def test_red_jump_left(self): # default turn is BLACK so we change it to RED first self.b.turn = Color.RED # Set a black piece to a jumpable position self.b.set_piece_at(Tile(3, 4), Piece(Color.BLACK)) self.assertMoveType(MoveType.JUMP, self.b.move_piece(Tile(2, 5), Tile(4, 3))) self.assertIsNone(self.b.get_piece_at(Tile(3, 4)))
def test_undo_normal_move(self): move = Move([Tile(5, 2), Tile(4, 3)]) must_jump = self.b.must_jump jumped_pieces, was_king = self.ai.do_move(move, self.b) self.ai.undo_move(move, jumped_pieces, must_jump, was_king, self.b) self.assertIsNone(self.b.get_piece_at(Tile(4, 3))) self.assertIsNotNone(self.b.get_piece_at(Tile(5, 2)))
def test_deep_copy_board(self): nb = copy.deepcopy(self.b) piece = self.b.get_piece_at(Tile(2, 1)) piece.king() self.assertEqual(False, nb.get_piece_at(Tile(2, 1)).is_king) self.b.move_piece(Tile(2, 1), Tile(3, 0)) self.assertEqual(None, nb.get_piece_at(Tile(3, 0)))
def test_win_condition(self): self.b = Board(True) self.b.set_piece_at(Tile(4, 1), Piece(Color.RED)) self.b.set_piece_at(Tile(5, 2), Piece(Color.BLACK)) self.b.red_checkers = 1 self.b.black_checkers = 1 self.b.move_piece(Tile(5, 2), Tile(3, 0)) self.assertEqual(Color.BLACK, self.b.winner())
def test_king_jump_back_right(self): # default turn is BLACK so we change it to RED first self.b.turn = Color.RED # Set up the red king piece = Piece(Color.RED) self.b.set_piece_at(Tile(6, 1), piece) piece.king() # King jumping back is a valid JUMP move self.assertMoveType(MoveType.JUMP, self.b.move_piece(Tile(6, 1), Tile(4, 3))) # Piece the king jumped is removed self.assertIsNone(self.b.get_piece_at(Tile(5, 2)))
def test_king_normal_moves(self): # default turn is BLACK so we change it to RED first self.b.turn = Color.RED piece = Piece(Color.RED) self.b.set_piece_at(Tile(4, 3), piece) piece.king() # red king moves backwards self.assertMoveType(MoveType.NORMAL, self.b.move_piece(Tile(4, 3), Tile(3, 4))) # RED shouldn't be able to move 2 turns in a row so we set to RED self.b.turn = Color.RED # red king moves forwards self.assertMoveType(MoveType.NORMAL, self.b.move_piece(Tile(3, 4), Tile(4, 3)))
def test_undo_jump_move(self): self.test_get_available_moves_with_jump() move = Move([Tile(3, 0), Tile(5, 2)]) must_jump = self.b.must_jump jumped_pieces, was_king = self.ai.do_move(move, self.b) jumped_piece = jumped_pieces[0] self.ai.undo_move(move, jumped_pieces, must_jump, was_king, self.b) self.assertIsNone(self.b.get_piece_at(Tile(5, 2))) red_piece = self.b.get_piece_at(Tile(3, 0)) self.assertIsNotNone(red_piece) black_piece = self.b.get_piece_at(Tile(4, 1)) self.assertIsNotNone(black_piece) self.assertEqual(jumped_piece, black_piece) self.assertEqual(Color.BLACK, black_piece.color)
def test_undo_double_jump(self): piece = Piece(Color.RED) piece.king() self.b.set_piece_at(Tile(4, 3), piece) self.b.set_piece_at(Tile(1, 0), None) move = Move([Tile(5, 4), Tile(3, 2), Tile(1, 0)]) must_jump = self.b.must_jump jumped_pieces, was_king = self.ai.do_move(move, self.b) self.ai.undo_move(move, jumped_pieces, must_jump, was_king, self.b) self.assertEqual(Color.RED, self.b.get_piece_at(Tile(2, 1)).color) # piece was added to array of jumped pieces by do_move and readded to the board by undo_move self.assertEqual(piece, self.b.get_piece_at(Tile(4, 3))) self.assertEqual(Color.BLACK, self.b.get_piece_at(Tile(5, 4)).color) self.assertIsNone(self.b.get_piece_at(Tile(1, 0))) self.assertIsNone(self.b.get_piece_at(Tile(3, 2)))
def get_available_moves(self, board) -> List[Move]: moves = [] for row in range(8): for col in range(8): if (col + row) % 2 == 1: moves += self.get_moves(Tile(row, col), board) return moves
def handle_click(self): (x, y) = pygame.mouse.get_pos() row = int((y - y % 100) / 100) column = int((x - x % 100) / 100) clicked_tile = Tile(row, column) piece = self.board.get_piece_at(clicked_tile) if self.selected_tile is None: if piece is None: return elif piece.color != self.board.turn: return elif self.board.must_jump and not self.board.can_jump(clicked_tile): return self.selected_tile = clicked_tile else: move_type = self.board.move_piece(self.selected_tile, clicked_tile) if move_type == MoveType.JUMP and self.board.can_jump(clicked_tile): self.selected_tile = clicked_tile else: self.selected_tile = None if self.board.turn == Color.RED and self.num_AIs == 1: self.draw_board() pygame.display.flip() self.red_ai.next_move()
def get_moves(self, start: Tile, board, only_jumps=False, previous_moves=None, counter=0) -> List[Move]: if previous_moves is None: previous_moves = [] moves = [] tiles_to_check = list(start.get_valid_diagonal_tiles(2)) if not only_jumps: tiles_to_check += list(start.get_valid_diagonal_tiles(1)) for end in tiles_to_check: current_move = Move([start, end]) redid_move = False for move in previous_moves: if current_move == move.inverse() or current_move == move: redid_move = True break if redid_move: continue move_type = board.classify_move(start, end) if move_type == MoveType.INVALID: continue if move_type == MoveType.NORMAL: moves.append(current_move) if move_type == MoveType.JUMP: piece = board.get_piece_at(start) was_king = piece.is_king if end.is_end_row(): piece.king() board.set_piece_at(start, None) board.set_piece_at(end, piece) previous_moves.append(current_move) extra_jumps = self.get_moves(end, board, only_jumps=True, previous_moves=previous_moves, counter=counter + 1) piece.king() if was_king else piece.unking() board.set_piece_at(start, piece) board.set_piece_at(end, None) if extra_jumps: moves += [Move([start] + m.path) for m in extra_jumps] else: moves.append(Move([start, end])) return moves
def test_triple_jump(self): self.b = Board(True) self.b.turn = Color.RED self.b.red_checkers = 1 self.b.black_checkers = 3 self.b.set_piece_at(Tile(0, 0), Piece(Color.RED)) self.b.set_piece_at(Tile(1, 1), Piece(Color.BLACK)) self.b.set_piece_at(Tile(3, 3), Piece(Color.BLACK)) self.b.set_piece_at(Tile(5, 5), Piece(Color.BLACK)) print(self.b) self.assertMoveType(MoveType.JUMP, self.b.move_piece(Tile(0, 0), Tile(2, 2))) print(self.b) self.assertMoveType(MoveType.JUMP, self.b.move_piece(Tile(2, 2), Tile(4, 4))) print(self.b) self.assertMoveType(MoveType.JUMP, self.b.move_piece(Tile(4, 4), Tile(6, 6))) print(self.b) self.assertEqual(self.b.turn, Color.BLACK)
def test_double_jump(self): self.b.set_piece_at(Tile(4, 3), Piece(Color.RED)) self.b.set_piece_at(Tile(1, 0), None) self.assertMoveType(MoveType.JUMP, self.b.move_piece(Tile(5, 4), Tile(3, 2))) # testing that pieces other than target_tile cannot move during a double jump self.assertMoveType(MoveType.INVALID, self.b.move_piece(Tile(5, 0), Tile(4, 1))) self.assertEqual(self.b.turn, Color.BLACK) self.assertMoveType(MoveType.JUMP, self.b.move_piece(Tile(3, 2), Tile(1, 0))) self.assertIsNone(self.b.target_tile) self.assertEqual(self.b.turn, Color.RED)
def test_same_color_jump_invalid(self): # default turn is BLACK so we change it to RED first self.b.turn = Color.RED # Red jumping red is INVALID and does not remove other red piece self.assertMoveType(MoveType.INVALID, self.b.move_piece(Tile(1, 2), Tile(3, 4))) self.assertIsNotNone(self.b.get_piece_at(Tile(2, 3))) # INVALID RED move should not change turn so we change it manually to BLACK self.b.turn = Color.BLACK # Black jumping black is INVALID and does not remove other black piece self.assertMoveType(MoveType.INVALID, self.b.move_piece(Tile(6, 1), Tile(4, 3))) self.assertIsNotNone(self.b.get_piece_at(Tile(5, 2)))
def test_has_jump_after_normal_with_jump(self): self.test_has_jump_after_normal_with_no_jump() self.assertMoveType(MoveType.NORMAL, self.b.move_piece(Tile(5, 4), Tile(4, 3))) self.assertTrue(self.b.must_jump)
def test_tile_addition(self): self.assertEqual(Tile(3, 4), Tile(1, 3) + Tile(2, 1)) self.assertEqual(Tile(1, 1), Tile(4, 2) + Tile(-3, -1))
def test_find_double_jump(self): self.b.move_piece(Tile(5, 0), Tile(4, 1)) self.b.move_piece(Tile(2, 7), Tile(3, 6)) self.b.move_piece(Tile(6, 1), Tile(5, 0)) self.b.move_piece(Tile(1, 6), Tile(2, 7)) self.b.move_piece(Tile(4, 1), Tile(3, 2)) print(self.b) moves = self.ai.get_available_moves(self.b) print(", ".join([str(m) for m in moves])) self.assertEqual([Move([Tile(2, 1), Tile(4, 3), Tile(6, 1)]), Move([Tile(2, 3), Tile(4, 1)])], moves)
def test_can_jump(self): self.b.set_piece_at(Tile(4, 3), Piece(Color.RED)) self.assertEqual(True, self.b.can_jump(Tile(5, 4)))
def test_promotion(self): self.b = Board(True) self.b.set_piece_at(Tile(1, 0), Piece(Color.BLACK)) self.b.move_piece(Tile(1, 0), Tile(0, 1)) self.assertEqual(True, self.b.get_piece_at(Tile(0, 1)).is_king)
def test_wrong_player(self): self.assertMoveType(MoveType.INVALID, self.b.move_piece(Tile(2, 1), Tile(3, 2))) self.assertIsNone(self.b.get_piece_at(Tile(3, 2))) self.assertIsNotNone(self.b.get_piece_at(Tile(2, 1))) self.assertEqual(Color.BLACK, self.b.turn)
def test_normal_moves(self): # default turn is BLACK so we change it to RED first self.b.turn = Color.RED # Alternating forward moves self.assertMoveType(MoveType.NORMAL, self.b.move_piece(Tile(2, 1), Tile(3, 2))) self.assertMoveType(MoveType.NORMAL, self.b.move_piece(Tile(5, 6), Tile(4, 7))) self.assertMoveType(MoveType.NORMAL, self.b.move_piece(Tile(2, 7), Tile(3, 6))) self.assertMoveType(MoveType.NORMAL, self.b.move_piece(Tile(5, 2), Tile(4, 1))) # Red moving back: INVALID self.assertMoveType(MoveType.INVALID, self.b.move_piece(Tile(3, 2), Tile(2, 1))) # INVALID RED move should not change turn so we change it manually to BLACK self.b.turn = Color.BLACK # Black moving back: INVALID self.assertMoveType(MoveType.INVALID, self.b.move_piece(Tile(4, 1), Tile(5, 0)))
def test_cannot_move_piece_if_has_jump(self): self.test_has_jump_after_normal_with_jump() self.assertMoveType(MoveType.INVALID, self.b.move_piece(Tile(2, 7), Tile(3, 6)))
def test_has_jump_after_jump(self): self.test_has_jump_after_normal_with_jump() self.assertMoveType(MoveType.JUMP, self.b.move_piece(Tile(3, 2), Tile(5, 4))) self.assertTrue(self.b.must_jump)
def test_get_available_moves_with_no_jumps(self): self.b.turn = Color.RED self.assertEqual([Move([Tile(2, 1), Tile(3, 0)]), Move([Tile(2, 1), Tile(3, 2)]), Move([Tile(2, 3), Tile(3, 2)]), Move([Tile(2, 3), Tile(3, 4)]), Move([Tile(2, 5), Tile(3, 4)]), Move([Tile(2, 5), Tile(3, 6)]), Move([Tile(2, 7), Tile(3, 6)])], self.ai.get_available_moves(self.b))
def test_get_available_moves_with_jump(self): self.b.move_piece(Tile(5, 0), Tile(4, 1)) self.b.move_piece(Tile(2, 1), Tile(3, 0)) self.b.move_piece(Tile(5, 2), Tile(4, 3)) print(self.b) print(", ".join([str(m) for m in self.ai.get_available_moves(self.b)]))
def test_normal_move_after_jump_good(self): self.test_double_jump() self.assertMoveType(MoveType.NORMAL, self.b.move_piece(Tile(2, 7), Tile(3, 6)))
def test_black_jump_left(self): # Set a red piece to a jumpable position self.b.set_piece_at(Tile(4, 3), Piece(Color.RED)) self.assertMoveType(MoveType.JUMP, self.b.move_piece(Tile(5, 4), Tile(3, 2))) self.assertIsNone(self.b.get_piece_at(Tile(4, 3)))
def test_cannot_move_wrong_piece_after_jump(self): self.b.set_piece_at(Tile(4, 3), Piece(Color.RED)) self.b.set_piece_at(Tile(1, 0), None) self.assertMoveType(MoveType.JUMP, self.b.move_piece(Tile(5, 4), Tile(3, 2))) self.assertEqual(self.b.turn, Color.BLACK) self.assertMoveType(MoveType.INVALID, self.b.move_piece(Tile(5, 0), Tile(4, 1)))
def test_turns_alternate(self): self.assertMoveType(MoveType.NORMAL, self.b.move_piece(Tile(5, 0), Tile(4, 1))) self.assertMoveType(MoveType.NORMAL, self.b.move_piece(Tile(2, 1), Tile(3, 2)))
def test_has_jump_after_normal_with_no_jump(self): self.b.turn = Color.RED self.assertMoveType(MoveType.NORMAL, self.b.move_piece(Tile(2, 1), Tile(3, 2))) self.assertFalse(self.b.must_jump)