class TestIsBeingChecked(unittest.TestCase): def setUp(self) -> None: self.game = ChessGame(fen="start") def test_is_being_checked_start(self): self.assertFalse(self.game.is_being_checked()) def test_is_being_checked_during_game_true(self): empty = Empty(None, Color.EMPTY, -1, -1) for row in range(8): for col in range(8): self.game.board[row][col] = empty self.game.board[0][0] = King(self.game, Color.WHITE, 0, 0) self.game.board[7][3] = King(self.game, Color.BLACK, 7, 3) self.game.kings_coordinate = [(0, 0), (7, 3)] self.game.board[1][0] = Pawn(self.game, Color.BLACK, 1, 0) self.game.board[4][5] = Pawn(self.game, Color.WHITE, 4, 5) self.game.board[4][1] = Rook(self.game, Color.WHITE, 4, 1) self.game.board[3][3] = Bishop(self.game, Color.BLACK, 3, 3) self.assertTrue(self.game.is_being_checked()) def test_is_being_checked_during_game_false(self): empty = Empty(None, Color.EMPTY, -1, -1) for row in range(8): for col in range(8): self.game.board[row][col] = empty self.game.board[0][4] = King(self.game, Color.WHITE, 0, 4) self.game.board[7][3] = King(self.game, Color.BLACK, 7, 3) self.game.kings_coordinate = [(0, 4), (7, 3)] self.game.board[1][0] = Pawn(self.game, Color.BLACK, 1, 0) self.game.board[4][5] = Pawn(self.game, Color.WHITE, 4, 5) self.game.board[4][1] = Rook(self.game, Color.WHITE, 4, 1) self.game.board[3][3] = Bishop(self.game, Color.BLACK, 3, 3) self.assertFalse(self.game.is_being_checked())
class TestUpdateCastle(unittest.TestCase): def setUp(self) -> None: self.game = ChessGame(fen="start") def test_update_castle(self): self.game.half_move_clock = 0 self.game.full_move_clock = 10 self.game.count = 20 self.game.empty_cell = Empty(None, Color.EMPTY, -1, -1) self.game.history = [{"fen": "r3k3/8/8/8/Pp6/8/8/4K2R b Kq a3 0 10", "movement": {"src": "a2", "tar": "a4"}}] self.game.turn = Color.BLACK for row in range(8): for col in range(8): self.game.board[row][col] = self.game.empty_cell self.game.board[7][4] = King(self.game, Color.BLACK, 7, 4) self.game.board[7][4].firstMove = True self.game.board[7][0] = Rook(self.game, Color.BLACK, 7, 0) self.game.board[7][0].firstMove = True self.game.board[0][4] = King(self.game, Color.WHITE, 0, 4) self.game.board[0][4].firstMove = True self.game.board[0][7] = Rook(self.game, Color.WHITE, 0, 7) self.game.board[0][7].firstMove = True self.game.board[3][0] = Pawn(self.game, Color.WHITE, 3, 0) self.game.board[3][1] = Pawn(self.game, Color.BLACK, 3, 1) expected_1 = self.game.board[7][0] expected_2 = self.game.board[0][7] self.game.update_castle((7, 4), (7, 2)) self.assertEqual(self.game.board[7][3], expected_1) self.game.update_castle((0, 4), (0, 6)) self.assertEqual(self.game.board[0][5], expected_2)
def create_game(self, username: str, mode: str) -> dict: """ Create a new chess game in put it in the dictionary, store the data in the database. :param username: username of the user playing the game :param mode: the mode of the game. "easy": easy AI game; "advanced": advanced AI game; "pvp": player vs player :return: A dict where only has one key "session_id" """ session_id = self.generate_unique_session_id() game = ChessGame() self.sessions[session_id] = (game, username) self.modes[session_id] = mode time = datetime.datetime.now() fen = game.get_fen() status = game.check_game_status() conn = self.engine.connect() conn.execute( self.current_game.insert(), { "username": username, "session_id": session_id, "status": status, "fen": fen, "mode": mode, "start_time": time, "last_update": time }) conn.close() return {"session_id": session_id, "valid": True}
class TestGetFen(unittest.TestCase): def setUp(self) -> None: self.game = ChessGame(fen="start") def test_get_fen_start(self): self.assertEqual(self.game.get_fen(), "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1") def test_get_fen_during_game(self): empty = Empty(None, Color.EMPTY, -1, -1) for row in range(8): for col in range(8): self.game.board[row][col] = empty self.game.board[0][0] = King(self.game, Color.WHITE, 0, 0) self.game.board[7][3] = King(self.game, Color.BLACK, 7, 3) self.game.board[1][0] = Pawn(self.game, Color.BLACK, 1, 0) self.game.board[4][5] = Pawn(self.game, Color.WHITE, 4, 5) self.game.board[4][1] = Rook(self.game, Color.WHITE, 4, 1) self.game.board[3][3] = Bishop(self.game, Color.BLACK, 3, 3) self.game.history = [{"src": (0, 4)}, {"src": (7, 4)}] self.game.en_passant_target_notation = "-" self.game.half_move_clock = 0 self.game.full_move_clock = 20 self.assertEqual(self.game.get_fen(), "3k4/8/8/1R3P2/3b4/8/p7/K7 w - - 0 20")
class TestGetGameHistory(unittest.TestCase): def setUp(self) -> None: self.game = ChessGame(fen="start") def test_get_game_history_empty(self): self.game.history = [] expected = [] ret = self.game.get_game_history() self.assertEqual(ret, expected) def test_get_game_history_restores_expected_history(self): self.game.history = [{"fen": "rnbqkbnr/pppppppp/8/8/P7/8/1PPPPPPP/RNBQKBNR b KQkq a3 0 1", "movement": {"src": "a2", "tar": "a4"}}, {"fen": "rnbqkbnr/1ppppppp/8/p7/P7/8/1PPPPPPP/RNBQKBNR w KQkq a6 0 2", "movement": {"src": "a7", "tar": "a5"}}, {"fen": "rnbqkbnr/1ppppppp/8/p7/P7/R7/1PPPPPPP/1NBQKBNR b Kkq - 1 2", "movement": {"src": "a1", "tar": "a3"}}, {"fen": "1nbqkbnr/1ppppppp/r7/p7/P7/R7/1PPPPPPP/1NBQKBNR w Kk - 2 3", "movement": {"src": "a8", "tar": "a6"}}, {"fen": "1nbqkbnr/1ppppppp/r7/p7/P6P/R7/1PPPPPP1/1NBQKBNR b Kk h3 0 3", "movement": {"src": "h2", "tar": "h4"}}, {"fen": "1nbqkbnr/1pppppp1/r7/p6p/P6P/R7/1PPPPPP1/1NBQKBNR w Kk h6 0 4", "movement": {"src": "h7", "tar": "h5"}}, {"fen": "1nbqkbnr/1pppppp1/r7/p6p/P6P/R6R/1PPPPPP1/1NBQKBN1 b k - 1 4", "movement": {"src": "h1", "tar": "h3"}}] expected = [{"src": "a2", "tar": "a4"}, {"src": "a7", "tar": "a5"}, {"src": "a1", "tar": "a3"}, {"src": "a8", "tar": "a6"}, {"src": "h2", "tar": "h4"}, {"src": "h7", "tar": "h5"}, {"src": "h1", "tar": "h3"}] ret = self.game.get_game_history() self.assertEqual(ret, expected)
def test_get_next_move_returns_correct_value(self): ai = AdvancedAI(ChessGame()) move = ai.get_next_move() self.assertEqual(move, (0, 1, 2, 2)) ai = AdvancedAI(ChessGame()) ai.game.update((0, 1), (2, 2), "Queen", is_ai=True) move = ai.get_next_move() self.assertEqual(move, (6, 0, 5, 0))
def setUp(self) -> None: self.game = ChessGame(fen="start") self.game.half_move_clock = 20 self.game.full_move_clock = 100 self.game.count = 200 for row in range(8): for col in range(8): self.game.board[row][col] = Empty(None, Color.EMPTY, row, col)
def test_get_next_move_returns_correct_value(self): simple_ai = SimpleAI(ChessGame()) move = simple_ai.get_next_move() self.assertEqual(move, (0, 1, 2, 2)) simple_ai = SimpleAI(ChessGame()) simple_ai.game.update((0, 1), (2, 2), "Queen") move = simple_ai.get_next_move() self.assertEqual(move, (6, 2, 5, 2))
def min_max_search(self, game: ChessGame, depth: int, maximize_color: Color, parent_max: int, parent_min: int, first_move: bool): """ Use minmax search with alpha beta prune to calculate the next best move """ board = game.board game_status = game.check_game_status() if not depth or game_status != 'Continue': if (game_status == "BlackLoss" and maximize_color == Color.WHITE) or (game_status == "WhiteLoss" and maximize_color == Color.BLACK): return math.inf ret = self.game_evaluation(maximize_color) return ret else: turn = game.turn if turn == maximize_color: max_score = parent_min for row in range(8): for col in range(8): piece = board[row][col] if piece.color == turn: moves = piece.get_checked_moves()["moves"] src = (row, col) for tar in moves: game.update(src, tar, 'Queen', is_ai=True) child_score = self.min_max_search( game, depth - 1, maximize_color, parent_max, max_score, False) game.undo() if child_score > max_score: if first_move: self.best_move = [src, tar] max_score = child_score if max_score > parent_max: return parent_max return max_score else: min_score = parent_max for row in range(8): for col in range(8): piece = board[row][col] if piece.color == turn: moves = piece.get_checked_moves()["moves"] src = (row, col) for tar in moves: game.update(src, tar, 'Queen', is_ai=True) child_score = self.min_max_search( game, depth - 1, maximize_color, min_score, parent_min, False) game.undo() if child_score < min_score: if first_move: self.best_move = [src, tar] min_score = child_score if min_score < parent_min: return parent_min return min_score
class TestGetTurnNotation(unittest.TestCase): def setUp(self) -> None: self.game = ChessGame(fen="start") def test_get_turn_notation_start(self): self.assertEqual(self.game.get_turn_notation(), "w") def test_get_turn_notation_during_game(self): self.game.turn = Color.BLACK self.assertEqual(self.game.get_turn_notation(), "b") self.game.turn = Color.WHITE self.assertEqual(self.game.get_turn_notation(), "w")
class TestKingCoordinate(unittest.TestCase): def setUp(self) -> None: self.game = ChessGame(fen="start") def test_king_coordinate_start(self): self.assertEqual(self.game.king_coordinate(Color.WHITE), (0, 4)) self.assertEqual(self.game.king_coordinate(Color.BLACK), (7, 4)) def test_king_coordinate(self): self.game.kings_coordinate = [(0, 0), (7, 3)] self.assertEqual(self.game.king_coordinate(Color.WHITE), (0, 0)) self.assertEqual(self.game.king_coordinate(Color.BLACK), (7, 3))
def __init__(self, db_url="init"): """ Set up database using db_url. Connect to the database, fetch data and create dict sessions where key is session_id and value is chess (game instance, username). :param db_url: if db_url is "init", the db_url is 'postgresql+psycopg2://postgres:[email protected]:5432' Otherwise, db_url can be the value of the parameter passed in """ if db_url == "init": db_url = 'postgresql+psycopg2://postgres:[email protected]:5432' self.engine = create_engine(db_url) meta = MetaData() self.current_game = Table( 'game', meta, Column('username', String), Column('session_id', Integer, primary_key=True), Column('fen', String), Column('status', String), Column('mode', String), Column('start_time', DateTime), Column('last_update', DateTime)) self.history = Table('history', meta, Column('session_id', Integer, primary_key=True), Column('step', Integer, primary_key=True), Column('src', String), Column('tar', String), Column('fen', String)) self.users = Table('users', meta, Column('username', String, primary_key=True), Column('password', String), Column('total_hours', Float), Column('score', Integer)) meta.create_all(self.engine) self.sessions = {} self.modes = {} conn = self.engine.connect() sessions_info = conn.execute(self.current_game.select()) for session in sessions_info: session_id = session["session_id"] fen = session["fen"] game = ChessGame(fen) self.sessions[session_id] = (game, session["username"]) self.modes[session_id] = session["mode"] for session_id in self.sessions: session_history = conn.execute(self.history.select().where( self.history.c.session_id == session_id).order_by( self.history.c.step)).all() game = self.sessions[session_id][0] game.init_history(session_history) conn.close()
class TestGetTurn(unittest.TestCase): def setUp(self) -> None: self.game = ChessGame(fen="start") def test_get_turn_start(self): self.assertEqual(self.game.get_turn(), "White") def test_switch_turn_during_game(self): self.game.turn = Color.BLACK self.assertEqual(self.game.get_turn(), "Black") self.game.turn = Color.WHITE self.assertEqual(self.game.get_turn(), "White")
class TestGetCheckedMoves(unittest.TestCase): def setUp(self) -> None: self.game = ChessGame(fen="start") self.game.half_move_clock = 20 self.game.full_move_clock = 100 self.game.count = 200 for row in range(8): for col in range(8): self.game.board[row][col] = Empty(None, Color.EMPTY, row, col) def test_get_checked_moves_checkmate(self): self.game.board[0][0] = King(self.game, Color.WHITE, 0, 0) self.game.board[7][4] = King(self.game, Color.BLACK, 7, 4) self.game.board[1][0] = Pawn(self.game, Color.BLACK, 1, 0) self.game.board[4][5] = Pawn(self.game, Color.WHITE, 4, 5) self.game.board[4][1] = Rook(self.game, Color.WHITE, 4, 1) self.game.board[3][3] = Bishop(self.game, Color.BLACK, 3, 3) self.game.turn = Color.WHITE checked_moves = self.game.get_checked_moves((4, 1)) moves = checked_moves["moves"] for move in moves: self.assertTrue(move in ["b2"]) checked_moves = self.game.get_checked_moves((0, 0)) moves = checked_moves["moves"] for move in moves: self.assertTrue(move in ["a2"]) checked_moves = self.game.get_checked_moves((4, 5)) moves = checked_moves["moves"] for move in moves: self.assertTrue(move in []) def test_get_checked_moves_checkmate2(self): self.game.board[0][3] = King(self.game, Color.WHITE, 0, 3) self.game.board[7][4] = King(self.game, Color.BLACK, 7, 4) self.game.board[1][2] = Pawn(self.game, Color.BLACK, 1, 2) self.game.board[4][1] = Rook(self.game, Color.WHITE, 4, 1) self.game.board[3][4] = Bishop(self.game, Color.BLACK, 3, 4) self.game.turn = Color.WHITE checked_moves = self.game.get_checked_moves((0, 3)) moves = checked_moves["moves"] for move in moves: self.assertTrue(move in ["c1", "d2", "e1", "e2"]) checked_moves = self.game.get_checked_moves((4, 1)) moves = checked_moves["moves"] for move in moves: self.assertTrue(move in [])
def setUp(self) -> None: fen = "8/8/8/8/8/8/8/8 w KQkq - 0 1" self.chess_game = ChessGame(fen=fen) # empty board self.chess_game.board[0][4] = King(self.chess_game, Color.WHITE, 0, 4) self.chess_game.board[0][7] = Rook(self.chess_game, Color.WHITE, 0, 7) self.chess_game.board[0][0] = Rook(self.chess_game, Color.WHITE, 0, 0) self.chess_game.board[7][4] = King(self.chess_game, Color.BLACK, 7, 4) self.chess_game.board[7][0] = Rook(self.chess_game, Color.BLACK, 7, 0)
def setUp(self) -> None: fen = "8/8/8/8/8/8/8/8 w KQkq - 0 1" self.chess_game = ChessGame(fen=fen) # empty board self.chess_game.board[0][0] = Rook(self.chess_game, Color.WHITE, 0, 0) self.chess_game.board[2][3] = Rook(self.chess_game, Color.WHITE, 2, 3) self.chess_game.board[0][3] = King(self.chess_game, Color.WHITE, 0, 3) self.chess_game.board[3][3] = Rook(self.chess_game, Color.BLACK, 3, 3) self.chess_game.kings_coordinate = [(0, 3), (None, None)]
def setUp(self) -> None: fen = "8/8/8/8/8/8/8/8 w KQkq - 0 1" self.chess_game = ChessGame(fen=fen) # empty board self.chess_game.board[4][4] = King(self.chess_game, Color.WHITE, 4, 4) self.chess_game.board[4][1] = King(self.chess_game, Color.BLACK, 4, 1) self.chess_game.kings_coordinate = [(4, 4), (4, 1)] self.chess_game.board[3][3] = Rook(self.chess_game, Color.BLACK, 3, 3) self.chess_game.board[3][2] = Rook(self.chess_game, Color.WHITE, 3, 2)
def test_get_value_returns_correct_value(self): simple_ai = SimpleAI(ChessGame()) self.assertEqual(simple_ai.get_value(simple_ai.game.board), -39) simple_ai.game.board[6][0] = simple_ai.game.empty_cell self.assertEqual(simple_ai.get_value(simple_ai.game.board), -38) simple_ai.game.board[6][0] = Rook(simple_ai.game, Color.BLACK, 6, 0) self.assertEqual(simple_ai.get_value(simple_ai.game.board), -43)
def setUp(self) -> None: fen = "8/8/8/8/8/8/8/8 w KQkq - 0 1" self.chess_game = ChessGame(fen=fen) # empty board self.chess_game.board[0][0] = Bishop(self.chess_game, Color.WHITE, 0, 0) self.chess_game.board[4][4] = Bishop(self.chess_game, Color.BLACK, 4, 4) self.chess_game.board[3][3] = Bishop(self.chess_game, Color.BLACK, 3, 3)
class TestGetHistory(unittest.TestCase): def setUp(self) -> None: self.game = ChessGame(fen="start") def test_get_history_start(self): self.assertEqual(self.game.get_history(), {}) def test_get_history_during_game(self): self.game.history = [{"fen": "rnbqkbnr/pppppppp/8/8/P7/8/1PPPPPPP/RNBQKBNR b KQkq a3 0 1", "movement": {"src": "a2", "tar": "a4"}}, {"fen": "rnbqkbnr/1ppppppp/8/p7/P7/8/1PPPPPPP/RNBQKBNR w KQkq a6 0 2", "movement": {"src": "a7", "tar": "a5"}}, {"fen": "rnbqkbnr/1ppppppp/8/p7/P7/R7/1PPPPPPP/1NBQKBNR b Kkq - 1 2", "movement": {"src": "a1", "tar": "a3"}}, {"fen": "1nbqkbnr/1ppppppp/r7/p7/P7/R7/1PPPPPP1/1NBQKBNR w Kk - 2 3", "movement": {"src": "a8", "tar": "a6"}}] expect = {"src": "a8", "tar": "a6", "fen": "1nbqkbnr/1ppppppp/r7/p7/P7/R7/1PPPPPP1/1NBQKBNR w Kk - 2 3", "step": 4} self.assertEqual(self.game.get_history(), expect)
def setUp(self) -> None: fen = "8/8/8/8/8/8/8/8 w KQkq - 0 1" self.chess_game = ChessGame(fen=fen) # empty board self.chess_game.board[0][0] = Knight(self.chess_game, Color.WHITE, 0, 0) self.chess_game.board[0][2] = Knight(self.chess_game, Color.WHITE, 0, 2) self.chess_game.board[1][0] = Knight(self.chess_game, Color.BLACK, 1, 0) self.chess_game.board[1][2] = Knight(self.chess_game, Color.BLACK, 1, 2)
class TestGetCastlingNotation(unittest.TestCase): def setUp(self) -> None: self.game = ChessGame(fen="start") def test_get_castling_notation_start(self): self.assertEqual(self.game.get_castling_notation(), "KQkq") def test_get_castling_notation_during_game(self): self.game.board[0][4].firstMove = True self.game.board[7][4].firstMove = True self.game.board[0][0].firstMove = True self.game.board[0][7].firstMove = True self.game.board[7][0].firstMove = True self.game.board[7][7].firstMove = True self.assertEqual(self.game.get_castling_notation(), "KQkq") self.game.board[0][0].firstMove = False self.assertEqual(self.game.get_castling_notation(), "Kkq") self.game.board[0][7].firstMove = False self.assertEqual(self.game.get_castling_notation(), "kq") self.game.board[7][0].firstMove = False self.assertEqual(self.game.get_castling_notation(), "k") self.game.board[7][7].firstMove = False self.assertEqual(self.game.get_castling_notation(), "-")
class TestUpdateEnPassant(unittest.TestCase): def setUp(self) -> None: self.game = ChessGame(fen="start") def test_update_implement_en_passant(self): self.game.half_move_clock = 0 self.game.full_move_clock = 10 self.game.count = 20 self.game.empty_cell = Empty(None, Color.EMPTY, -1, -1) self.game.history = [{"fen": "3q4/8/8/8/Pp6/8/8/5K2 b - a3 0 10", "movement": {"src": "a2", "tar": "a4"}}] self.game.castling_notation = "-" self.game.turn = Color.BLACK for row in range(8): for col in range(8): self.game.board[row][col] = self.game.empty_cell self.game.board[7][3] = King(self.game, Color.BLACK, 7, 3) self.game.board[0][5] = King(self.game, Color.WHITE, 0, 5) self.game.board[3][0] = Pawn(self.game, Color.WHITE, 3, 0) self.game.board[3][1] = Pawn(self.game, Color.BLACK, 3, 1) self.game.update_en_passant((3, 1), (2, 0)) self.assertEqual(self.game.board[3][0], self.game.empty_cell)
class TestInitHistory(unittest.TestCase): def setUp(self) -> None: self.game = ChessGame(fen="start") def test_init_history_restores_expected_history(self): history = [["", 1, "a2", "a4", "rnbqkbnr/pppppppp/8/8/P7/8/1PPPPPPP/RNBQKBNR b KQkq a3 0 1"], ["", 2, "a7", "a5", "rnbqkbnr/1ppppppp/8/p7/P7/8/1PPPPPPP/RNBQKBNR w KQkq a6 0 2"], ["", 3, "a1", "a3", "rnbqkbnr/1ppppppp/8/p7/P7/R7/1PPPPPPP/1NBQKBNR b Kkq - 1 2"], ["", 4, "a8", "a6", "1nbqkbnr/1ppppppp/r7/p7/P7/R7/1PPPPPPP/1NBQKBNR w Kk - 2 3"], ["", 5, "h2", "h4", "1nbqkbnr/1ppppppp/r7/p7/P6P/R7/1PPPPPP1/1NBQKBNR b Kk h3 0 3"], ["", 6, "h7", "h5", "1nbqkbnr/1pppppp1/r7/p6p/P6P/R7/1PPPPPP1/1NBQKBNR w Kk h6 0 4"], ["", 7, "h1", "h3", "1nbqkbnr/1pppppp1/r7/p6p/P6P/R6R/1PPPPPP1/1NBQKBN1 b k - 1 4"]] self.game.init_history(history) expected = [{"fen": "rnbqkbnr/pppppppp/8/8/P7/8/1PPPPPPP/RNBQKBNR b KQkq a3 0 1", "movement": {"src": "a2", "tar": "a4"}}, {"fen": "rnbqkbnr/1ppppppp/8/p7/P7/8/1PPPPPPP/RNBQKBNR w KQkq a6 0 2", "movement": {"src": "a7", "tar": "a5"}}, {"fen": "rnbqkbnr/1ppppppp/8/p7/P7/R7/1PPPPPPP/1NBQKBNR b Kkq - 1 2", "movement": {"src": "a1", "tar": "a3"}}, {"fen": "1nbqkbnr/1ppppppp/r7/p7/P7/R7/1PPPPPPP/1NBQKBNR w Kk - 2 3", "movement": {"src": "a8", "tar": "a6"}}, {"fen": "1nbqkbnr/1ppppppp/r7/p7/P6P/R7/1PPPPPP1/1NBQKBNR b Kk h3 0 3", "movement": {"src": "h2", "tar": "h4"}}, {"fen": "1nbqkbnr/1pppppp1/r7/p6p/P6P/R7/1PPPPPP1/1NBQKBNR w Kk h6 0 4", "movement": {"src": "h7", "tar": "h5"}}, {"fen": "1nbqkbnr/1pppppp1/r7/p6p/P6P/R6R/1PPPPPP1/1NBQKBN1 b k - 1 4", "movement": {"src": "h1", "tar": "h3"}}] self.assertEqual(self.game.history[0], expected[0]) self.assertEqual(self.game.history[1], expected[1]) self.assertEqual(self.game.history[2], expected[2]) self.assertEqual(self.game.history[3], expected[3]) self.assertEqual(self.game.history[4], expected[4]) self.assertEqual(self.game.history[5], expected[5]) self.assertEqual(self.game.history[6], expected[6]) self.assertEqual(len(history), 7) self.assertEqual(len(self.game.history), 7)
def test_load_fen_restores_correct_moves_and_clock(self): game = ChessGame() game.load_fen("8/8/8/8/8/8/8/8 w KQkq - 0 1") self.assertEqual(game.half_move_clock, 0) self.assertEqual(game.full_move_clock, 1) self.assertEqual(game.count, 0) game.load_fen("8/8/8/8/8/8/8/8 b KQkq - 10 15") self.assertEqual(game.half_move_clock, 10) self.assertEqual(game.full_move_clock, 15) self.assertEqual(game.count, 29) game.load_fen("8/8/8/8/8/8/8/8 w - - 20 14") self.assertEqual(game.half_move_clock, 20) self.assertEqual(game.full_move_clock, 14) self.assertEqual(game.count, 26)
def test_load_fen_gives_correct_board(self): game = ChessGame() game.load_fen("8/8/8/8/8/8/8/8 w KQkq - 0 1") for row in range(8): for col in range(8): self.assertEqual(type(game.board[row][col]), Empty) game.load_fen("8/8/1r1R4/8/8/8/8/8 w KQkq - 0 1") self.assertEqual(type(game.board[5][1]), Rook) self.assertEqual(game.board[5][1].color, Color.BLACK) self.assertEqual(type(game.board[5][3]), Rook) self.assertEqual(game.board[5][3].color, Color.WHITE) game.load_fen("8/8/8/8/8/8/8/k7 w KQkq - 0 1") self.assertEqual(type(game.board[0][0]), King) self.assertEqual(game.board[0][0].color, Color.BLACK)
class TestIsBeingCheckedAfterMove(unittest.TestCase): def setUp(self) -> None: self.game = ChessGame(fen="start") def test_is_being_checked_after_move_start(self): self.assertFalse(self.game.is_being_checked_after_move((1, 4), (3, 4))) def test_is_being_checked_after_move_in_few_moves(self): self.assertFalse(self.game.is_being_checked_after_move((6, 2), (4, 2))) self.assertFalse(self.game.is_being_checked_after_move((0, 6), (2, 5))) self.assertFalse(self.game.is_being_checked_after_move((0, 6), (2, 5))) self.assertFalse(self.game.is_being_checked_after_move((6, 0), (4, 0))) self.assertFalse(self.game.is_being_checked_after_move((0, 7), (0, 6))) self.assertFalse(self.game.is_being_checked_after_move((7, 0), (6, 0))) self.assertFalse(self.game.is_being_checked_after_move((1, 0), (3, 0))) self.assertFalse(self.game.is_being_checked_after_move((6, 7), (4, 7))) self.assertFalse(self.game.is_being_checked_after_move((0, 0), (1, 0))) self.assertFalse(self.game.is_being_checked_after_move((7, 7), (6, 7))) def test_is_being_checked_after_move_during_game_true(self): empty = Empty(None, Color.EMPTY, -1, -1) for row in range(8): for col in range(8): self.game.board[row][col] = empty self.game.board[0][0] = King(self.game, Color.WHITE, 0, 0) self.game.board[7][3] = King(self.game, Color.BLACK, 7, 3) self.game.kings_coordinate = [(0, 0), (7, 3)] self.game.board[1][0] = Pawn(self.game, Color.BLACK, 1, 0) self.game.board[4][5] = Pawn(self.game, Color.WHITE, 4, 5) self.game.board[4][1] = Rook(self.game, Color.WHITE, 4, 1) self.game.board[4][2] = Bishop(self.game, Color.BLACK, 4, 2) self.assertTrue(self.game.is_being_checked_after_move((4, 2), (3, 3))) def test_is_being_checked_after_move_during_game_false(self): empty = Empty(None, Color.EMPTY, -1, -1) for row in range(8): for col in range(8): self.game.board[row][col] = empty self.game.board[0][4] = King(self.game, Color.WHITE, 0, 4) self.game.board[7][3] = King(self.game, Color.BLACK, 7, 3) self.game.kings_coordinate = [(0, 4), (7, 3)] self.game.board[1][0] = Pawn(self.game, Color.BLACK, 1, 0) self.game.board[4][5] = Pawn(self.game, Color.WHITE, 4, 5) self.game.board[4][1] = Rook(self.game, Color.WHITE, 4, 1) self.game.board[4][2] = Bishop(self.game, Color.BLACK, 4, 2) self.assertFalse(self.game.is_being_checked_after_move((4, 2), (2, 4)))
def test_get_checked_moves_include_castling(self): fen = "8/8/8/8/8/8/8/8 w KQkq - 0 1" chess_game2 = ChessGame(fen=fen) chess_game2.board[0][4] = King(chess_game2, Color.WHITE, 0, 4) chess_game2.board[7][4] = King(chess_game2, Color.BLACK, 7, 4) chess_game2.board[0][7] = Rook(chess_game2, Color.WHITE, 0, 7) chess_game2.board[0][0] = Rook(chess_game2, Color.WHITE, 0, 0) actual = chess_game2.board[0][4].get_checked_moves() expected = { 'moves': [(1, 4), (1, 5), (0, 5), (0, 3), (1, 3), (0, 6), (0, 2)] } self.assertEqual(actual, expected)
class TestUndo(unittest.TestCase): def setUp(self) -> None: self.game = ChessGame(fen="start") def test_undo_init(self): self.game.undo() self.assertEqual(self.game.turn, Color.WHITE) self.assertEqual(self.game.history, []) def test_undo_first_step(self): self.game.history = [{"fen": "rnbqkbnr/pppppppp/8/8/P7/8/1PPPPPPP/RNBQKBNR b KQkq a3 0 1", "movement": {"src": "a2", "tar": "a4"}}] self.game.turn = Color.BLACK self.game.undo() self.assertEqual(self.game.turn, Color.WHITE) self.assertEqual(self.game.history, []) def test_undo(self): self.game.history = [{"fen": "rnbqkbnr/pppppppp/8/8/P7/8/1PPPPPPP/RNBQKBNR b KQkq a3 0 1", "movement": {"src": "a2", "tar": "a4"}}, {"fen": "rnbqkbnr/1ppppppp/8/p7/P7/8/1PPPPPPP/RNBQKBNR w KQkq a6 0 2", "movement": {"src": "a7", "tar": "a5"}}, {"fen": "rnbqkbnr/1ppppppp/8/p7/P7/R7/1PPPPPPP/1NBQKBNR b Kkq - 1 2", "movement": {"src": "a1", "tar": "a3"}}, {"fen": "1nbqkbnr/1ppppppp/r7/p7/P7/R7/1PPPPPP1/1NBQKBNR w Kk - 2 3", "movement": {"src": "a8", "tar": "a6"}}] self.game.undo() color = Color.BLACK self.assertEqual(self.game.turn, color) self.assertEqual(self.game.castling_notation, "Kkq") self.assertEqual(self.game.en_passant_target_notation, "-") self.assertEqual(self.game.half_move_clock, 1) self.assertEqual(self.game.full_move_clock, 2) self.assertEqual(self.game.board[0][0], self.game.empty_cell) self.assertEqual(type(self.game.board[0][1]), Knight) self.assertEqual(self.game.board[0][1].color, Color.WHITE) self.assertEqual(type(self.game.board[0][2]), Bishop) self.assertEqual(type(self.game.board[0][3]), Queen) self.assertEqual(type(self.game.board[0][4]), King) self.assertEqual(type(self.game.board[0][5]), Bishop) self.assertEqual(type(self.game.board[0][6]), Knight) self.assertEqual(type(self.game.board[0][7]), Rook) self.assertEqual(type(self.game.board[7][0]), Rook) self.assertEqual(type(self.game.board[7][1]), Knight) self.assertEqual(self.game.board[7][1].color, Color.BLACK) self.assertEqual(type(self.game.board[7][2]), Bishop) self.assertEqual(type(self.game.board[7][3]), Queen) self.assertEqual(type(self.game.board[7][4]), King) self.assertEqual(type(self.game.board[7][5]), Bishop) self.assertEqual(type(self.game.board[7][6]), Knight) self.assertEqual(type(self.game.board[7][7]), Rook)
class TestUpdatePromotion(unittest.TestCase): def setUp(self) -> None: self.game = ChessGame(fen="start") def test_update_implement_promotion(self): self.game.half_move_clock = 0 self.game.full_move_clock = 10 self.game.count = 20 self.game.empty_cell = Empty(None, Color.EMPTY, -1, -1) self.game.history = [{"fen": "3bk3/PP6/8/8/8/8/6pp/4KB2 w - - 0 10", "movement": {"src": "a6", "tar": "a7"}}] self.game.turn = Color.WHITE for row in range(8): for col in range(8): self.game.board[row][col] = self.game.empty_cell self.game.board[7][4] = King(self.game, Color.BLACK, 7, 4) self.game.board[7][3] = Bishop(self.game, Color.BLACK, 7, 3) self.game.board[7][4].firstMove = True self.game.board[0][4] = King(self.game, Color.WHITE, 0, 4) self.game.board[0][5] = Rook(self.game, Color.WHITE, 0, 5) self.game.board[0][4].firstMove = True self.game.board[6][0] = Pawn(self.game, Color.WHITE, 6, 0) self.game.board[1][7] = Pawn(self.game, Color.BLACK, 1, 7) self.game.board[6][1] = Pawn(self.game, Color.WHITE, 6, 1) self.game.board[1][6] = Pawn(self.game, Color.BLACK, 1, 6) self.game.update_promotion((6, 0), (7, 0), "Queen") self.assertEqual(type(self.game.board[7][0]), Queen) self.assertEqual(self.game.board[7][0].color, Color.WHITE) self.game.update_promotion((1, 7), (0, 7), "Rook") self.assertEqual(type(self.game.board[0][7]), Rook) self.assertEqual(self.game.board[0][7].color, Color.BLACK) self.game.update_promotion((6, 1), (7, 1), "Bishop") self.assertEqual(type(self.game.board[7][1]), Bishop) self.assertEqual(self.game.board[7][0].color, Color.WHITE) self.game.update_promotion((1, 6), (0, 6), "Knight") self.assertEqual(type(self.game.board[0][6]), Knight) self.assertEqual(self.game.board[0][6].color, Color.BLACK)