Beispiel #1
0
def main():
    run = True
    clock = pygame.time.Clock()
    board = Board()
    active_click = 0

    while run:
        clock.tick(FPS)

        for event in pygame.event.get():
            #For exiting the game
            if event.type == pygame.QUIT:
                run = False

            #For clicking on screen
            if event.type == pygame.MOUSEBUTTONDOWN:
                if active_click == 1:
                    pos = pygame.mouse.get_pos()
                    row, col = return_row_col_of_mouse(pos)
                    board.move_piece(piece, row, col)
                    active_click = 0
                else:
                    pos = pygame.mouse.get_pos()
                    row, col = return_row_col_of_mouse(pos)
                    piece = board.return_piece(row, col)
                    if piece != 0:
                        active_click = 1

        board.draw(WIN)
        pygame.display.update()

    pygame.quit()
Beispiel #2
0
class Game:
    def __init__(self, win):
        self.win = win
        self.color_value = {(255, 255, 255): "White", (0, 0, 0): "Black"}
        self._init()

    def _init(self):
        self.selected = None
        self.board = Board()
        self.turn = WHITE
        self.valid_moves = []
        self.check_mate = False
        self.move_x, self.move_y = 805, 40
        self.__draw_static_text()

    def __draw_static_text(self):
        self.win.fill(BLACK)
        display_text(self.win, SMALL_FONT, 'WHITE | BLACK | WHITE | BLACK',
                     800, 20, (255, 255, 255))

    def update(self):
        self.board.draw(self.win)
        if self.selected:
            self.draw_valid_moves(self.valid_moves)
        if self.check_mate:
            display_text(
                self.win, LARGE_FONT,
                f"Check Mate!! {self.color_value.get(self.turn)} Wins!!", 250,
                350, (255, 0, 0))
            display_text(self.win, LARGE_FONT, "Press R to restart", 300, 450,
                         (255, 0, 0))
        pygame.display.update()

    def __display_moves(self, move):
        if self.turn == WHITE:
            display_text(self.win, SMALL_FONT, move, self.move_x, self.move_y,
                         (255, 255, 255))
        else:
            display_text(self.win, SMALL_FONT, move, self.move_x + 50,
                         self.move_y, (255, 255, 255))
            self.move_y += 20

        if self.move_y > 780:
            self.move_x = 905

    def reset(self):
        self._init()

    def __get_opposing_color(self, color):
        return BLACK if color == WHITE else WHITE

    def select(self, coordinate):
        """
        Takes in a coordinate, if a piece is selected it will make the move on a temporary board to ensure it is valid.
        Otherwise a piece will be selected and its valid moves will be calculated
        :param coordinate: integer representing the selected board coordinate
        :return: boolean representing whether or not a piece has been selected
        """
        if self.selected:
            destination_coordinate = coordinate
            temp_board = self.simulate_move(self.selected,
                                            destination_coordinate,
                                            self.board.get_board().copy())
            if self.is_in_check(temp_board,
                                self.__get_opposing_color(self.turn)):
                self.selected = None
                self.select(coordinate)

            result = self.__move(coordinate)
            if not result:
                self.selected = None
                self.select(coordinate)
            else:
                self.update()
        else:
            piece = self.board.get_piece(coordinate)
            if piece != 0 and piece.color == self.turn:
                self.selected = piece
                self.valid_moves = piece.calculate_legal_moves(
                    self.board.get_board())
                return True

        return False

    def get_king_position(self, current_board, color):
        for i in range(len(current_board)):
            if str(current_board[i]
                   ) == 'King' and current_board[i].color == color:
                return i
        return -1  # Should not happen

    def is_in_check(self, current_board, color):
        temp_king_pos = self.get_king_position(
            current_board, self.__get_opposing_color(color))
        enemy_pieces = self.board.get_player_pieces(color, current_board)
        current_enemy_moves = self.board.get_player_moves(
            enemy_pieces, current_board)

        return temp_king_pos in current_enemy_moves

    def is_check_mate(self, current_board, color):
        player_pieces = self.board.get_player_pieces(color, current_board)
        for piece in player_pieces:
            current_player_moves = piece.calculate_legal_moves(current_board)
            for move in current_player_moves:
                updated_board = self.simulate_move(piece, move,
                                                   current_board.copy())
                # if one of the moves does not result in check i.e. there is a valid move, return false
                if not self.is_in_check(updated_board,
                                        self.__get_opposing_color(color)):
                    return False
        return True

    def simulate_move(self, piece, destination_coordinate, simulated_board):
        piece_position = piece.tile_index
        simulated_board[destination_coordinate] = piece
        simulated_board[piece_position] = 0
        return simulated_board

    def __move(self, coordinate):
        if self.selected and coordinate in self.valid_moves:
            self.board.move(self.selected, coordinate)
            self.__display_moves(self.selected.notation +
                                 ALGEBRAIC_NOTATION[coordinate])
            self.change_turn()
        else:
            return False
        return True

    def draw_valid_moves(self, moves):
        for move in moves:
            row = move // ROWS
            col = move % ROWS
            self.win.blit(GREEN_BOX, (col * SQUARE_SIZE, row * SQUARE_SIZE))

    def change_turn(self):
        self.selected = None
        self.turn = WHITE if self.turn == BLACK else BLACK

        if self.is_check_mate(self.board.get_board(), self.turn):
            self.check_mate = True

    def get_current_player(self):
        return self.turn

    def get_board(self):
        return self.board

    def ai_move(self, board):
        current_board = self.board.get_board()
        piece = None
        coordinate = None

        # Find the Piece that was moved and its coordinate
        for i in range(len(board)):
            if current_board[i] != board[i] and board[i] != 0:
                piece = board[i]
                coordinate = i
                break
        if piece:
            self.__display_moves(piece.notation +
                                 ALGEBRAIC_NOTATION[coordinate])
            self.board.move(piece, coordinate)
        else:
            print("COULDN'T FIND PIECE")
        self.change_turn()

    def evaluate(self, depth, current_board):
        """
        Evaluates a given board using the helper functions below
        :param depth: integer representing how deep the minimax algorithm went
        :param current_board:
        :return: inteer representing the evaluated score
        """
        return self.__check(current_board) + self.__checkmate(
            depth, current_board) + self.__mobility() + self.__piece_value(
                current_board)

    def __checkmate(self, depth, current_board):
        return CHECK_MATE_BONUS * self.__depth_bonus(
            depth) if self.is_check_mate(
                current_board, self.__get_opposing_color(self.turn)) else 0

    def __depth_bonus(self, depth):
        return 1 if depth == 0 else DEPTH_BONUS * depth

    def __check(self, current_board):
        return CHECK_BONUS if self.is_in_check(
            current_board, self.__get_opposing_color(self.turn)) else 0

    def __mobility(self):
        return len(self.valid_moves)

    def __piece_value(self, current_board):
        piece_value_score = 0
        pieces = self.board.get_player_pieces(self.turn, current_board)
        for piece in pieces:
            piece_value_score += piece.piece_value
        return piece_value_score
Beispiel #3
0
class Game:
    def __init__(self, win, skill_level):
        self.win = win
        self.board = Board()
        self._initialize()
        self.engine = Engine(skill_level)
        self.buttons = [
            Button(SQUARE_SIZE * 9, SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE // 2,
                   RED, "queen"),
            Button(SQUARE_SIZE * 9, SQUARE_SIZE * 2, SQUARE_SIZE,
                   SQUARE_SIZE // 2, BLUE, "bishop"),
            Button(SQUARE_SIZE * 9, SQUARE_SIZE * 3, SQUARE_SIZE,
                   SQUARE_SIZE // 2, GREEN, "knight"),
            Button(SQUARE_SIZE * 9, SQUARE_SIZE * 4, SQUARE_SIZE,
                   SQUARE_SIZE // 2, ORANGE, "rook")
        ]

    def _initialize(self):

        self.selected = None
        self.turn = WHITE
        self.valid_moves = {}
        self.winner = None
        self.moves_since_pawn_move_or_capture = 0
        self.past_positions = {self.board.get_position(): 1}
        self.move_count = 0
        self.promotion_move = False

    def update(self):
        self.board.draw(self.win)
        self.draw_valid_moves()
        if self.promotion_move:
            for button in self.buttons:
                button.draw(self.win)

    def draw_valid_moves(self):
        for move in self.valid_moves:
            row, col = move
            pygame.draw.circle(
                self.win, LIGHT_BLUE,
                (col * SQUARE_SIZE + SQUARE_SIZE // 2 + BOARD_EDGE,
                 row * SQUARE_SIZE + SQUARE_SIZE // 2 + BOARD_EDGE),
                POSSIBLE_MOVE_RADIUS)

    def make_engine_move(self):
        self.engine.set_position(self.get_current_fen())
        move = self.engine.get_move(ENGINE_TIME_PER_MOVE)
        promotion = False
        if len(move) == 5:
            start_col, start_row, end_col, end_row, promotion = move
            start_col, end_col = ord(start_col) - ord('a'), ord(end_col) - ord(
                'a')
            start_row, end_row = ROWS - int(start_row), ROWS - int(end_row)
        else:
            start_col, start_row, end_col, end_row = move
            start_col, end_col = ord(start_col) - ord('a'), ord(end_col) - ord(
                'a')
            start_row, end_row = ROWS - int(start_row), ROWS - int(end_row)
        piece = self.board.get_piece(start_row, start_col)
        self.selected = piece
        self.valid_moves = piece.find_legal_moves(self.board.board)
        if promotion:
            self.board.move(self.selected, end_row, end_col, self.board.board)
            if promotion == "q":
                self.board.board[end_row][end_col] = piece.promote_to_queen()
            elif promotion == 'n':
                self.board.board[end_row][end_col] = piece.promote_to_knight()
            elif promotion == 'r':
                self.board.board[end_row][end_col] = piece.promote_to_rook()
            elif promotion == 'b':
                self.board.board[end_row][end_col] = piece.promote_to_bishop()
            self.board.remove(self.board.board, (start_row, start_col))
            self.moves_since_pawn_move_or_capture = 0
            current_position = self.board.get_position()
            self.update_past_positions()
            self.change_turn(current_position)
        else:
            self._move(end_row, end_col)
        time.sleep(1)

    def select(self, position):
        pos = self.get_position(position)
        if pos and not self.promotion_move:
            row, col = pos
            if self.selected:
                result = self._move(row, col)
                if not result:
                    self.selected = None
                    self.select(position)
                    self.valid_moves = {}
            piece = self.board.get_piece(row, col)
            if piece is not None and piece.get_color() == self.turn:
                self.selected = piece
                self.valid_moves = self.board.find_legal_moves(piece)
                return True
        elif self.promotion_move:
            row, col = self.promotion_move
            piece = self.board.get_piece(row, col)
            for button in self.buttons:
                if button.clicked(position):
                    piece_type = button.get_name()
                    piece = self.board.get_piece(row, col)
                    if piece_type == "queen":
                        self.board.board[row][col] = piece.promote_to_queen()
                    elif piece_type == "bishop":
                        self.board.board[row][col] = piece.promote_to_bishop()
                    elif piece_type == "knight":
                        self.board.board[row][col] = piece.promote_to_knight()
                    elif piece_type == "rook":
                        self.board.board[row][col] = piece.promote_to_rook()
                    self.promotion_move = False
                    self.board.promotion_move = False
                    self.update_past_positions()
                    board_pos = self.board.get_position()
                    self.change_turn(board_pos)
                    self.moves_since_pawn_move_or_capture = 0
                    return True
        return False

    @staticmethod
    def get_position(position):
        x, y = position
        if BOARD_EDGE < x < WIDTH + BOARD_EDGE and BOARD_EDGE < y < HEIGHT + BOARD_EDGE:
            row = (y - BOARD_EDGE) // SQUARE_SIZE
            col = (x - BOARD_EDGE) // SQUARE_SIZE
            return row, col
        else:
            return None

    def _move(self, row, col):
        if self.selected and (row, col) in self.valid_moves:
            self.board.move(self.selected, row, col, self.board.board)
            capture = self.valid_moves[(row, col)]
            if capture:
                self.moves_since_pawn_move_or_capture = 0
                capture_row, capture_col = capture
                if capture_row != row:  # en passant
                    self.board.remove(self.board.board, capture)
            elif isinstance(self.selected, Pawn):
                self.moves_since_pawn_move_or_capture = 0
            else:
                self.moves_since_pawn_move_or_capture += 1
            position = self.board.get_position()
            self.promotion_move = self.board.promotion_move
            if not self.promotion_move:
                self.update_past_positions()
                self.change_turn(position)
        else:
            return False
        return True

    def change_turn(self, position):
        self.valid_moves = {}
        self.board.stop_en_passant(self.turn)
        self.selected = None
        if self.turn == WHITE:
            self.turn = BLACK
            self.move_count += 1
        else:
            self.turn = WHITE
        self.board.find_all_possible_moves(self.turn)
        if self.moves_since_pawn_move_or_capture == 100:
            self.winner = "Draw - 50 move rule"
        elif self.past_positions[position] == 3:
            self.winner = "Draw - 3 fold repetition"
        else:
            self.winner = self.board.checkmate_or_stalemate(self.turn)

    def reset(self):
        self.board.reset()
        self._initialize()

    def get_winner(self):
        return self.winner

    def check_promotion(self):
        piece = self.board.promotion_move
        if piece:
            self.board.promotion_move = False
            return piece
        return False

    def update_past_positions(self):
        position = self.board.get_position()
        if position in self.past_positions:
            self.past_positions[position] += 1
        else:
            self.past_positions[position] = 1

    def get_current_fen(self):
        return self.board.get_fen(self.turn,
                                  self.moves_since_pawn_move_or_capture,
                                  self.move_count)