public Player(ChessGame game) { this.Game = game; IsComputer = false; }
/// <summary> /// Recursive method to find the best move in a given position. Min-max algorithm alternates /// between black and white. /// </summary> /// <param name="board"></param> /// <param name="turn"></param> /// <param name="possibleMoves"></param> /// <param name="level">Number of half moves to look forward.</param> /// <param name="topLevel">True if this is the outermost call.</param> /// <param name="alpha"></param> /// <param name="beta"></param> /// <param name="bestMove"></param> /// <returns></returns> private int CalculateMove(ChessBoard board, ChessPieceColor turn, List <ChessMove> possibleMoves, int level, bool topLevel, int alpha, int beta, out ChessMove bestMove, int initialDepth) { int best_score = -INFINITY; bestMove = null; if (!Stop) { int i = 0; foreach (ChessMove possibleMove in possibleMoves) { if (topLevel && ((depthToVisualize != 0 && initialDepth >= depthToVisualize) || (depthToVisualize == 0 && initialDepth > 2))) { RaiseConsideringMoveEvent(possibleMove); } i++; ChessBoard resBoard = new ChessBoard(board); resBoard.ApplyMove(turn, possibleMove, null); int move_score = 0; if (level == 0) { #if PROF prof.Start("StaticEval"); #endif move_score = StaticEvaluation(resBoard, turn); #if PROF prof.End("StaticEval"); #endif } else { ChessMove m = null; ChessPieceColor newTurn = ChessGame.InvertColor(turn); List <ChessMove> moves = ChessGame.GetPossibleMoves(resBoard, newTurn); bool abort = false; if (moves.Count == 0) { if (!ChessGame.IsInCheck(board, newTurn)) { // Stale mate, good depending on piece value. int whiteValue = 0; int blackValue = 0; board.GetPiecesValue(out whiteValue, out blackValue); int delta = (turn == ChessPieceColor.White ? whiteValue - blackValue : blackValue - whiteValue); if (delta > 0) { move_score = -10000; } else { move_score = 10000; } } else { int checkMateScore = 50000 + level * 100; // Prioritize early check mate. move_score = checkMateScore; // Check mate. } } else { move_score = -CalculateMove(resBoard, newTurn, moves, level - 1, false, -beta, -alpha, out m, initialDepth); if (m == null) // Abort { abort = true; } } if (abort) // Abort { bestMove = null; best_score = -INFINITY; break; } } if (topLevel) { // Decrease score for repetition moves. if (Game.ChessMoves.Count >= 3) { ChessMove myLastMove = Game.ChessMoves[Game.ChessMoves.Count - 2]; ChessMove oppLastMove = Game.ChessMoves[Game.ChessMoves.Count - 1]; ChessMove oppSecLastMove = Game.ChessMoves[Game.ChessMoves.Count - 3]; if (myLastMove.FromIndex == possibleMove.ToIndex && myLastMove.ToIndex == possibleMove.FromIndex && !myLastMove.IsCapture && oppLastMove.FromIndex == oppSecLastMove.ToIndex && oppLastMove.ToIndex == oppSecLastMove.FromIndex && !oppLastMove.IsCapture && !oppSecLastMove.IsCapture) // TODO: check for IsCapture in possibleMove { move_score -= 30; } } } #if LOGGING Debug.WriteLine(string.Format("{0}Level {1} {2} {3} alpha {4} beta {5}", GetIndent(level), level, possibleMove.ToString(), move_score, alpha, beta)); #endif if (move_score > best_score) { best_score = move_score; bestMove = possibleMove; } if (best_score > alpha) { alpha = best_score; } if (alpha >= beta) { return(alpha); // This means the move is as good as or worse than a previous move. } } } return(best_score); }
private ChessMove GetNextMove() { int startTicks = (int)DateTime.Now.Ticks; ChessMove move = null; Progress = 0; Aborted = false; Stop = false; // Try opening book first. move = openingBook.GetNextMove(Game.ChessMoves); if (move != null && Game.MakeMove(move, true)) { #if !NETFX_CORE Thread.Sleep(200); #endif } else { #if LOGGING Debug.WriteLine(string.Format("Calc start")); #endif #if NETFX_CORE MyTimer timer = null; if (TimeLimit > 0) { timer = new MyTimer(OutOfTime, null, TimeLimit, System.Threading.Timeout.Infinite); Debug.WriteLine("Timer " + TimeLimit); } #else Timer timer = null; if (TimeLimit > 0) { timer = new Timer(OutOfTime, null, TimeLimit, System.Threading.Timeout.Infinite); Debug.WriteLine("Timer " + TimeLimit); } #endif List <ChessMove> possibleMoves = ChessGame.GetPossibleMoves(Game.Board, Game.Turn); // Iterative deepening. int depth = 0; while (true) { ChessMove bestMove = null; Game.AddLog(string.Format("lvl {0} start depth {1}", (int)DifficultyLevel, depth)); int calcStartTicks = (int)DateTime.Now.Ticks; CalculateMove(Game.Board, Game.Turn, possibleMoves, depth, true, -INFINITY, INFINITY, out bestMove, depth); int calcTimeTicks = (int)DateTime.Now.Ticks - calcStartTicks; Game.AddLog(string.Format("end depth {0} ticks {1} bestMove {2}", depth, calcTimeTicks, (bestMove == null ? 0 :1))); Debug.WriteLine(string.Format("dTV: {0} time: {1}", depthToVisualize, calcTimeTicks / TimeSpan.TicksPerSecond)); if (depthToVisualize == 0 && ((float)calcTimeTicks / (float)TimeSpan.TicksPerSecond) > 0.3f) { depthToVisualize = depth; } if (bestMove != null) { move = bestMove; } if (bestMove == null || DepthLimit > 0 && depth >= DepthLimit) { if (timer != null) { timer.Dispose(); } break; } else { // Move the move to the beginning of the list. if (possibleMoves.Remove(move)) { possibleMoves.Insert(0, move); } } depth++; } #if LOGGING Debug.WriteLine(string.Format("Calc end.")); #endif } gameTicks += (int)DateTime.Now.Ticks - startTicks; return(move); }
/// <summary> /// Creates a new board. /// </summary> public ChessBoard(ChessGame game) { this.Game = game; InitBoardState(); this.capturedPieces = new List <ChessPiece>(); }
public void ApplyMove(ChessPieceColor color, ChessMove move, ChessMoveInfo moveInfo) { // Make the move... ulong fromPos = Precomputed.IndexToBitBoard[(int)move.FromIndex]; ulong toPos = Precomputed.IndexToBitBoard[(int)move.ToIndex]; ulong capturePos = toPos; if (moveInfo != null) { moveInfo.MovedBy = color; } count50MoveRule++; ChessBoardColorState boardState = GetBoardState(color); boardState.Pieces &= ~fromPos; // Move the piece. boardState.Pieces |= toPos; // Move the piece. switch (move.PieceType) { case ChessPieceType.Pawn: count50MoveRule = 0; boardState.Pawns &= ~fromPos; switch (move.PromotionPieceType) { case ChessPieceType.Knight: boardState.Knights |= toPos; break; case ChessPieceType.Bishop: boardState.Bishops |= toPos; break; case ChessPieceType.Rook: boardState.Rooks |= toPos; break; case ChessPieceType.Queen: boardState.Queens |= toPos; break; default: boardState.Pawns |= toPos; break; } if (color == ChessPieceColor.White) { if ((Precomputed.WhitePawnCaptureMoves[(int)move.FromIndex] & toPos & (enPassantTarget << 8)) != 0) { capturePos = enPassantTarget; enPassantTarget = 0; } else if ((Precomputed.WhitePawnDoubleMoves[(int)move.FromIndex] & toPos) != 0) { enPassantTarget = toPos; } else { enPassantTarget = 0; } } else { if ((Precomputed.BlackPawnCaptureMoves[(int)move.FromIndex] & toPos & (enPassantTarget >> 8)) != 0) { capturePos = enPassantTarget; enPassantTarget = 0; } else if ((Precomputed.BlackPawnDoubleMoves[(int)move.FromIndex] & toPos) != 0) { enPassantTarget = toPos; } else { enPassantTarget = 0; } } break; case ChessPieceType.Knight: enPassantTarget = 0; boardState.Knights &= ~fromPos; boardState.Knights |= toPos; break; case ChessPieceType.Bishop: enPassantTarget = 0; boardState.Bishops &= ~fromPos; boardState.Bishops |= toPos; break; case ChessPieceType.Rook: enPassantTarget = 0; boardState.Rooks &= ~fromPos; boardState.Rooks |= toPos; if ((fromPos & Precomputed.IndexToBitBoard[(int)ChessPositionIndex.A1]) != 0) { whiteBoardState.QueensideCastlingPossible = false; } else if ((fromPos & Precomputed.IndexToBitBoard[(int)ChessPositionIndex.H1]) != 0) { whiteBoardState.KingsideCastlingPossible = false; } else if ((fromPos & Precomputed.IndexToBitBoard[(int)ChessPositionIndex.A8]) != 0) { blackBoardState.QueensideCastlingPossible = false; } else if ((fromPos & Precomputed.IndexToBitBoard[(int)ChessPositionIndex.H8]) != 0) { blackBoardState.KingsideCastlingPossible = false; } break; case ChessPieceType.Queen: enPassantTarget = 0; boardState.Queens &= ~fromPos; boardState.Queens |= toPos; break; case ChessPieceType.King: enPassantTarget = 0; boardState.King &= ~fromPos; boardState.King |= toPos; boardState.KingsideCastlingPossible = false; boardState.QueensideCastlingPossible = false; if (move.IsKingsideCastling) { if (color == ChessPieceColor.White) { MoveRookWhenCastling(color, ChessPositionIndex.H1, ChessPositionIndex.F1, moveInfo); } else { MoveRookWhenCastling(color, ChessPositionIndex.H8, ChessPositionIndex.F8, moveInfo); } } else if (move.IsQueensideCastling) { if (color == ChessPieceColor.White) { MoveRookWhenCastling(color, ChessPositionIndex.A1, ChessPositionIndex.D1, moveInfo); } else { MoveRookWhenCastling(color, ChessPositionIndex.A8, ChessPositionIndex.D8, moveInfo); } } break; } ChessPieceColor invertedColor = ChessGame.InvertColor(color); ChessBoardColorState invertedBoardState = GetBoardState(invertedColor); if ((invertedBoardState.Pieces & capturePos) != 0) // Check if there is a capture. { invertedBoardState.Pieces &= ~capturePos; // Remove the piece from all black pieces. invertedBoardState.Pawns &= ~capturePos; invertedBoardState.Knights &= ~capturePos; invertedBoardState.Bishops &= ~capturePos; invertedBoardState.Rooks &= ~capturePos; invertedBoardState.Queens &= ~capturePos; move.IsCapture = true; count50MoveRule = 0; if (moveInfo != null) { moveInfo.CapturedPiecePos = (ChessPositionIndex)Util.fastBitScanForward(capturePos); } // PP 2012-12-24: when a rook is captured, castling is no longer possible. if ((capturePos & Precomputed.IndexToBitBoard[(int)ChessPositionIndex.A1]) != 0) { whiteBoardState.QueensideCastlingPossible = false; } else if ((capturePos & Precomputed.IndexToBitBoard[(int)ChessPositionIndex.H1]) != 0) { whiteBoardState.KingsideCastlingPossible = false; } else if ((capturePos & Precomputed.IndexToBitBoard[(int)ChessPositionIndex.A8]) != 0) { blackBoardState.QueensideCastlingPossible = false; } else if ((capturePos & Precomputed.IndexToBitBoard[(int)ChessPositionIndex.H8]) != 0) { blackBoardState.KingsideCastlingPossible = false; } } }
public void HookUp(ChessGame game) { this.Game = game; }