This commit is contained in:
timerix 2023-12-01 14:14:07 +06:00
parent 1dbe2e1bb6
commit 7b345ba39c
5 changed files with 200 additions and 14 deletions

View File

@ -5,6 +5,10 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="TicTacToe.Cell" x:Class="TicTacToe.Cell"
BorderThickness="2" BorderThickness="2"
BorderBrush="White"> BorderBrush="White"
<TextBlock TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="40">X</TextBlock> FontSize="40">
<Button Name="Text" Click="Text_OnClick"
HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
</Button>
</UserControl> </UserControl>

View File

@ -1,11 +1,26 @@
using Avalonia.Controls; using System.Net.Mime;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Media;
namespace TicTacToe; namespace TicTacToe;
public partial class Cell : UserControl public partial class Cell : UserControl
{ {
public required Game Game;
public Cell() public Cell()
{ {
InitializeComponent(); 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;
}
} }

135
TicTacToe/Game.cs Normal file
View File

@ -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<char>? 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;
}
}

View File

@ -2,17 +2,23 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 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" x:Class="TicTacToe.MainWindow"
Title="TicTacToe" Title="TicTacToe"
FontSize="20"> FontSize="20"
Width="600"
Height="600"
d:DesignHeight="600"
d:DesignWidth="600">
<Grid> <Grid>
<Grid.RowDefinitions>40 *</Grid.RowDefinitions> <Grid.RowDefinitions>40 *</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Spacing="20"> <StackPanel Orientation="Horizontal" Spacing="20">
<Label Target="SizeTextBox" VerticalContentAlignment="Center">Size:</Label> <Label Target="SizeTextBox" VerticalContentAlignment="Center">Size:</Label>
<TextBox Name="SizeTextBox"></TextBox> <TextBox Name="SizeTextBox" Width="60"></TextBox>
<Button Click="RestartButton_OnClick">Restart</Button> <Button Click="RestartButton_OnClick">Restart</Button>
</StackPanel> </StackPanel>
<Grid Grid.Row="1" Name="GameGrid"></Grid> <Grid Grid.Row="1" Name="GameGrid"></Grid>
<StackPanel Grid.Row="1" Name="WinPanel" IsEnabled="False"
HorizontalAlignment="Center" VerticalAlignment="Center"><TextBlock Name="WinText"></TextBlock></StackPanel>
</Grid> </Grid>
</Window> </Window>

View File

@ -6,15 +6,35 @@ namespace TicTacToe;
public partial class MainWindow : Window public partial class MainWindow : Window
{ {
private Game _game = new(3, 3);
public MainWindow() public MainWindow()
{ {
InitializeComponent(); InitializeComponent();
DrawGame();
_game.PlayerWon += ShowWin;
} }
private void RestartButton_OnClick(object? sender, RoutedEventArgs e) private void RestartButton_OnClick(object? sender, RoutedEventArgs e)
{ {
int size = Convert.ToInt32(SizeTextBox.Text); 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.Children.Clear();
GameGrid.RowDefinitions = new RowDefinitions(); GameGrid.RowDefinitions = new RowDefinitions();
for(int y=0; y<size; y++) for(int y=0; y<size; y++)
@ -25,11 +45,17 @@ public partial class MainWindow : Window
for(int y=0; y<size; y++) for(int y=0; y<size; y++)
for (int x = 0; x < size; x++) for (int x = 0; x < size; x++)
{ {
var c = new Cell(); var cellView = new Cell
c.SetValue(Grid.ColumnProperty, x); {
c.SetValue(Grid.RowProperty, y); Game = _game
GameGrid.Children.Add(c); };
cellView.SetValue(Grid.ColumnProperty, x);
cellView.SetValue(Grid.RowProperty, y);
char cellValue = _game.GameField[y][x];
if (cellValue != '\0')
cellView.Text.Content = cellValue.ToString();
GameGrid.Children.Add(cellView);
}
}
} }
}
}