Exemple #1
0
class Chess:
    """Controller class of the game Chess"""

    def __init__(self):
        """Setup of Chess game. All game state variables, positin, and the 
        view are created."""

        # Game state variables
        self.play = True
        self.status = 'start_screen'
        self.win_condition = None
        
        self.move = []
        
        # Board is flipped if white is shown on top of the board
        self.is_flipped = False
        
        # Mouse events
        self.is_down = False
        self.is_dragged = None
        self.is_clicked = None
        self.left_click = None
        self.right_click = None
        
        # Settings
        self.settings = {'flip': False, 
                         'vs_computer': False, 
                         'ai_level': 1}

        # View
        self.view = GameView()
        
        # Board
        self.board = None
        
    def process_click(self, x, y, is_up=False):
        """The main method of the controller.
        This method determines in which phase of the game we are and 
        what method needs to be executed based on the phase.

        Args:
        - x: x-coordinate of mouse at click (in px)
        - y: y-coordinate of mouse at click (in px)
        """
        if self.status == 'start_screen': self.start_screen(x, y)
        elif self.status == 'settings': self.update_settings(x, y)
        elif self.status == 'game': self.play_game(x, y, is_up)
        elif self.status == 'replay': self.play_again(x, y)
    
    def start_screen(self, x, y):
        """Start screen of the game.
        There are three options: start the game, look and 
        change the game settings, or quit the game.
        
        Args:
        - x: x-coordinate of mouse at click (in px)
        - y: y-coordinate of mouse at click (in px)
        """
        if self.view.start_game_button.is_clicked(x, y):
            self.status = 'game'
            self.get_settings()
            self.start_game()
        elif self.view.settings_button.is_clicked(x, y):
            self.status = 'settings'
        elif self.view.quit_game_button.is_clicked(x, y):
            self.status = 'end_game'
            self.play = False

    def get_settings(self):
        """Get the selected settings by the user"""
        for button in self.view.all_buttons:
            group = button.group
            if (group == 'flip' or group == 'vs_computer' or group == 'ai_level') and button.selected:
                self.settings[group] = button.value

    def update_settings(self, x, y):
        """Settings page.
        Determine what settings the user changes. The values that can be changed are: 
        the opponent (human or AI), and the level of the AI (1, 2 or 3).
        
        Args:
        - x: x-coordinate of mouse at click (in px)
        - y: y-coordinate of mouse at click (in px)
        """
        button_groups = ['flip', 'vs_computer', 'ai_level']

        # Check if button is clicked
        for button in self.view.all_buttons:
            if button.group in button_groups and button.is_clicked(x, y):
                
                # Update view of other buttons that are not selected
                for related_button in self.view.all_buttons:
                    if related_button.group == button.group and related_button.selected:
                        related_button.update(False, self.view.LIGHT_GRAY, self.view.BLACK)

                # Update view of clicked button
                button.update(True, self.view.GREEN, self.view.WHITE)
        
        # Check if user is satisfied with settings and wants to return to
        # start screen to start playing the game
        if self.view.back_button.is_clicked(x, y):
            self.status = 'start_screen'

    def start_game(self):
        """The game is started with the selected settings.
        The default settings are: human vs. human."""

        # Change starting screen to Chess board
        self.board = Board(square_width=self.view.square_width, 
                           square_height=self.view.square_height,
                           is_flipped=self.is_flipped)

        # Create players
        self.board.player_list.append('Human')
        
        if self.settings['vs_computer']: self.board.player_list.append('AI')
        else: self.board.player_list.append('Human') 
        
    def play_game(self, mouse_x, mouse_y, is_up):
        """[summary]

        Args:
            mouse_x ([type]): [description]
            mouse_y ([type]): [description]
            is_up (bool): [description]
        """
        x, y = self.pixel_coord_to_tile(mouse_x, mouse_y)
        square = self.board.get_square(x, y)
        
        # Check if button is clicked
        if (is_up 
            and (self.view.draw_game_button.is_clicked(mouse_x, mouse_y) 
                 or self.view.resign_game_button.is_clicked(mouse_x, mouse_y))): 
                self.new_game(mouse_x, mouse_y)

        elif is_up and self.is_clicked:
            # Check possible moves, and if possible
            # make the move.
            self.board.moves = self.is_clicked.valid_moves
            if (square.x, square.y) != self.left_click:
                self.move = [self.left_click, (square.x, square.y)]
                
                if (self.is_clicked.can_move 
                    and self.move in self.is_clicked.valid_moves):
                    self.board.move_piece(color=self.board.current_color, 
                                          moving_piece=self.is_clicked, 
                                          move=self.move)
                    self.update()                    
                    self.board.next_turn(self.is_clicked, self.move)
                    if self.settings['flip']: self.board.is_flipped = not self.board.is_flipped
                                        
                self.board.moves = []
                self.is_clicked = None
                self.is_dragged = None
                
            else: self.is_dragged = None
        
        else:
            if square is not None and not (self.is_clicked and self.is_dragged):
                if not isinstance(square, Empty) and square.color == self.board.current_color:
                    self.is_clicked = square
                    self.is_dragged = square
                    self.left_click = (square.x, square.y)
                else: self.reset_highlights_and_arrows()

    def reset_highlights_and_arrows(self):
        """Reset highlights and arrows from board"""
        self.board.moves = []
        self.board.highlighted_tiles = []
        self.board.arrow_coordinates = []

    def process_right_click(self, mouse_x, mouse_y, is_up):
        """Get annotations drawn on the board using the right mouse button.

        Args:
            mouse_x (int): x-coordinate of the mouse (in px)
            mouse_y (int): y-coordinate of the mouse (in px)
            is_up (bool): variable indicating whether the mouse button is pressed
                or released.
        """
        x, y = self.pixel_coord_to_tile(mouse_x, mouse_y)

        # Mouse button is released
        if is_up:
            
            # Check for possible arrows
            if (x, y) != self.right_click:
                x1, y1 = self.right_click
                arrow = [(x1, y1), (x, y)]

                # Check if user wants to remove arrow by drawing opposite arrow
                if arrow in self.board.arrow_coordinates:
                    index = self.board.arrow_coordinates.index(arrow)
                    self.board.arrow_coordinates.pop(index)
                else: self.board.arrow_coordinates.append(arrow)                   

            else:
                # User does not want to draw arrow but wants to highlight tiles
                if (x, y) not in self.board.highlighted_tiles:
                    self.board.highlighted_tiles.append((x, y))
                else:
                    index = self.board.highlighted_tiles.index((x, y))
                    self.board.highlighted_tiles.pop(index)

        # Mouse button is pressed
        else: self.right_click = (x, y)          

    def ai_move(self):
        """"""
        pass
    
    def update(self):
        """"""
        if self.status == 'game':
            self.board.update_possible_moves()
            self.check_for_game_end()
                
    def check_for_game_end(self):
        """"""
        for condition, state in self.board.end_conditions.items():
            if state: 
                self.win_condition = condition
                self.status = 'replay'
                break

    def new_game(self, x, y):
        """"""
        if self.view.draw_game_button.is_clicked(x, y): 
            self.board.end_conditions['draw_agreed'] = True
            self.board.winner = 'Draw'
            
        if self.view.resign_game_button.is_clicked(x, y): 
            self.board.end_conditions['resignation'] = True
            winner = 1 if self.board.current_player == 0 else 0
            self.board.winner = ['White', 'Black'][winner]
    
    def play_again(self, x, y):
        if self.view.play_again_button.is_clicked(x, y): self.status = 'start_screen'
        if self.view.nomore_game_button.is_clicked(x, y): 
            self.status = 'end_game'
            self.play = False

    def chess_coord_to_pixels(self, board_x, board_y):
        """Get pixel coordinates from chess board coordinates"""
        return board_x * self.view.square_width, board_y * self.view.square_height

    def pixel_coord_to_tile(self, pixel_x, pixel_y):
        """Get board coordinates from pixel board coordinates"""
        return pixel_x // self.view.square_width, pixel_y // self.view.square_height