public void Reset(PlayerPieceSet white_pieces, PlayerPieceSet black_pieces) { Debug.Assert(white_pieces != null); Debug.Assert(black_pieces != null); AddPieces(white_pieces, Players.White); AddPieces(black_pieces, Players.Black); }
public static ChessboardArray GetChessboardArray(PlayerPieceSet white_pieces, PlayerPieceSet black_pieces) { // TODO var result = new ChessboardArray(); result.Reset(white_pieces, black_pieces); return result; }
private static void MakeBishopMoves(PlayerPieceSet my_pieces, PlayerPieceSet other_pieces, List<Move> moves) { for (uint i = 0, e = my_pieces.BishopsCount; i < e; ++i) { uint cell_index; int cell = my_pieces.GetBishopCell(i, out cell_index); MakeDiagonalMoves(Exports.Pieces.Bishop, my_pieces, other_pieces, cell, cell_index, moves); } }
private void AddPieces(PlayerPieceSet pieces, Players player) { Debug.Assert(pieces != null); AddPiece(player, Exports.Pieces.King, pieces.KingsCell); for (uint i = 0, e = pieces.QueensCount; i < e; ++i) { AddPiece(player, Exports.Pieces.Queen, pieces.GetQueenCell(i)); } for (uint i = 0, e = pieces.RooksCount; i < e; ++i) { AddPiece(player, Exports.Pieces.Rook, pieces.GetRookCell(i)); } for (uint i = 0, e = pieces.BishopsCount; i < e; ++i) { AddPiece(player, Exports.Pieces.Bishop, pieces.GetBishopCell(i)); } for (uint i = 0, e = pieces.KnightsCount; i < e; ++i) { AddPiece(player, Exports.Pieces.Knight, pieces.GetKnightCell(i)); } for (uint i = 0, e = pieces.PawnsCount; i < e; ++i) { AddPiece(player, Exports.Pieces.Pawn, pieces.GetPawnCell(i)); } }
public void Reset(PlayerPieceSet white_pieces, PlayerPieceSet black_pieces, Players player_to_move, Castle white_castling_options, Castle black_castling_options, int? capture_en_passant_column, ushort fullmove_number, ushort halfmove_clock) { Debug.Assert(white_pieces != null); Debug.Assert(black_pieces != null); Debug.Assert(m_white_pieces == null); Debug.Assert(m_black_pieces == null); m_white_pieces = white_pieces; m_black_pieces = black_pieces; m_position_flags.Clear(); if (player_to_move == Players.White) { m_position_flags.SetBit(BIT_WHITE_TO_MOVE); } // TODO - HasFlag is known to be slow, consider optimizing SetCanCastleShort(Players.White, white_castling_options.HasFlag(Castle.Short)); SetCanCastleLong(Players.White, white_castling_options.HasFlag(Castle.Long)); SetCanCastleShort(Players.Black, black_castling_options.HasFlag(Castle.Short)); SetCanCastleLong(Players.Black, black_castling_options.HasFlag(Castle.Long)); CaptureEnPassantColumn = capture_en_passant_column; FullmoveNumber = fullmove_number; HalfmoveClock = halfmove_clock; }
private Castle CalcNewCastlingOptions(Players player, PlayerPieceSet pieces, int base_row) { // We could deduce base_row value here, but let us pass it is as a // parameter for better(?) performance // Nevertheless, it is worth to check for typos Debug.Assert((player == Players.White && base_row == Chessboard.ROW_MIN) || (player == Players.Black && base_row == Chessboard.ROW_MAX)); var result = Castle.None; if (pieces.KingsCell == ChessboardCell.CalculateValue(base_row, Chessboard.COLUMN_E)) { var cell = ChessboardCell.CalculateValue(base_row, Chessboard.COLUMN_H); if (IsCanCastleShort(player) && pieces.IsOccupiedCell(cell) && pieces.IsRookAtCell(cell)) { result |= Castle.Short; } cell = ChessboardCell.CalculateValue(base_row, Chessboard.COLUMN_A); if (IsCanCastleLong(player) && pieces.IsOccupiedCell(cell) && pieces.IsRookAtCell(cell)) { result |= Castle.Long; } } return result; }
public static bool IsQueenAttacks(ChessboardCell queen_cell, ChessboardCell cell_to_check, PlayerPieceSet my_pieces, PlayerPieceSet other_pieces) { return IsBishopAttacks(queen_cell, cell_to_check, my_pieces, other_pieces) || IsRookAttacks(queen_cell, cell_to_check, my_pieces, other_pieces); }
public static bool IsCellAttackedFromDir(ChessboardCell attacked_cell, ChessboardCell attack_origin, PlayerPieceSet attacker_pieces, PlayerPieceSet defender_pieces) { Debug.Assert(!attacked_cell.IsSame(attack_origin)); int delta_row = attack_origin.Row - attacked_cell.Row; int delta_column = attack_origin.Column - attacked_cell.Column; // Fast check if the two cells are on the same vertical or horizontal line // or one the same diagonal if (delta_row != 0 && delta_column != 0 && delta_row != delta_column && delta_row != -delta_column) { return false; } // Check the ray from attacked_cell towards attack_origin and possibly behind // attack_origin until we reach the edge of the chessboard bool result = false; int row_inc = 0; int column_inc = 0; int iter_count = int.MaxValue; if (delta_row < 0) { row_inc = -1; iter_count = attacked_cell.Row - Chessboard.ROW_MIN; } else if (delta_row > 0) { row_inc = 1; iter_count = Chessboard.ROW_MAX - attacked_cell.Row; } if (delta_column < 0) { column_inc = -1; iter_count = Math.Min(iter_count, attacked_cell.Column - Chessboard.COLUMN_MIN); } else if (delta_column > 0) { column_inc = 1; iter_count = Math.Min(iter_count, Chessboard.COLUMN_MAX - attacked_cell.Column); } int cur_row = attacked_cell.Row; int cur_column = attacked_cell.Column; for (int i = 0; i < iter_count; ++i) { cur_row += row_inc; cur_column += column_inc; Debug.Assert(cur_row >= Chessboard.ROW_MIN && cur_row <= Chessboard.ROW_MAX && cur_column >= Chessboard.COLUMN_MIN && cur_column <= Chessboard.COLUMN_MAX); int cur_cell = ChessboardCell.CalculateValue(cur_row, cur_column); if (defender_pieces.IsOccupiedCell(cur_cell)) { result = false; break; } if (attacker_pieces.IsOccupiedCell(cur_cell)) { if (attacker_pieces.IsQueenAtCell(cur_cell)) { result = true; } else if (row_inc == 0 || column_inc == 0) { result = attacker_pieces.IsRookAtCell(cur_cell); } else { result = attacker_pieces.IsBishopAtCell(cur_cell); } break; } } return result; }
private static void MakeHorizVertMoves(Exports.Pieces piece, PlayerPieceSet my_pieces, PlayerPieceSet other_pieces, int from_cell, List<Move> moves) { Debug.Assert(piece == Exports.Pieces.Rook || piece == Exports.Pieces.Queen); var from_cell_obj = new ChessboardCell(from_cell); // Left MakeMovesAlongLine(piece, my_pieces, other_pieces, from_cell, 0, -1, from_cell_obj.Column, moves); // Right MakeMovesAlongLine(piece, my_pieces, other_pieces, from_cell, 0, 1, Chessboard.COLUMN_MAX - from_cell_obj.Column, moves); // Down MakeMovesAlongLine(piece, my_pieces, other_pieces, from_cell, -1, 0, from_cell_obj.Row, moves); // Up MakeMovesAlongLine(piece, my_pieces, other_pieces, from_cell, 1, 0, Chessboard.ROW_MAX - from_cell_obj.Row, moves); }
public static bool IsRookAttacks(ChessboardCell rook_cell, ChessboardCell cell_to_check, PlayerPieceSet my_pieces, PlayerPieceSet other_pieces) { return (rook_cell.Row == cell_to_check.Row || rook_cell.Column == cell_to_check.Column) && IsCellAttackedFromDir(cell_to_check, rook_cell, my_pieces, other_pieces); }
private static void MakeKingMoves(PlayerPieceSet my_pieces, PlayerPieceSet other_pieces, List<Move> moves) { var king_cell = new ChessboardCell(my_pieces.KingsCell); int row_min = Math.Max(Chessboard.ROW_MIN, king_cell.Row - 1); int row_max = Math.Min(Chessboard.ROW_MAX, king_cell.Row + 1); int column_min = Math.Max(Chessboard.COLUMN_MIN, king_cell.Column - 1); int column_max = Math.Min(Chessboard.COLUMN_MAX, king_cell.Column + 1); for (int row = row_min; row <= row_max; ++row) { for (int column = column_min; column <= column_max; ++column) { int new_cell = ChessboardCell.CalculateValue(row, column); if (!my_pieces.IsOccupiedCell(new_cell)) { bool is_capture = other_pieces.IsOccupiedCell(new_cell); moves.Add(new Move(Exports.Pieces.King, king_cell.Value, new_cell, 0, is_capture ? Move.Flags.Capture : 0)); } } } }
public static PlayerPieceSet MovePiece(PlayerPieceSet base_obj, Exports.Pieces piece, int remove_at_cell, int new_cell) { Debug.Assert(base_obj != null); Debug.Assert(piece != Exports.Pieces.NoPiece); Debug.Assert(remove_at_cell >= 0 && remove_at_cell < 64); Debug.Assert(new_cell >= 0 && new_cell < 64); Debug.Assert(remove_at_cell != new_cell); Debug.Assert(base_obj.IsOccupiedCell(remove_at_cell)); Debug.Assert(!base_obj.IsOccupiedCell(new_cell)); var result = (PlayerPieceSet)base_obj.MemberwiseClone(); result.m_bitboard.UnsetBit(remove_at_cell); result.m_bitboard.SetBit(new_cell); // Insert new_cell first. Easier to do it now, because we know // the sorted ranges uint range_begin = 0; uint range_length = 0; switch (piece) { case Exports.Pieces.Pawn: range_begin = result.PawnsStartIndex; range_length = result.PawnsCount; break; case Exports.Pieces.Knight: range_begin = result.KnightsStartIndex; range_length = result.KnightsCount; break; case Exports.Pieces.Bishop: range_begin = result.BishopsStartIndex; range_length = result.BishopsCount; break; case Exports.Pieces.Rook: range_begin = result.RooksStartIndex; range_length = result.RooksCount; break; case Exports.Pieces.Queen: range_begin = result.QueensStartIndex; range_length = result.QueensCount; break; case Exports.Pieces.King: range_begin = 0; range_length = 1; break; } bool is_inserted = false; for (uint i = range_begin, e = range_begin + range_length; i < e; ++i) { if (new_cell < result.m_pieces_cells.GetCell(i)) { result.m_pieces_cells.InsertAt(i, new_cell); is_inserted = true; break; } } if (!is_inserted) { result.m_pieces_cells.InsertAt(range_begin + range_length, new_cell); } result.m_pieces_cells.EraseAt( (uint)result.m_pieces_cells.FindIndex(remove_at_cell)); return result; }
private static void MakeRookMoves(PlayerPieceSet my_pieces, PlayerPieceSet other_pieces, List<Move> moves) { for (uint i = 0, e = my_pieces.RooksCount; i < e; ++i) { MakeHorizVertMoves(Exports.Pieces.Rook, my_pieces, other_pieces, my_pieces.GetRookCell(i), moves); } }
private static void MakeQueeenMoves(PlayerPieceSet my_pieces, PlayerPieceSet other_pieces, List<Move> moves) { for (uint i = 0, e = my_pieces.QueensCount; i < e; ++i) { uint cell_index; int queen_cell = my_pieces.GetQueenCell(i, out cell_index); MakeHorizVertMoves(Exports.Pieces.Queen, my_pieces, other_pieces, queen_cell, moves); MakeDiagonalMoves(Exports.Pieces.Queen, my_pieces, other_pieces, queen_cell, cell_index, moves); } }
private static void MakePawnMoves(PlayerPieceSet my_pieces, PlayerPieceSet other_pieces, bool is_white_to_move, int? en_passant_capture_column, List<Move> moves) { int move_row_diff = is_white_to_move ? 1 : -1; for (uint i = 0, e = my_pieces.PawnsCount; i < e; ++i) { uint cell_index; var pawn_cell = new ChessboardCell(my_pieces.GetPawnCell(i, out cell_index)); var new_cell_value = ChessboardCell.CalculateValue( pawn_cell.Row + move_row_diff, pawn_cell.Column); // Moves without captures if (!my_pieces.IsOccupiedCell(new_cell_value) && !other_pieces.IsOccupiedCell(new_cell_value)) { WritePawnMove(pawn_cell.Value, new_cell_value, cell_index, 0, moves); // Two-rows move from the initial rank int initial_row = is_white_to_move ? Chessboard.ROW_MIN + 1 : Chessboard.ROW_MAX - 1; if (pawn_cell.Row == initial_row) { new_cell_value = ChessboardCell.CalculateValue( pawn_cell.Row + 2 * move_row_diff, pawn_cell.Column); if (!my_pieces.IsOccupiedCell(new_cell_value) && !other_pieces.IsOccupiedCell(new_cell_value)) { WritePawnMove(pawn_cell.Value, new_cell_value, cell_index, 0, moves); } } } // Captures except en passant captures // delta_column can be -1 or 1 for (int delta_column = -1; delta_column <= 1; delta_column += 2) { int new_column = pawn_cell.Column + delta_column; if (new_column >= Chessboard.COLUMN_MIN && new_column <= Chessboard.COLUMN_MAX) { new_cell_value = ChessboardCell.CalculateValue(pawn_cell.Row + move_row_diff, new_column); if (other_pieces.IsOccupiedCell(new_cell_value)) { WritePawnMove(pawn_cell.Value, new_cell_value, cell_index, Move.Flags.Capture, moves); } } } // En passant capture if (en_passant_capture_column.HasValue && ((is_white_to_move && pawn_cell.Row == 4) || (!is_white_to_move && pawn_cell.Row == 3)) && Math.Abs(pawn_cell.Column - en_passant_capture_column.Value) == 1) { new_cell_value = ChessboardCell.CalculateValue(pawn_cell.Row + move_row_diff, en_passant_capture_column.Value); // Since en passant capture is allowed, we know that the destination // cell is not occupied WritePawnMove(pawn_cell.Value, new_cell_value, cell_index, Move.Flags.Capture | Move.Flags.EnPassantCapture, moves); } // TODO - add en passant captures // TODO - uncomment //throw new NotImplementedException(); } }
private static void MakeMovesAlongLine(Exports.Pieces piece, PlayerPieceSet my_pieces, PlayerPieceSet other_pieces, int from_cell, int delta_row, int delta_column, int count, List<Move> moves) { var from_cell_obj = new ChessboardCell(from_cell); // count must be such that we hit the border of the chessboard at the end // of the loop Debug.Assert( from_cell_obj.Row + count * delta_row == Chessboard.ROW_MIN || from_cell_obj.Row + count * delta_row == Chessboard.ROW_MAX || from_cell_obj.Column + count * delta_column == Chessboard.COLUMN_MIN || from_cell_obj.Column + count * delta_column == Chessboard.COLUMN_MAX); int cur_row = from_cell_obj.Row; int cur_column = from_cell_obj.Column; for (int i = 0; i < count; ++i) { cur_row += delta_row; cur_column += delta_column; Debug.Assert(cur_row >= Chessboard.ROW_MIN && cur_row <= Chessboard.ROW_MAX && cur_column >= Chessboard.COLUMN_MIN && cur_column <= Chessboard.COLUMN_MAX); var cur_cell = ChessboardCell.CalculateValue(cur_row, cur_column); if (my_pieces.IsOccupiedCell(cur_cell)) { break; } bool is_capture = other_pieces.IsOccupiedCell(cur_cell); moves.Add(new Move(piece, from_cell, cur_cell, 0 /* TODO - FIXME */, is_capture ? Move.Flags.Capture : 0)); if (is_capture) { break; } } }
private static void MakeKnightMoves(PlayerPieceSet my_pieces, PlayerPieceSet other_pieces, List<Move> moves) { for (uint i = 0, e = my_pieces.KnightsCount; i < e; ++i) { uint cell_index; var knight_cell = new ChessboardCell(my_pieces.GetKnightCell(i, out cell_index)); if (knight_cell.Row - 2 >= Chessboard.ROW_MIN && knight_cell.Row + 2 <= Chessboard.ROW_MAX && knight_cell.Column - 2 >= Chessboard.COLUMN_MIN && knight_cell.Column + 2 <= Chessboard.COLUMN_MAX) { // In this case we do not need to check that new cells are within // the chessboard foreach (var move_delta in m_knight_moves) { var new_cell = ChessboardCell.CalculateValue( knight_cell.Row + move_delta.m_delta_row, knight_cell.Column + move_delta.m_delta_column); if (!my_pieces.IsOccupiedCell(new_cell)) { bool is_capture = other_pieces.IsOccupiedCell(new_cell); moves.Add(new Move(Exports.Pieces.Knight, knight_cell.Value, new_cell, cell_index, is_capture ? Move.Flags.Capture : 0)); } } } else { // Do range check for every new cell foreach (var move_delta in m_knight_moves) { int new_row = knight_cell.Row + move_delta.m_delta_row; if (new_row < Chessboard.ROW_MIN || new_row > Chessboard.ROW_MAX) { continue; } int new_column = knight_cell.Column + move_delta.m_delta_column; if (new_column < Chessboard.COLUMN_MIN || new_column > Chessboard.COLUMN_MAX) { continue; } var new_cell = ChessboardCell.CalculateValue(new_row, new_column); if (!my_pieces.IsOccupiedCell(new_cell)) { bool is_capture = other_pieces.IsOccupiedCell(new_cell); moves.Add(new Move(Exports.Pieces.Knight, knight_cell.Value, new_cell, cell_index, is_capture ? Move.Flags.Capture : 0)); } } } } }
public static PlayerPieceSet InsertPiece(PlayerPieceSet base_obj, Exports.Pieces piece_to_insert, int insert_at_cell) { Debug.Assert(base_obj != null); Debug.Assert(piece_to_insert != Exports.Pieces.NoPiece && piece_to_insert != Exports.Pieces.King); Debug.Assert(insert_at_cell >= 0 && insert_at_cell < 64); Debug.Assert(!base_obj.IsOccupiedCell(insert_at_cell)); var result = (PlayerPieceSet)base_obj.MemberwiseClone(); result.m_bitboard.SetBit(insert_at_cell); uint start_index = 0; uint cur_piece_count = 0; switch (piece_to_insert) { // TODO - add checks like PawnsCount < MAX_PAWN_COUNT case Exports.Pieces.Pawn: start_index = result.PawnsStartIndex; cur_piece_count = result.PawnsCount; ++result.PawnsCount; break; case Exports.Pieces.Knight: start_index = result.KnightsStartIndex; cur_piece_count = result.KnightsCount; // Increment result.KnightsCount ++result.PawnsStartIndex; break; case Exports.Pieces.Bishop: start_index = result.BishopsStartIndex; cur_piece_count = result.BishopsCount; // Increment result.BishopsCount ++result.PawnsStartIndex; ++result.KnightsStartIndex; break; case Exports.Pieces.Rook: start_index = result.RooksStartIndex; cur_piece_count = result.RooksCount; // Increment result.RooksCount ++result.PawnsStartIndex; ++result.KnightsStartIndex; ++result.BishopsStartIndex; break; case Exports.Pieces.Queen: start_index = result.QueensStartIndex; cur_piece_count = result.QueensCount; // Increment result.QueensCount ++result.PawnsStartIndex; ++result.KnightsStartIndex; ++result.BishopsStartIndex; ++result.RooksStartIndex; break; } result.m_pieces_cells.InsertAt(result.m_pieces_cells .GetInsertionIndex(start_index, cur_piece_count, insert_at_cell), insert_at_cell); return result; }
public static bool IsBishopAttacks(ChessboardCell bishop_cell, ChessboardCell cell_to_check, PlayerPieceSet my_pieces, PlayerPieceSet other_pieces) { return bishop_cell.IsSameDiagonal(cell_to_check) && IsCellAttackedFromDir(cell_to_check, bishop_cell, my_pieces, other_pieces); }
public static PlayerPieceSet RemovePiece(PlayerPieceSet base_obj, Exports.Pieces piece_to_remove, int remove_at_cell) { Debug.Assert(base_obj != null); Debug.Assert(piece_to_remove != Exports.Pieces.NoPiece && piece_to_remove != Exports.Pieces.King); Debug.Assert(remove_at_cell >= 0 && remove_at_cell < 64); Debug.Assert(base_obj.IsOccupiedCell(remove_at_cell)); var result = (PlayerPieceSet)base_obj.MemberwiseClone(); result.m_bitboard.UnsetBit(remove_at_cell); uint start_index = 0; switch (piece_to_remove) { case Exports.Pieces.Pawn: start_index = result.PawnsStartIndex; Debug.Assert(result.PawnsCount > 0); --result.PawnsCount; break; case Exports.Pieces.Knight: start_index = result.KnightsStartIndex; Debug.Assert(result.KnightsCount > 0); // Decrement result.KnightsCount --result.PawnsStartIndex; break; case Exports.Pieces.Bishop: start_index = result.BishopsStartIndex; Debug.Assert(result.BishopsCount > 0); // Decrement result.BishopsCount --result.PawnsStartIndex; --result.KnightsStartIndex; break; case Exports.Pieces.Rook: start_index = result.RooksStartIndex; Debug.Assert(result.RooksCount > 0); // Decrement result.RooksCount --result.PawnsStartIndex; --result.KnightsStartIndex; --result.BishopsStartIndex; break; case Exports.Pieces.Queen: start_index = result.QueensStartIndex; Debug.Assert(result.QueensCount > 0); // Decrement result.QueensCount --result.PawnsStartIndex; --result.KnightsStartIndex; --result.BishopsStartIndex; --result.RooksStartIndex; break; } result.m_pieces_cells.EraseAt((uint)result.m_pieces_cells .FindNextIndex(start_index, remove_at_cell)); return result; }
private static void MakeDiagonalMoves(Exports.Pieces piece, PlayerPieceSet my_pieces, PlayerPieceSet other_pieces, int from_cell, uint cell_index, List<Move> moves) { Debug.Assert(piece == Exports.Pieces.Bishop || piece == Exports.Pieces.Queen); var from_cell_obj = new ChessboardCell(from_cell); // Down-left diagonal MakeMovesAlongLine(piece, my_pieces, other_pieces, from_cell, -1, -1, Math.Min(from_cell_obj.Row, from_cell_obj.Column), moves); // Down-right diagonal MakeMovesAlongLine(piece, my_pieces, other_pieces, from_cell, 1, -1, Math.Min(Chessboard.ROW_MAX - from_cell_obj.Row, from_cell_obj.Column), moves); // Up-right diagonal MakeMovesAlongLine(piece, my_pieces, other_pieces, from_cell, 1, 1, Math.Min(Chessboard.ROW_MAX - from_cell_obj.Row, Chessboard.COLUMN_MAX - from_cell_obj.Column), moves); // Up-left diagonal MakeMovesAlongLine(piece, my_pieces, other_pieces, from_cell, -1, 1, Math.Min(from_cell_obj.Row, Chessboard.COLUMN_MAX - from_cell_obj.Column), moves); }