private bool ApplyMove(BoardPieceMove move) { // Check the moving piece belongs to the correct player and is a valid move if (BoardPieces[move.From.X, move.From.Y].PieceOwner != PlayerTurn || !ValidMovesCalc.IsMoveValid(move, PlayerTurn, this) || (GameState != GameState.Playing)) { // Move is invalid return(false); } List <BoardChange> boardChanges = ApplyMoveToBoard(move); CheckPawnPromotion(move, boardChanges); // Store changes for (int i = 0; i < boardChanges.Count; i++) { GameChanges.Push(boardChanges[i]); } OnBoardChanged?.Invoke(boardChanges); if (ValidMovesCalc.IsPlayerInCheck(BoardPieces, BoardHelpers.GetOpponentPlayer(PlayerTurn))) { if (ValidMovesCalc.PlayerCanMove(this, BoardHelpers.GetOpponentPlayer(PlayerTurn))) { // CHECKMATE ChangeGameState(GameState.WonByCheckmate); return(true); } // IN CHECK OnPlayerInCheck?.Invoke(BoardHelpers.GetOpponentPlayer(PlayerTurn)); } else { if (ValidMovesCalc.PlayerCanMove(this, BoardHelpers.GetOpponentPlayer(PlayerTurn))) { // STALEMATE ChangeGameState(GameState.WonByStaleMate); return(true); } } ClearEnPassant(); SwapPlayerTurns(); return(true); }
private float Maximise(Board board, int depth, ref BoardPieceMoveScore maxBestMove, float beta, Player currentPlayer) { // If the depth limit is reached, don't go any deeper and return the score of the board if (depth >= _searchDepth) { return(ScoreTheBoard(board, currentPlayer)); } HashSet <BoardPieceMove> validMoves = new HashSet <BoardPieceMove>(); ValidMovesCalc.GetValidMovesForPlayer(board, board.PlayerTurn, validMoves); float alpha = -10000000; // Set alpha to low num BoardPieceMoveScore bestChildMove = null; // Iterate through every available move foreach (var move in validMoves) { // Create a copy of the board and then perform the current move Board newBoard = BoardHelpers.DuplicateBoard(board); newBoard.BoardPieces[move.From.X, move.From.Y].HasMoved = true; newBoard.BoardPieces[move.To.X, move.To.Y] = newBoard.BoardPieces[move.From.X, move.From.Y]; newBoard.BoardPieces[move.From.X, move.From.Y] = new BoardPiece(); newBoard.PlayerTurn = BoardHelpers.GetOpponentPlayer(newBoard.PlayerTurn); // Go down a layer and find the minimum score available for the enemy (PLAYER). Set it to alpha if it is greater than a previous alpha. alpha = Math.Max(alpha, Minimise(newBoard, depth + 1, alpha, currentPlayer)); // If the new alpha is greater than the previous best score (or hasn't been set yet) if (bestChildMove == null || alpha > bestChildMove.Score) { bestChildMove = new BoardPieceMoveScore(move, alpha); } // If a move is found to be worse than the best score currently stored, return out of the tree early. if (alpha > beta) { return(alpha); } } // If we're on the top layer, return the best move available if (depth == 0) { maxBestMove = bestChildMove; } return(alpha); }
private float Minimise(Board board, int depth, float alpha, Player currentPlayer) { if (depth >= _searchDepth) { return(ScoreTheBoard(board, currentPlayer)); } HashSet <BoardPieceMove> validMoves = new HashSet <BoardPieceMove>(); ValidMovesCalc.GetValidMovesForPlayer(board, board.PlayerTurn, validMoves); float beta = 10000000; BoardPieceMoveScore bestChildMove = null; // Iterate through every available move foreach (var move in validMoves) { // Create a copy of the board and then perform the current move Board newBoard = BoardHelpers.DuplicateBoard(board); newBoard.BoardPieces[move.From.X, move.From.Y].HasMoved = true; newBoard.BoardPieces[move.To.X, move.To.Y] = newBoard.BoardPieces[move.From.X, move.From.Y]; newBoard.BoardPieces[move.From.X, move.From.Y] = new BoardPiece(); newBoard.PlayerTurn = BoardHelpers.GetOpponentPlayer(newBoard.PlayerTurn); var newMove = new BoardPieceMoveScore(move, beta); beta = Math.Min(beta, Maximise(newBoard, depth + 1, ref newMove, beta, currentPlayer)); if (bestChildMove == null || beta < bestChildMove.Score) { bestChildMove = new BoardPieceMoveScore(move, beta); } if (beta < alpha) { return(beta); } } return(beta); }