Files
abdelaziz bc4118704e logic
2026-03-30 07:49:37 +02:00

266 lines
9.0 KiB
C#

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
}
}