def test_minimax_evaluates_correct_side(minimax_engines): """ Tests that minimax evaluate function returns best move for own side i.e doesn't return best move for black when playing as white""" white_minimax, black_minimax = minimax_engines # White should capture blacks queen and vice-versa board = chess.Board(fen=load_fen("capture_black_queen_2")) assert str(white_minimax.move(board)) == "f4c4" board = chess.Board(fen=load_fen("capture_white_queen_2")) assert str(black_minimax.move(board)) == "c4f4"
def modified_boards() -> List[tuple]: """ Sets up boards with modified FENs for testing. Includes move that should be taken Returns: {List[tuple]} """ return [ (chess.Board(fen=load_fen("capture_black_knight")), "f3d4"), (chess.Board(fen=load_fen("capture_black_queen")), "e4d5"), (chess.Board(fen=load_fen("capture_rook_or_knight")), "d4h8"), ]
def test_minimax_no_pruning_captures_obvious_pieces(minimax_engines): """ Test that without alpha beta pruning, minimax still evaluates obvious positions """ white_minimax, black_minimax = minimax_engines white_minimax.alpha_beta_pruning = False black_minimax.alpha_beta_pruning = False # White should capture blacks queen and vice-versa board = chess.Board(fen=load_fen("capture_black_queen_2")) assert str(white_minimax.move(board)) == "f4c4" board = chess.Board(fen=load_fen("capture_white_queen_2")) assert str(black_minimax.move(board)) == "c4f4"
def test_scholars_mate_resigns_when_sequence_interrupted(): """ Tests that ScholarsMate resigns when any move is blocked """ engine = ScholarsMate() # In both board states, white is interrupted from completed sequence interrupted_fen_sequences = [ load_fen("blocked_queen_fen"), load_fen("captured_queen_fen"), ] for interrupted_fen in interrupted_fen_sequences: board = chess.Board(fen=interrupted_fen) assert engine.move(board) == chess.Move.null()
def stalemate_boards(): """ Sets up boards that ended due to stalemate Returns: List[chess.Board] """ return [chess.Board(fen=load_fen("stalemate_fen"))]
def not_mated_boards(): """ Sets up boards that ended due to resignation Returns: List[chess.Board] """ return [chess.Board(fen=f) for f in load_fen("not_mated_fens")]
def in_progress_board(): """ Set ups board of an in progress game Returns: (chess.Board) """ board = chess.Board(fen=load_fen("in_progress_fen")) return board
def test_minimax_depth_2_evaluation_captures(minimax_engines): """ Tests that minimax at depth 2 sees moves 2 steps ahead i.e obvious forks """ fork_boards = [(chess.Board(fen=load_fen("black_knight_fork_fen")), "d4c2") ] engine = minimax_engines[1] engine.alpha_beta_pruning = False for board, rec_move in fork_boards: move = engine.move(board) assert str(move) == rec_move
def test_mvv_lva_fischer_returns_sorted_captures(): """ Tests that MVV_LVA with Fischer piece values (where bishop is ranked higher than knight returns captures with bishops prioritized over knights """ board = chess.Board(fen=load_fen("white_capture_bishop_or_knight")) pawn_capture_bishop = chess.Move.from_uci("c3d4") pawn_capture_knight = chess.Move.from_uci("f3e4") # Since Fischer values rank bishop over knight, should prioritize bishop captures_sorted = [pawn_capture_bishop, pawn_capture_knight] assert MVV_LVA(board, FischerPieceValues) == captures_sorted
def test_get_engine_evaluation_runs_with_fen_input(): """ Tests that get_engine_evaluations will evaluate given FEN as input """ eval_ = get_engine_evaluations( load_fen("starting_fen"), Random(), AvoidCapture(), MiniMax(color=chess.WHITE, depth=1), ) # Check that each engine evaluated assert set(["Random", "Avoid Capture", "MiniMax"]) == set(eval_.keys()) # Check that evaluations from each engine are legal chess moves assert all(len(v) == 4 for v in eval_.values())
def test_prioritize_pieces_chooses_correct_move(): """ Tests that PrioritizePieceMoves chooses the correct move for different pieces """ board = chess.Board(fen=load_fen("anyone_captures_queen")) piece_to_move_map = { "p": "h4g5", "B": "c1g5", "n": "f3g5", "R": "g3g5", "q": "e5g5" } for piece, rec_move in piece_to_move_map.items(): engine = PrioritizePieceMoves(piece=piece) move = engine.move(board) assert str(move) == rec_move
def test_mvv_lva_conventional_returns_sorted_captures(): """ Tests that MVV_LVA with conventional piece values returns all captures sorted by highest value difference """ board = chess.Board(fen=load_fen("white_aggressor")) # All available captures in fen position sorted pawn_capture_queen = chess.Move.from_uci("b4c5") knight_capture_queen = chess.Move.from_uci("d3c5") pawn_capture_knight = chess.Move.from_uci("g3f4") pawn_capture_bishop = chess.Move.from_uci("f3e4") knight_capture_knight = chess.Move.from_uci("d3f4") captures_sorted = [ pawn_capture_queen, knight_capture_queen, pawn_capture_knight, pawn_capture_bishop, knight_capture_knight, ] assert MVV_LVA(board, ConventionalPieceValues) == captures_sorted
def test_engineplay_board_setter_with_valid_fen_no_errors(setup_engineplay): """ Tests that setting a valid FEN string to EnginePlay raises no errors """ setup_engineplay.board = load_fen("in_progress_fen")
def test_evaluate_ending_for_white_win_position(): """ Tests that boards correspond to mate are correctly evaluated """ white_to_mate = chess.Board(fen=load_fen("white_to_mate")) white_to_mate.push_uci("d3e4") assert evaluate_ending_board(white_to_mate) == "White win by mate"