logic
This commit is contained in:
@@ -1,12 +1,266 @@
|
||||
using System.Windows;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace CheckersSpielBot
|
||||
{
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
private readonly GameService _game;
|
||||
private readonly BoardRenderer _renderer;
|
||||
private readonly DatabaseService _db = new();
|
||||
private AiService _ai;
|
||||
|
||||
private int _humanPlayer = 1;
|
||||
private int _aiPlayer = 2;
|
||||
private bool _gameEnded = false;
|
||||
|
||||
private int _selectedRow = -1;
|
||||
private int _selectedCol = -1;
|
||||
private bool _hasPieceSelected = false;
|
||||
private bool _isAiThinking = false;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
_game = new GameService();
|
||||
_renderer = new BoardRenderer(this, _game);
|
||||
_ai = new AiService(_aiPlayer);
|
||||
InitializeNewGame();
|
||||
}
|
||||
|
||||
#region Setup
|
||||
private void InitializeNewGame()
|
||||
{
|
||||
// End previous game as draw if it wasn't finished
|
||||
if (PlayerSession.CurrentGameId != -1 && !_gameEnded)
|
||||
_db.EndGame(PlayerSession.CurrentGameId, "draw");
|
||||
|
||||
_gameEnded = false;
|
||||
|
||||
GameModeDialog dialog = new GameModeDialog();
|
||||
dialog.ShowDialog();
|
||||
|
||||
if (dialog.HumanGoesFirst)
|
||||
{
|
||||
_humanPlayer = 1;
|
||||
_aiPlayer = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
_humanPlayer = 2;
|
||||
_aiPlayer = 1;
|
||||
}
|
||||
|
||||
_ai = new AiService(_aiPlayer);
|
||||
|
||||
string wentFirst = dialog.HumanGoesFirst ? "player" : "bot";
|
||||
PlayerSession.CurrentGameId = _db.StartGame(PlayerSession.PlayerId, wentFirst);
|
||||
|
||||
_game.InitializeNewGame();
|
||||
ClearSelection();
|
||||
RenderBoard();
|
||||
RefreshStatusBar();
|
||||
|
||||
if (_game.ActivePlayer == _aiPlayer) { TriggerAiTurnAsync(); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Input
|
||||
private void CellClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_isAiThinking) return;
|
||||
if (_game.ActivePlayer != _humanPlayer) return;
|
||||
if (sender is not Button btn || btn.Tag == null) return;
|
||||
|
||||
ParseCellTag(btn.Tag.ToString()!, out int row, out int col);
|
||||
|
||||
if (_game.IsChainJumpActive) { HandleChainJumpClick(row, col); return; }
|
||||
if (_hasPieceSelected) HandleSecondClick(row, col);
|
||||
else HandleFirstClick(row, col);
|
||||
}
|
||||
|
||||
private void HandleFirstClick(int row, int col)
|
||||
{
|
||||
int piece = _game.Board[row, col];
|
||||
if (!_game.BelongsToActivePlayer(piece)) return;
|
||||
|
||||
if (_game.MandatoryCapturePieces.Count > 0 && !_game.MandatoryCapturePieces.Contains((row, col))) return;
|
||||
if (_game.GetLegalMoves(row, col, capturesOnly: false).Count == 0) return;
|
||||
|
||||
_selectedRow = row;
|
||||
_selectedCol = col;
|
||||
_hasPieceSelected = true;
|
||||
RenderBoard();
|
||||
}
|
||||
|
||||
private void HandleSecondClick(int row, int col)
|
||||
{
|
||||
int piece = _game.Board[row, col];
|
||||
|
||||
if (_game.BelongsToActivePlayer(piece))
|
||||
{
|
||||
bool blockedByCapture = _game.MandatoryCapturePieces.Count > 0
|
||||
&& !_game.MandatoryCapturePieces.Contains((row, col));
|
||||
if (!blockedByCapture && _game.GetLegalMoves(row, col, capturesOnly: false).Count > 0)
|
||||
{
|
||||
_selectedRow = row;
|
||||
_selectedCol = col;
|
||||
RenderBoard();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var legalMoves = _game.GetLegalMoves(_selectedRow, _selectedCol, capturesOnly: false);
|
||||
var chosen = legalMoves.Find(m => m.DestinationRow == row && m.DestinationCol == col);
|
||||
|
||||
if (chosen != null) { ProcessMoveResult(_game.ExecuteMove(_selectedRow, _selectedCol, chosen)); }
|
||||
}
|
||||
|
||||
private void HandleChainJumpClick(int row, int col)
|
||||
{
|
||||
if (row == _game.ChainJumpRow && col == _game.ChainJumpCol) return;
|
||||
|
||||
var jumps = _game.GetLegalMoves(_game.ChainJumpRow, _game.ChainJumpCol, capturesOnly: true);
|
||||
var chosen = jumps.Find(m => m.DestinationRow == row && m.DestinationCol == col);
|
||||
|
||||
if (chosen != null) { ProcessMoveResult(_game.ExecuteMove(_game.ChainJumpRow, _game.ChainJumpCol, chosen)); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region MoveResult
|
||||
private void ProcessMoveResult(MoveResult result)
|
||||
{
|
||||
ClearSelection();
|
||||
|
||||
switch (result.Type)
|
||||
{
|
||||
case MoveResult.ResultType.ChainJumpRequired:
|
||||
if (_game.ActivePlayer == _aiPlayer)
|
||||
{
|
||||
TriggerAiTurnAsync();
|
||||
return;
|
||||
}
|
||||
_hasPieceSelected = true;
|
||||
_selectedRow = _game.ChainJumpRow;
|
||||
_selectedCol = _game.ChainJumpCol;
|
||||
RenderBoard();
|
||||
StatusText.Text = "Chain jump — must continue!";
|
||||
break;
|
||||
|
||||
case MoveResult.ResultType.Victory:
|
||||
RenderBoard();
|
||||
AnnounceWinner(result.Victor);
|
||||
break;
|
||||
|
||||
case MoveResult.ResultType.TurnAdvanced:
|
||||
RenderBoard();
|
||||
RefreshStatusBar();
|
||||
if (_game.ActivePlayer == _aiPlayer) { TriggerAiTurnAsync(); }
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region AI
|
||||
private async void TriggerAiTurnAsync()
|
||||
{
|
||||
_isAiThinking = true;
|
||||
StatusText.Text = "Bot is thinking...";
|
||||
|
||||
int[,] boardSnapshot = (int[,])_game.Board.Clone();
|
||||
Move? bestMove = await Task.Run(() => _ai.GetBestMove(boardSnapshot));
|
||||
|
||||
_isAiThinking = false;
|
||||
|
||||
if (bestMove == null)
|
||||
{
|
||||
AnnounceWinner(_humanPlayer);
|
||||
return;
|
||||
}
|
||||
|
||||
int originRow = -1, originCol = -1;
|
||||
for (int r = 0; r < 8 && originRow == -1; r++)
|
||||
{
|
||||
for (int c = 0; c < 8 && originRow == -1; c++)
|
||||
{
|
||||
if (!BoardHelper.BelongsToPlayer(_game.Board[r, c], _aiPlayer)) continue;
|
||||
|
||||
var moves = _game.GetLegalMoves(r, c, capturesOnly: true);
|
||||
if (moves.Count == 0) { moves = _game.GetLegalMoves(r, c, capturesOnly: false); }
|
||||
|
||||
if (moves.Exists(m => m.DestinationRow == bestMove.DestinationRow &&
|
||||
m.DestinationCol == bestMove.DestinationCol &&
|
||||
m.CapturedPieceRow == bestMove.CapturedPieceRow &&
|
||||
m.CapturedPieceCol == bestMove.CapturedPieceCol))
|
||||
{
|
||||
originRow = r;
|
||||
originCol = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (originRow == -1) return;
|
||||
ProcessMoveResult(_game.ExecuteMove(originRow, originCol, bestMove));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region UI
|
||||
private void RenderBoard()
|
||||
{
|
||||
_renderer.RenderBoard(_selectedRow, _selectedCol, _hasPieceSelected, _game.IsChainJumpActive);
|
||||
}
|
||||
|
||||
private void ClearSelection()
|
||||
{
|
||||
_hasPieceSelected = false;
|
||||
_selectedRow = -1;
|
||||
_selectedCol = -1;
|
||||
}
|
||||
|
||||
private void RefreshStatusBar()
|
||||
{
|
||||
if (_game.ActivePlayer == _aiPlayer)
|
||||
{
|
||||
StatusText.Text = "Bot's turn";
|
||||
return;
|
||||
}
|
||||
string hint = _game.MandatoryCapturePieces.Count > 0 ? " — Capture is mandatory!" : "";
|
||||
StatusText.Text = $"Your turn{hint}";
|
||||
}
|
||||
|
||||
private void AnnounceWinner(int victor)
|
||||
{
|
||||
_gameEnded = true;
|
||||
string winnerStr = victor == _humanPlayer ? "player" : "bot";
|
||||
_db.EndGame(PlayerSession.CurrentGameId, winnerStr);
|
||||
|
||||
string message = victor == _humanPlayer ? "You win!" : "Bot wins!";
|
||||
StatusText.Text = message;
|
||||
MessageBox.Show(message, "Game Over", MessageBoxButton.OK, MessageBoxImage.None);
|
||||
}
|
||||
|
||||
private void History_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dialog = new HistoryDialog();
|
||||
dialog.ShowDialog();
|
||||
}
|
||||
|
||||
private void Window_Closing(object sender, CancelEventArgs e)
|
||||
{
|
||||
if (PlayerSession.CurrentGameId != -1 && !_gameEnded)
|
||||
_db.EndGame(PlayerSession.CurrentGameId, "draw");
|
||||
}
|
||||
|
||||
private static void ParseCellTag(string tag, out int row, out int col)
|
||||
{
|
||||
var parts = tag.Split(',');
|
||||
row = int.Parse(parts[0]);
|
||||
col = int.Parse(parts[1]);
|
||||
}
|
||||
|
||||
private void NewGame(object sender, RoutedEventArgs e) { InitializeNewGame(); }
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user