/// <summary> /// Adds a board to the history. If the board already exists the frequency is increased. /// </summary> /// <param name="board">Board to add.</param> public void AddBoard(Board board) { int count; ZobristHash hash = board.BoardHash(true); m_gameHashHistory.TryGetValue(hash, out count); m_gameHashHistory[hash] = count + 1; }
/// <summary> /// Adds a position to the opening book. /// </summary> /// <param name="board">Board with position to add.</param> /// <param name="adjustValue">value to adjust the boards value with.</param> public void AddPosition(Board board, int adjustValue) { int currentValue = 0; ZobristHash boardHash = board.BoardHash(true); m_positionTable.TryGetValue(boardHash, out currentValue); m_positionTable[boardHash] = currentValue + adjustValue; }
/// <summary> /// Initializes a new instance of the Move class. /// </summary> /// <param name="board">Board on which the move is to be performed.</param> /// <param name="from">Location move is done from.</param> /// <param name="to">Location move is done to.</param> public Move(Board board, Square from, Square to) { m_board = board; m_from = from; m_to = to; m_piece = m_board[m_from]; m_capture = m_board[m_to]; m_score = int.MinValue; }
/// <summary> /// Verifies if a piece attacks a square. This method does not check if the piece on "from" /// on the board is of the same type as this FlyweightPiece represents. /// </summary> /// <param name="board">Board to check attacking on.</param> /// <param name="from">Square on which attacking piece is placed.</param> /// <param name="to">The square to check if attacked.</param> /// <returns>True if a FlyweightPiece placed on "from" square attacks the "to" square. False otherwise.</returns> public bool Attacks(Board board, Square from, Square to) { if (Math.Abs(Board.Rank(from) - Board.Rank(to)) <= 1 && Math.Abs(Board.File(from) - Board.File(to)) <= 1) { return board.IsPathClear(from, to); } return false; }
/// <summary> /// Verifies if a piece attacks a square. This method does not check if the piece on "from" /// on the board is of the same type as this FlyweightPiece represents. /// </summary> /// <param name="board">Board to check attacking on.</param> /// <param name="from">Square on which attacking piece is placed.</param> /// <param name="to">The square to check if attacked.</param> /// <returns>True if a FlyweightPiece placed on "from" square attacks the "to" square. False otherwise.</returns> public bool Attacks(Board board, Square from, Square to) { if (Board.Rank(from) == Board.Rank(to) || Board.File(from) == Board.File(to)) { return board.IsPathClear(from, to); } return false; }
/// <summary> /// Generate moves a FlyweightPiece can make. /// This method does not varifies if a move puts its own king in check. /// This is done in MoveOrganizer when adding a move. /// </summary> /// <param name="board">Board to generate moves for.</param> /// <param name="location">Location of the piece.</param> /// <param name="moves">Container class to which all generated moves are added.</param> public void GenerateMoves(Board board, Square location, MoveOrganizer moves) { if (m_color == board.State.ColorToPlay) { //Basic moves for (int i = 0; i < m_directions.Length; i++) { m_iterator.Reset(board, location, m_directions[i]); if (m_iterator.Next()) if (m_iterator.CurrentPieceColor() != m_color) moves.Add(new Move(board, location, m_iterator.CurrentSquare())); } //Castling moves switch (m_color) { case PieceColor.White: if (board.State.WhiteCanCastleLong && board.IsPathClear(Square.E1, Square.A1) && !board.IsSquareAttacted(PieceColor.Black, Square.E1) && !board.IsSquareAttacted(PieceColor.Black, Square.D1)) { moves.Add(new CastlingMove(board, Square.E1, Square.C1)); } if (board.State.WhiteCanCastleShort && board.IsPathClear(Square.E1, Square.H1) && !board.IsSquareAttacted(PieceColor.Black, Square.E1) && !board.IsSquareAttacted(PieceColor.Black, Square.F1)) { moves.Add(new CastlingMove(board, Square.E1, Square.G1)); } break; case PieceColor.Black: if (board.State.BlackCanCastleLong && board.IsPathClear(Square.E8, Square.A8) && !board.IsSquareAttacted(PieceColor.White, Square.E8) && !board.IsSquareAttacted(PieceColor.White, Square.D8)) { moves.Add(new CastlingMove(board, Square.E8, Square.C8)); } if (board.State.BlackCanCastleShort && board.IsPathClear(Square.E8, Square.H8) && !board.IsSquareAttacted(PieceColor.White, Square.E8) && !board.IsSquareAttacted(PieceColor.White, Square.F8)) { moves.Add(new CastlingMove(board, Square.E8, Square.G8)); } break; } } }
/// <summary> /// Verifies if a piece attacks a square. This method does not check if the piece on "from" /// on the board is of the same type as this FlyweightPiece represents. /// </summary> /// <param name="board">Board to check attacking on.</param> /// <param name="from">Square on which attacking piece is placed.</param> /// <param name="to">The square to check if attacked.</param> /// <returns>True if a FlyweightPiece placed on "from" square attacks the "to" square. False otherwise.</returns> public bool Attacks(Board board, Square from, Square to) { if (Board.File(from) != Board.File(to) && Board.Rank(from) != Board.Rank(to) && (Math.Abs(Board.File(from) - Board.File(to)) + Math.Abs(Board.Rank(from) - Board.Rank(to))) == 3) { return true; } return false; }
/// <summary> /// /// </summary> /// <param name="board"></param> /// <param name="from"></param> /// <param name="to"></param> public Move(Board board, Square from, Square to) { m_moveType = MoveType.StandardMove; m_from = from; m_to = to; m_piece = board[from]; m_capture = board[to]; //m_promoteTo = Piece.None; //m_rookFrom = Square.None; //m_rookTo = Square.None; }
/// <summary> /// Removes a board from the history. If the frequency for /// the board is larger then one the frequency is decreased. /// </summary> /// <param name="board">Board to remove.</param> public void RemoveBoard(Board board) { int count; ZobristHash hash = board.BoardHash(true); m_gameHashHistory.TryGetValue(hash, out count); if (count > 1) m_gameHashHistory[hash] = count - 1; else m_gameHashHistory.Remove(hash); }
/// <summary> /// Verifies if a piece attacks a square. This method does not check if the piece on "from" /// on the board is of the same type as this FlyweightPiece represents. /// </summary> /// <param name="board">Board to check attacking on.</param> /// <param name="from">Square on which attacking piece is placed.</param> /// <param name="to">The square to check if attacked.</param> /// <returns>True if a FlyweightPiece placed on "from" square attacks the "to" square. False otherwise.</returns> public bool Attacks(Board board, Square from, Square to) { if ((m_color == PieceColor.White && Board.Rank(to) == Board.Rank(from) + 1) || (m_color == PieceColor.Black && Board.Rank(to) == Board.Rank(from) - 1)) { if ((Math.Abs(Board.File(to) - Board.File(from)) == 1) && (board.GetPieceColor(to) != m_color)) return true; } return false; }
/// <summary> /// Initializes a new instance of the Game class. /// </summary> /// <param name="board">A board holding the layout this game will be initialized with. If this parameter is null a standard layout will be created.</param> /// <param name="clockConfiguration">The type of clock to use for this game.</param> public Game(Board board, ClockConfiguration clockConfiguration) { m_board = (board == null) ? new Board() : new Board(board); m_possibleMoves = new MoveOrganizer(); m_undoMoveHistory = new Stack<Move>(); m_redoMoveHistory = new Stack<Move>(); SetClockConfiguration(clockConfiguration); HandleGameHasChanged(); }
/// <summary> /// Generate moves a FlyweightPiece can make. /// This method does not varifies if a move puts its own king in check. /// This is done by a move when its carried out. /// </summary> /// <param name="board">Board to generate moves for.</param> /// <param name="location">Location of the piece.</param> /// <param name="moves">Container class to which all generated moves are added.</param> public void GenerateMoves(Board board, Square location, MoveOrganizer moves) { if (m_color == board.State.ColorToPlay) { for (int i = 0; i < KNIGHT_MOVES; ++i) { m_iterator.Reset(board, location, m_directions[i]); m_iterator.Next(m_directions[i + 0]); m_iterator.Next(m_directions[i + 1]); if (m_iterator.Next(m_directions[i + 2])) { if (m_iterator.CurrentPieceColor() != m_color) moves.Add(new Move(board, location, m_iterator.CurrentSquare())); } } } }
/// <summary> /// Generate moves a FlyweightPiece can make. /// This method does not varifies if a move puts its own king in check. /// This is done in MoveOrganizer when adding a move. /// </summary> /// <param name="board">Board to generate moves for.</param> /// <param name="location">Location of the piece.</param> /// <param name="moves">Container class to which all generated moves are added.</param> public void GenerateMoves(Board board, Square location, MoveOrganizer moves) { if (m_color == board.State.ColorToPlay) { for (int i = 0; i < m_directions.Length; i++) { m_iterator.Reset(board, location, m_directions[i]); if (m_iterator.Next(m_directions[(i + 0) % m_directions.Length]) && m_iterator.Next(m_directions[(i + 1) % m_directions.Length]) && m_iterator.Next(m_directions[(i + 2) % m_directions.Length])) { if (m_iterator.CurrentPieceColor() != m_color) moves.Add(new Move(board, location, m_iterator.CurrentSquare())); } } } }
/// <summary> /// Initializes a new instance of the CastlingMove class. /// </summary> /// <param name="board">Board on which the move is to be performed.</param> /// <param name="from">Location kings move is done from.</param> /// <param name="to">Location kings move is done to.</param> public CastlingMove(Board board, Square from, Square to) : base(board, from, to) { switch (from) { case Square.E1: switch (to) { case Square.C1: m_rookFrom = Square.A1; m_rookTo = Square.D1; break; case Square.G1: m_rookFrom = Square.H1; m_rookTo = Square.F1; break; } break; case Square.E8: switch (to) { case Square.C8: m_rookFrom = Square.A8; m_rookTo = Square.D8; break; case Square.G8: m_rookFrom = Square.H8; m_rookTo = Square.F8; break; } break; } }
/// <summary> /// Generate moves a FlyweightPiece can make. /// This method does not varifies if a move puts its own king in check. /// This is done in MoveOrganizer when adding a move. /// </summary> /// <param name="board">Board to generate moves for.</param> /// <param name="location">Location of the piece.</param> /// <param name="moves">Container class to which all generated moves are added.</param> public void GenerateMoves(Board board, Square location, MoveOrganizer moves) { if (m_color == board.State.ColorToPlay) { for (int i = 0; i < m_directions.Length; i++) { m_iterator.Reset(board, location, m_directions[i]); while (m_iterator.Next()) { if (m_iterator.CurrentPiece() == Piece.None) { moves.Add(new Move(board, location, m_iterator.CurrentSquare())); } else { if (m_iterator.CurrentPieceColor() != m_color) moves.Add(new Move(board, location, m_iterator.CurrentSquare())); break; } } } } }
public Board(Board board) { m_squares = new Piece[board.m_squares.Length]; for (int i = 0; i < m_squares.Length; ++i) m_squares[i] = board.m_squares[i]; m_state = board.m_state; m_history = new HashHistory(board.m_history); m_pieceFactory = FlyweightPieceFactory.Instance(); m_whiteLocationList = new PieceLocationManager(board.m_whiteLocationList); m_blackLocationList = new PieceLocationManager(board.BlackPieceLocations); m_whiteKingLocation = board.m_whiteKingLocation; m_blackKingLocation = board.m_blackKingLocation; m_boardHash = new ZobristHash(board.m_boardHash); }
/// <summary> /// Takes back (undo) the move. Nothing is done to verify if undoing the move is actually /// valid for the board associated to this move. /// </summary> private void StandardUnExecute(Board board) { board.RemoveFromHistory(); board.MovePiece(m_to, m_from); board.PlacePiece(m_to, m_capture); board.State = m_beforeState; }
/// <summary> /// Initializes a new instance of a Zobrist hash with a value corrosponding to "board". /// </summary> /// <param name="board">The board the zobrist hash will be created for.</param> public ZobristHash(Board board) { HashSet(board); }
/// <summary> /// Removes illigal moves due to putting ones own king in check. /// </summary> public void RemoveSelfCheckingMoves(Board board) { for (int i = 0; i < m_moves.Count; ++i) { Move move = m_moves[i]; if (move != null) { if (move.Execute(board)) move.UnExecute(board); else m_moves.RemoveAt(i--); } } }
/// <summary> /// Initializes a new instance of the BoardIterator class. /// </summary> /// <param name="board">Board to iterate</param> /// <param name="startSquare">Square where iteration is started.</param> /// <param name="direction">Direction to iterate.</param> public BoardIterator(Board board, Square startSquare, Direction direction) { m_board = board; m_currentSquare = startSquare; m_direction = direction; }
/// <summary> /// Sets the hash value according to a board. /// </summary> /// <param name="board">The board a hash value will be generated for.</param> public void HashSet(Board board) { m_key = 0; m_lock = 0; if (board != null) { foreach (Square square in board) { if (board[square] != Piece.None) { m_key ^= ZobristValues.Keys[((int)board[square] * 128) + (int)square]; m_lock ^= ZobristValues.Locks[((int)board[square] * 128) + (int)square]; } } if (board.State.ColorToPlay == PieceColor.White) { m_key ^= ZobristValues.Keys[1536]; m_lock ^= ZobristValues.Locks[1536]; } if (board.State.WhiteCanCastleLong) { m_key ^= ZobristValues.Keys[1537]; m_lock ^= ZobristValues.Locks[1537]; } if (board.State.WhiteCanCastleShort) { m_key ^= ZobristValues.Keys[1538]; m_lock ^= ZobristValues.Locks[1538]; } if (board.State.BlackCanCastleLong) { m_key ^= ZobristValues.Keys[1539]; m_lock ^= ZobristValues.Locks[1539]; } if (board.State.BlackCanCastleShort) { m_key ^= ZobristValues.Keys[1540]; m_lock ^= ZobristValues.Locks[1540]; } if (board.State.EnPassantTarget != Square.None) { if (Board.Rank(board.State.EnPassantTarget) == 3) { m_key ^= ZobristValues.Keys[1541 + Board.File(board.State.EnPassantTarget)]; m_lock ^= ZobristValues.Locks[1541 + Board.File(board.State.EnPassantTarget)]; } if (Board.Rank(board.State.EnPassantTarget) == 4) { m_key ^= ZobristValues.Keys[1549 + Board.File(board.State.EnPassantTarget)]; m_lock ^= ZobristValues.Locks[1549 + Board.File(board.State.EnPassantTarget)]; } } } }
/// <summary> /// Initializes a new instance of the EnPassantCaptureMove class. /// </summary> /// <param name="board">Board on which the move is to be performed.</param> /// <param name="from">Location move is done from.</param> /// <param name="to">Location move is done to.</param> public EnPassantCaptureMove(Board board, Square from, Square to) : base(board, from, to) { m_capture = board[board.State.EnPassantTarget]; }
/// <summary> /// Resets the iterator. /// </summary> /// <param name="board">Board to iterate</param> /// <param name="startSquare">Square where iteration is started.</param> /// <param name="direction">Direction to iterate.</param> public void Reset(Board board, Square startSquare, Direction direction) { m_board = board; m_currentSquare = startSquare; m_direction = direction; }
/// <summary> /// Generate moves a FlyweightPiece can make. /// This method does not varifies if a move puts its own king in check. /// This is done in MoveOrganizer when adding a move. /// </summary> /// <param name="board">Board to generate moves for.</param> /// <param name="location">Location of the piece.</param> /// <param name="moves">Container class to which all generated moves are added.</param> public void GenerateMoves(Board board, Square location, MoveOrganizer moves) { if (m_color == board.State.ColorToPlay) { for (int i = 0; i < m_directions.Length; i++) { m_iterator.Reset(board, location, m_directions[i]); if (m_iterator.Next()) { if (m_iterator.CurrentPiece() == Piece.None && (m_iterator.CurrentDirection() == Direction.Up || m_iterator.CurrentDirection() == Direction.Down)) { //Non hitting moves switch (Board.Rank(m_iterator.CurrentSquare())) { case 0: //Black non hitting promotion move moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.BlackBishop)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.BlackKnight)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.BlackQueen)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.BlackRook)); break; case 7: //White non hitting promotion move moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.WhiteBishop)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.WhiteKnight)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.WhiteQueen)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.WhiteRook)); break; default: //Basic non hitting move moves.Add(new Move(board, location, m_iterator.CurrentSquare())); break; } if ((Board.Rank(m_iterator.CurrentSquare()) == 2 && m_iterator.CurrentDirection() == Direction.Up) || (Board.Rank(m_iterator.CurrentSquare()) == 5 && m_iterator.CurrentDirection() == Direction.Down)) { //Two squares forward opening move m_iterator.Next(); if (m_iterator.CurrentPiece() == Piece.None) moves.Add(new Move(board, location, m_iterator.CurrentSquare())); } } else if (m_iterator.CurrentPiece() != Piece.None && m_iterator.CurrentPieceColor() != m_color && m_iterator.CurrentDirection() != Direction.Up && m_iterator.CurrentDirection() != Direction.Down) { //Hitting moves switch (Board.Rank(m_iterator.CurrentSquare())) { case 0: //Black hitting promotion move moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.BlackBishop)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.BlackKnight)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.BlackQueen)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.BlackRook)); break; case 7: //White hitting promotion move moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.WhiteBishop)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.WhiteKnight)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.WhiteQueen)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.WhiteRook)); break; default: //Basic hitting move moves.Add(new Move(board, location, m_iterator.CurrentSquare())); break; } } } } //EnPassant moves if (board.State.EnPassantTarget != Square.None && Math.Abs(board.State.EnPassantTarget - location) == 1 && Board.Rank(board.State.EnPassantTarget) == Board.Rank(location)) { switch (m_color) { case PieceColor.White: moves.Add(new EnPassantCaptureMove(board, location, Board.Position(Board.File(board.State.EnPassantTarget), Board.Rank(location) + 1))); break; case PieceColor.Black: moves.Add(new EnPassantCaptureMove(board, location, Board.Position(Board.File(board.State.EnPassantTarget), Board.Rank(location) - 1))); break; } } } }
/// <summary> /// Makes computer think. When the move to play as been decided the /// "MoveFound" event is raised. /// </summary> /// <param name="board">The board to find a move for.</param> /// <param name="moveOrganizer">List of possible moves for the current position on board.</param> /// <param name="useBook">May the engine use the opening book when selecting a move.</param> /// <param name="maxSearchDepth">Maximum AlphaBeta depth to search. Must be equal to, or larger then one.</param> /// <param name="maxSearchTime">Time before search is stoppen.</param> /// <param name="clockTime">The remaining time of the clock.</param> public void Think(Board board, MoveOrganizer moveOrganizer, bool useBook, int maxSearchDepth, TimeSpan maxSearchTime, TimeSpan clockTime) { if (!m_thinking) { m_waitHandle.Reset(); m_thinking = true; TimeSpan calculatedAimTime = m_timeControl.CalculateAimedSearchTime(clockTime); TimeSpan calculatedMaxTime = m_timeControl.CalculateMaxSearchTime(clockTime); if (calculatedMaxTime > maxSearchTime) calculatedMaxTime = maxSearchTime; if (calculatedAimTime > calculatedMaxTime) calculatedAimTime = calculatedMaxTime; m_workerThread.RunWorkerAsync(new ThreadParam(board, moveOrganizer, useBook, maxSearchDepth, calculatedAimTime, calculatedMaxTime)); } }
/// <summary> /// Instantiates a new instance of the "ThreadParam" class. /// </summary> /// <param name="board">Board associated with move organizer.</param> /// <param name="moveOrganizer">Collection of moves to evaluate and carry out search for.</param> /// <param name="useBook">May the engine use the opening book when selecting a move.</param> /// <param name="searchDepth">Depth to search.</param> /// <param name="aimSearchTime">Time to search. Actual search will typically be a little more.</param> /// <param name="maxSearchTime">Maximum time to search.</param> public ThreadParam(Board board, MoveOrganizer moveOrganizer, bool useBook, int searchDepth, TimeSpan aimSearchTime, TimeSpan maxSearchTime) { m_board = board; m_moveOrganizer = moveOrganizer; m_useBook = useBook; m_maxSearchDepth = searchDepth; m_aimSearchTime = aimSearchTime; m_maxSearchTime = maxSearchTime; }
/// <summary> /// Evaluates a board from the perspective of the current player. /// </summary> /// <param name="board">Board to evaluate.</param> /// <returns>Score for board.</returns> public int EvaluatePosition(Board board) { m_board = board; m_whiteLocations = board.WhitePieceLocations; m_blackLocations = board.BlackPieceLocations; m_whiteScore = 0; m_blackScore = 0; EvaluateMaterial(); EvaluatePositions(); EvaluatePawns(); switch (m_board.State.ColorToPlay) { case PieceColor.Black: return m_blackScore - m_whiteScore; case PieceColor.White: return m_whiteScore - m_blackScore; default: return 0; } }
public Move Query(Board board, MoveOrganizer moveOrganizer) { int totalQuaryVal = 0; m_queryMoves.Clear(); foreach (Move move in moveOrganizer) { if (move.Execute(board)) { int currentQueryVal = 0; if (board.State.NonHitAndPawnMovesPlayed < 100 && board.BoardHistoryFrequency() < 3 && m_positionTable.TryGetValue(board.BoardHash(false), out currentQueryVal)) { totalQuaryVal += currentQueryVal; m_queryMoves.Add(new QueryEntry(move, currentQueryVal)); } move.UnExecute(board); } } //select a move using probabilety based on the quary value int selectValueCurrent = 0; int selectValueTarget = (int)Math.Round(m_moveSelector.NextDouble() * totalQuaryVal); for (int i = 0; i < m_queryMoves.Count; ++i) { selectValueCurrent += m_queryMoves[i].QueryScore; if (selectValueCurrent >= selectValueTarget) { OutputWriter.Write("Book moves: " + m_queryMoves.Count + ", Selecting: " + Math.Round((float)m_queryMoves[i].QueryScore / (float)totalQuaryVal, 6)); return m_queryMoves[i].QueryMove; } } return null; }
/// <summary> /// Generate moves a FlyweightPiece can make. /// This method does not varifies if a move puts its own king in check. /// This is done by a move when its carried out. /// </summary> /// <param name="board">Board to generate moves for.</param> /// <param name="location">Location of the piece.</param> /// <param name="moves">Container class to which all generated moves are added.</param> public void GenerateMoves(Board board, Square location, MoveOrganizer moves) { if (m_color == board.State.ColorToPlay) { //Non hitting moves m_iterator.Reset(board, location, m_directions[0]); if (m_iterator.Next()) { if (m_iterator.CurrentPiece() == Piece.None) { switch (Board.Rank(m_iterator.CurrentSquare())) { case 0: //Black non hitting promotion move moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.BlackBishop)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.BlackKnight)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.BlackQueen)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.BlackRook)); break; case 7: //White non hitting promotion move moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.WhiteBishop)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.WhiteKnight)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.WhiteQueen)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.WhiteRook)); break; default: //Basic non hitting move moves.Add(new Move(board, location, m_iterator.CurrentSquare())); break; } //Two squares forward opening move if (Board.Rank(m_iterator.CurrentSquare()) == moveAgainRow) { m_iterator.Next(); if (m_iterator.CurrentPiece() == Piece.None) moves.Add(new Move(board, location, m_iterator.CurrentSquare())); } } } //Hitting moves to the left and right for (int i = 1; i < m_directions.Length; ++i) { m_iterator.Reset(board, location, m_directions[i]); if (m_iterator.Next()) { if (m_iterator.CurrentPieceColor() == m_opponentColor) { switch (Board.Rank(m_iterator.CurrentSquare())) { case 0: //Black hitting promotion move moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.BlackBishop)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.BlackKnight)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.BlackQueen)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.BlackRook)); break; case 7: //White hitting promotion move moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.WhiteBishop)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.WhiteKnight)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.WhiteQueen)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.WhiteRook)); break; default: //Basic hitting move moves.Add(new Move(board, location, m_iterator.CurrentSquare())); break; } } } } //EnPassant moves if (Math.Abs(board.State.EnPassantTarget - location) == 1) { switch (m_color) { case PieceColor.White: moves.Add(new Move(board, location, Board.Position(Board.File(board.State.EnPassantTarget), Board.Rank(location) + 1), board.State.EnPassantTarget)); break; case PieceColor.Black: moves.Add(new Move(board, location, Board.Position(Board.File(board.State.EnPassantTarget), Board.Rank(location) - 1), board.State.EnPassantTarget)); break; } } } }
/// <summary> /// Obtains the frequency of a board in the history. /// </summary> /// <param name="board">Board to return frequency for.</param> /// <returns>Frequency of board.</returns> public int BoardFrequency(Board board) { int count; m_gameHashHistory.TryGetValue(board.BoardHash(false), out count); return count; }