public double RateDraw(IChessBoard board, ChessDraw draw, int searchDepth) { // simulate the given draw var simulatedBoard = board.ApplyDraw(draw); // use the minimax algorithm to rate the score of the given draw double score = negamax(simulatedBoard, draw, searchDepth - 1, double.MinValue, double.MaxValue, false) * -1; return(score); }
/// <summary> /// Simulate the given chess draw on the given chess board and determine whether it draws into an allied check situation. /// </summary> /// <param name="board">The chess board with the game situation to evaluate</param> /// <param name="draw">The chess draw to be evaluated</param> /// <returns>boolean that indicates whether the draw would cause an allied check situation</returns> public bool IsDrawIntoCheck(IChessBoard board, ChessDraw draw) { // TODO: remove clone operation if it causes performance issues // clone chess board and simulate the draw var simulatedBoard = board.ApplyDraw(draw); // get all enemy chess pieces and their possible answers var enemyPieces = simulatedBoard.GetPiecesOfColor(draw.DrawingSide.Opponent()); var possibleEnemyAnswers = enemyPieces.SelectMany(piece => ChessDrawGenerator.Instance.GetDraws(simulatedBoard, piece.Position, draw, false)); // find out if the allied king could be taken by at least one enemy answer var alliedKing = (draw.DrawingSide == ChessColor.White) ? simulatedBoard.WhiteKing : simulatedBoard.BlackKing; bool ret = possibleEnemyAnswers.Any(x => x.NewPosition == alliedKing.Position); return(ret); }
private double negamax(IChessBoard board, ChessDraw?lastDraw, int depth, double alpha, double beta, bool isMaximizing = true) { var drawingSide = lastDraw?.DrawingSide.Opponent() ?? ChessColor.White; // recursion anchor: depth <= 0 if (depth <= 0) { return(_estimator.GetScore(board, drawingSide)); } // init max score double maxScore = alpha; // compute possible draws var draws = generateDraws(board, lastDraw); // order draws by possible gain, so the alpha-beta prune can achieve fast cut-offs // at high-level game tree nodes which ideally saves lots of computation effort var preorderedDraws = getPreorderedDrawsByPossibleGain(board, draws, drawingSide); // loop through all possible draws for (int i = 0; i < preorderedDraws.Length; i++) { // simulate draw var simDraw = preorderedDraws[i]; var simBoard = board.ApplyDraw(simDraw); // start recursion double score = negamax(simBoard, simDraw, depth - 1, -beta, -maxScore, !isMaximizing) * -1; // update max score if (score > maxScore) { maxScore = score; } // check for beta cut-off if (maxScore >= beta) { break; } } return(maxScore); }
private ChessDraw[] getPreorderedDrawsByPossibleGain(IChessBoard board, IList <ChessDraw> draws, ChessColor drawingSide) { // initialize score array var drawsXScoreTuples = new ChessDrawScore[draws.Count()]; // loop through all draws for (int i = 0; i < draws.Count(); i++) { // simulate the draw var simDraw = draws[i]; var simBoard = board.ApplyDraw(simDraw); // compute the score of the resulting position (= score of the draw) double score = _estimator.GetScore(simBoard, drawingSide); // add the (draw, score) tuple to the list drawsXScoreTuples[i] = new ChessDrawScore() { Draw = simDraw, Score = score }; } return(sortByScoreDesc(drawsXScoreTuples)); }
public void GetCheckGameStatusTest() { // test no check IChessBoard board = ChessBoard.StartFormation; var enemyDraw = new ChessDraw(board, new ChessPosition(0, 0), new ChessPosition(0, 0)); board = board.ApplyDraw(enemyDraw); Assert.True(ChessDrawSimulator.Instance.GetCheckGameStatus(board, enemyDraw) == ChessGameStatus.None); // test simple check var pieces = new List <ChessPieceAtPos>() { new ChessPieceAtPos(new ChessPosition(0, 4), new ChessPiece(ChessPieceType.King, ChessColor.White, true)), new ChessPieceAtPos(new ChessPosition(1, 5), new ChessPiece(ChessPieceType.Peasant, ChessColor.White, true)), new ChessPieceAtPos(new ChessPosition(7, 3), new ChessPiece(ChessPieceType.Queen, ChessColor.Black, true)), new ChessPieceAtPos(new ChessPosition(7, 4), new ChessPiece(ChessPieceType.King, ChessColor.Black, true)), }; board = new ChessBoard(pieces); enemyDraw = new ChessDraw(board, new ChessPosition(7, 3), new ChessPosition(6, 4)); board = board.ApplyDraw(enemyDraw); Assert.True(ChessDrawSimulator.Instance.GetCheckGameStatus(board, enemyDraw) == ChessGameStatus.Check); // test checkmate for (int putSavingPieceValue = 0; putSavingPieceValue < 2; putSavingPieceValue++) { pieces = new List <ChessPieceAtPos>() { new ChessPieceAtPos(new ChessPosition(0, 4), new ChessPiece(ChessPieceType.King, ChessColor.White, true)), new ChessPieceAtPos(new ChessPosition(6, 1), new ChessPiece(ChessPieceType.Peasant, ChessColor.White, true)), new ChessPieceAtPos(new ChessPosition(2, 3), new ChessPiece(ChessPieceType.Queen, ChessColor.Black, true)), new ChessPieceAtPos(new ChessPosition(2, 4), new ChessPiece(ChessPieceType.King, ChessColor.Black, true)), }; // allow the ally to avoid the checkmate by putting an additional chess piece on the board // and test if the simulator makes use of this opportunity bool putSavingPiece = (putSavingPieceValue == 1); if (putSavingPiece) { pieces.Add(new ChessPieceAtPos(new ChessPosition(1, 7), new ChessPiece(ChessPieceType.Rook, ChessColor.White, true))); } board = new ChessBoard(pieces); enemyDraw = new ChessDraw(board, new ChessPosition(2, 3), new ChessPosition(1, 4)); board = board.ApplyDraw(enemyDraw); Assert.True( (!putSavingPiece && ChessDrawSimulator.Instance.GetCheckGameStatus(board, enemyDraw) == ChessGameStatus.Checkmate) || (putSavingPiece && ChessDrawSimulator.Instance.GetCheckGameStatus(board, enemyDraw) == ChessGameStatus.Check) ); } // test stalemate pieces = new List <ChessPieceAtPos>() { new ChessPieceAtPos(new ChessPosition(0, 4), new ChessPiece(ChessPieceType.King, ChessColor.White, true)), new ChessPieceAtPos(new ChessPosition(6, 1), new ChessPiece(ChessPieceType.Peasant, ChessColor.White, true)), new ChessPieceAtPos(new ChessPosition(2, 3), new ChessPiece(ChessPieceType.Queen, ChessColor.Black, true)), new ChessPieceAtPos(new ChessPosition(3, 5), new ChessPiece(ChessPieceType.Queen, ChessColor.Black, true)), new ChessPieceAtPos(new ChessPosition(2, 4), new ChessPiece(ChessPieceType.King, ChessColor.Black, true)), new ChessPieceAtPos(new ChessPosition(7, 1), new ChessPiece(ChessPieceType.Rook, ChessColor.Black, true)), }; board = new ChessBoard(pieces); enemyDraw = new ChessDraw(board, new ChessPosition(3, 5), new ChessPosition(2, 5)); board = board.ApplyDraw(enemyDraw); Assert.True(ChessDrawSimulator.Instance.GetCheckGameStatus(board, enemyDraw) == ChessGameStatus.Stalemate); }