diff --git a/TicTacToe/Cell.axaml b/TicTacToe/Cell.axaml index f01d175..46686be 100644 --- a/TicTacToe/Cell.axaml +++ b/TicTacToe/Cell.axaml @@ -5,6 +5,10 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="TicTacToe.Cell" BorderThickness="2" - BorderBrush="White"> - X + BorderBrush="White" + FontSize="40"> + diff --git a/TicTacToe/Cell.axaml.cs b/TicTacToe/Cell.axaml.cs index d18fb3f..6429fc5 100644 --- a/TicTacToe/Cell.axaml.cs +++ b/TicTacToe/Cell.axaml.cs @@ -1,11 +1,26 @@ -using Avalonia.Controls; +using System.Net.Mime; +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Media; namespace TicTacToe; public partial class Cell : UserControl { + public required Game Game; + public Cell() { InitializeComponent(); } + + private void Text_OnClick(object? sender, RoutedEventArgs e) + { + if(Text.Content != null) + return; + Text.Content = Game.CurrentPlayerSign; + Game.Turn(GetValue(Grid.RowProperty), GetValue(Grid.ColumnProperty)); + IsEnabled = false; + Foreground = Brushes.White; + } } \ No newline at end of file diff --git a/TicTacToe/Game.cs b/TicTacToe/Game.cs new file mode 100644 index 0000000..23c4c6a --- /dev/null +++ b/TicTacToe/Game.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections; + +namespace TicTacToe; + +public class Game +{ + /* 0 1 2 ... + * 0 [ ][ ][ ] + * 1 [ ][ ][ ] + * 2 [ ][ ][ ] + * ... + */ + public char[][] GameField => _gameField; + public char CurrentPlayerSign => _players[_nextPlayerIndex]; + + public event Action? PlayerWon; + + private char[][] _gameField; + private char[] _players = { 'X', '0' }; + private int _nextPlayerIndex = 0; + private int _winSequenceLength; + private int _sideLength; + + public Game(int gameFieldSideSize, int winSequenceLength) + { + _winSequenceLength = winSequenceLength; + _sideLength = gameFieldSideSize; + _gameField = new char[gameFieldSideSize][]; + for (int y = 0; y < gameFieldSideSize; y++) + { + _gameField[y] = new char[gameFieldSideSize]; + for (int x = 0; x < gameFieldSideSize; x++) + _gameField[y][x] = '\0'; + } + } + + public void Turn(int cell_row, int cell_col) + { + if (_gameField[cell_row][cell_col] != '\0') + throw new Exception("the cell was already used"); + _gameField[cell_row][cell_col] = CurrentPlayerSign; + if (CheckWinCombination(cell_row, cell_col)) + { + PlayerWon?.Invoke(CurrentPlayerSign); + return; + } + + _nextPlayerIndex++; + if (_nextPlayerIndex >= _players.Length) + _nextPlayerIndex = 0; + } + + private bool CheckWinCombination(int cell_row, int cell_col) + { + int sequenceLength = 0; + // up + for (int row = cell_row; row > -1; row--) + { + if(_gameField[row][cell_col] != CurrentPlayerSign) + break; + if (++sequenceLength == _winSequenceLength) + return true; + } + // down + sequenceLength--; + for (int row = cell_row; row < _sideLength; row++) + { + if(_gameField[row][cell_col] != CurrentPlayerSign) + break; + if (++sequenceLength == _winSequenceLength) + return true; + } + sequenceLength = 0; + + // left + for (int col = cell_col; col > -1; col--) + { + if(_gameField[cell_row][col] != CurrentPlayerSign) + break; + if (++sequenceLength == _winSequenceLength) + return true; + } + // right + sequenceLength--; + for (int col = cell_col; col < _sideLength; col++) + { + if(_gameField[cell_row][col] != CurrentPlayerSign) + break; + if (++sequenceLength == _winSequenceLength) + return true; + } + sequenceLength = 0; + + // up-left + for (int row = cell_row, col = cell_col; row > -1 && col > -1; row--, col--) + { + if(_gameField[row][col] != CurrentPlayerSign) + break; + if (++sequenceLength == _winSequenceLength) + return true; + } + // down-right + sequenceLength--; + for (int row = cell_row, col = cell_col; col < _sideLength && row < _sideLength; row++, col++) + { + if(_gameField[row][col] != CurrentPlayerSign) + break; + if (++sequenceLength == _winSequenceLength) + return true; + } + sequenceLength = 0; + + + // up-right + for (int row = cell_row, col = cell_col; row > -1 && col < _sideLength; row--, col++) + { + if(_gameField[row][col] != CurrentPlayerSign) + break; + if (++sequenceLength == _winSequenceLength) + return true; + } + // down-left + sequenceLength--; + for (int row = cell_row, col = cell_col; col > -1 && row < _sideLength; row++, col--) + { + if(_gameField[row][col] != CurrentPlayerSign) + break; + if (++sequenceLength == _winSequenceLength) + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/TicTacToe/MainWindow.axaml b/TicTacToe/MainWindow.axaml index bc01056..e7bbb76 100644 --- a/TicTacToe/MainWindow.axaml +++ b/TicTacToe/MainWindow.axaml @@ -2,17 +2,23 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" + mc:Ignorable="d" x:Class="TicTacToe.MainWindow" Title="TicTacToe" - FontSize="20"> + FontSize="20" + Width="600" + Height="600" + d:DesignHeight="600" + d:DesignWidth="600"> 40 * - + + diff --git a/TicTacToe/MainWindow.axaml.cs b/TicTacToe/MainWindow.axaml.cs index 0a6d1af..c0a5782 100644 --- a/TicTacToe/MainWindow.axaml.cs +++ b/TicTacToe/MainWindow.axaml.cs @@ -6,15 +6,35 @@ namespace TicTacToe; public partial class MainWindow : Window { + private Game _game = new(3, 3); + public MainWindow() { InitializeComponent(); + DrawGame(); + _game.PlayerWon += ShowWin; } - private void RestartButton_OnClick(object? sender, RoutedEventArgs e) { int size = Convert.ToInt32(SizeTextBox.Text); + _game = new Game(size, size); + _game.PlayerWon += ShowWin; + DrawGame(); + } + + private void ShowWin(char playerChar) + { + GameGrid.IsVisible = false; + WinPanel.IsVisible = true; + WinText.Text = $"Player {playerChar} won!!1!"; + } + + private void DrawGame() + { + GameGrid.IsVisible = true; + WinPanel.IsVisible = false; + int size = _game.GameField.Length; GameGrid.Children.Clear(); GameGrid.RowDefinitions = new RowDefinitions(); for(int y=0; y