Esempio n. 1
0
class GameState(BaseState):
    """
    This class is the main game class.
    ---------------------------------------------------------------------------
    Attributes :
        - __main : Main object
        - __grid : The grid of the game (8x8)
        - __player1 : The player 1 of the game
        - __player2 : The player 2 of the game
        - __piece_to_mouse : The piece that has been clicked dans that the player is moving
    """
    def __init__(self, cfg, main):
        """
        Constructor
        -----------------------------------------------------------------------
        Arguments :
            - cfg : Config of the class
            - main : Main class
        -----------------------------------------------------------------------
        Return : None.
        """
        super(GameState, self).__init__(cfg=cfg, main=main)
        self._main = main
        self.__grid = []
        self.__player1 = Player(cfg=self._ownConfig["players"]["1"],
                                game=self,
                                number=1)
        self.__player2 = Player(cfg=self._ownConfig["players"]["2"],
                                game=self,
                                number=2)
        self.__piece_to_mouse = None

    def set_up(self):
        """
        Method used to set_up everything
        -----------------------------------------------------------------------
        Arguments :
        -----------------------------------------------------------------------
        Return : None.
        """
        # Set up the grid
        self.set_up_grid()

        # Set up pieces
        self.set_up_pieces()

        # start player
        self.__player1.set_playing(True)

    def launch(self):
        """
        Method called to launch the game
        -----------------------------------------------------------------------
        Arguments : None.
        -----------------------------------------------------------------------
        Return : None.
        """
        self.set_up()

    def set_up_grid(self):
        """
        Method called to set up the grid
        -----------------------------------------------------------------------
        Arguments : None.
        -----------------------------------------------------------------------
        Return : None.
        """
        # Setting the grid 8x8
        for i in range(8):
            self.__grid.append(i)

    def set_up_pieces(self):
        """
        Method called to set up the pieces
        It is not done with loop because it could need so much effort
        for nothing as the pieces are always the same and at the same square
        -----------------------------------------------------------------------
        Arguments : None.
        -----------------------------------------------------------------------
        Return : None.
        """
        pieces = []

        # Player 1
        pieces.append(
            Rook(y=0, x=0, code=Piece.ROOK_CODE, player=self.__player1))
        pieces.append(
            Knight(y=0, x=1, code=Piece.KNIGHT_CODE, player=self.__player1))
        pieces.append(
            Bishop(y=0, x=2, code=Piece.BISHOP_CODE, player=self.__player1))
        pieces.append(
            King(y=0, x=3, code=Piece.KING_CODE, player=self.__player1))
        pieces.append(
            Queen(y=0, x=4, code=Piece.QUEEN_CODE, player=self.__player1))
        pieces.append(
            Bishop(y=0, x=5, code=Piece.BISHOP_CODE, player=self.__player1))
        pieces.append(
            Knight(y=0, x=6, code=Piece.KNIGHT_CODE, player=self.__player1))
        pieces.append(
            Rook(y=0, x=7, code=Piece.ROOK_CODE, player=self.__player1))

        for i in range(8):
            pieces.append(Pawn(y=1, x=i, code=PAWN_CODE,
                               player=self.__player1))
            pass
        self.__player1.setPieces(pieces)

        pieces = []

        # Player 2
        pieces.append(
            Rook(y=7, x=0, code=Piece.ROOK_CODE, player=self.__player2))
        pieces.append(
            Knight(y=7, x=1, code=Piece.KNIGHT_CODE, player=self.__player2))
        pieces.append(
            Bishop(y=7, x=2, code=Piece.BISHOP_CODE, player=self.__player2))
        pieces.append(
            King(y=7, x=3, code=Piece.KING_CODE, player=self.__player2))
        pieces.append(
            Queen(y=7, x=4, code=Piece.QUEEN_CODE, player=self.__player2))
        pieces.append(
            Bishop(y=7, x=5, code=Piece.BISHOP_CODE, player=self.__player2))
        pieces.append(
            Knight(y=7, x=6, code=Piece.KNIGHT_CODE, player=self.__player2))
        pieces.append(
            Rook(y=7, x=7, code=Piece.ROOK_CODE, player=self.__player2))
        pieces.append(
            Rook(y=7, x=8, code=Piece.ROOK_CODE, player=self.__player2))

        for i in range(8):
            pieces.append(Pawn(y=6, x=i, code=PAWN_CODE,
                               player=self.__player2))

        self.__player2.setPieces(pieces)

    # GETTERS SETTERS
    def getGrid(self):
        return self.__grid

    def getPieces(self):
        return self.__player1.getPieces(), self.__player2.getPieces()

    def handle_events(self, events):
        """
        This method is used to handle events.
        -----------------------------------------------------------------------
        Arguments :
            - events : List of event from pygame.event.get()
        -----------------------------------------------------------------------
        Return : None.
        """
        # Event from pygame
        for event in events:
            # Window quit event
            if event.type == pygame.QUIT:
                self._main.stop_gui()

            # Click event
            elif event.type == pygame.MOUSEBUTTONUP:

                # Getting mouse coordinates
                mx, my = pygame.mouse.get_pos()
                # Checking if it's the first player is playing
                if self.__player1.is_playing():
                    # If it's him then we can check what to do with his click

                    played = self.check_clicked_pieces(
                        self.__player1.getPieces(), mx, my,
                        self.__player1.getNumber())
                    if played:
                        self.__player1.set_playing(False)
                        self.__player2.set_playing(True)
                else:
                    played = self.check_clicked_pieces(
                        self.__player2.getPieces(), mx, my,
                        self.__player2.getNumber())
                    if played:
                        self.__player1.set_playing(True)
                        self.__player2.set_playing(False)

    def checkmate(self):
        pass

    def check_clicked_pieces(self, pieces, mx, my, player_nb):
        """
        This method handle the click on the pieces.
        It will check which piece is clicked and how to handle it with
        the current player and pieces pos.
        -----------------------------------------------------------------------
        Arguments :
            - pieces : Current player pieces
            - mx : X pos of the mouse
            - my : Y pos of the mouse
            - player_nb : current number of the player
        -----------------------------------------------------------------------
        Return :
            - True : If the player moved his piece
            - False : If not
        """
        for player in (self.__player1, self.__player2):
            current_pl_pos, other_pl_pos = self.getPlayersPos(player_nb)

        # There we go for each piece of the player to check if he clicked on one
        for p in pieces:
            # Get the coordintes of the piece
            y = p.getY() * 62.5
            x = p.getX() * 62.5

            # We use x, y, mx, my to check if the current piece of the loop is being clicked and if there is no piece already
            # Selected
            if mx > x and mx < x + p.getWidth(
            ) and my > y and my < y + p.getWidth(
            ) and self.__piece_to_mouse == None and p.is_alive():
                # If so, we change the state of the piece
                p.selected()
                # And we keep a reference to the piece
                self.__piece_to_mouse = p
            # Same than above but with a piece already selected, so we need to check if the square is empty or if the is
            # an enemy on it
            elif mx > x and mx < x + p.getWidth(
            ) and my > y and my < y + p.getWidth(
            ) and self.__piece_to_mouse != None and p.is_alive():
                self.__piece_to_mouse.selected()

            # If there is already a piece selected
            elif self.__piece_to_mouse is not None:
                # If the selected piece is the current
                if p.is_selected():
                    # We get the clicked square
                    x, y = self.get_clicked_square(mx, my)

                    # We call the method of the piece to check if the moce is avaible
                    if p.is_move_avaible(x,
                                         y,
                                         current_pl_pos=current_pl_pos,
                                         other_pl_pos=other_pl_pos):
                        # Check if there is a kill
                        self.check_kill(x, y, player_nb)

                        # Update the pos of the piece
                        p.new_pos(x, y)
                        # Update the selected attribute of the piece
                        p.selected()
                        # Remove the reference
                        self.__piece_to_mouse = None
                        return True

                    # If the move is not avaible we reset put back the piece where it belongs
                    p.selected()
                    self.__piece_to_mouse = None
                    return False
        return False

    def getPlayersPos(self, player_nb):
        """
        Method used to get the player pieces pos
        -----------------------------------------------------------------------
        Arguments :
            - player_nb : Current number of the player
        -----------------------------------------------------------------------
        Return :
            - current_pl_pos : list with current player pieces pos
            - other_pl_pos : list with the player that is not playing pieces pos
        """
        current_pl_pos = []
        other_pl_pos = []

        # Setting up var to loop
        if player_nb == 1:
            player = self.__player1
            other_player = self.__player2
        else:
            player = self.__player2
            other_player = self.__player1

        # Adding pieces to each list
        for p in player.getPieces():
            current_pl_pos.append(p.getPos())

        for p in other_player.getPieces():
            other_pl_pos.append(p.getPos())

        return current_pl_pos, other_pl_pos

    def check_kill(self, x, y, player_nb):
        """
        Method used to check if there is a kill
        -----------------------------------------------------------------------
        Arguments :
            - x : X of the next square
            - y : Y of the next square
        -----------------------------------------------------------------------
        Return : None.
        """
        # Going through all pieces
        for pl in (self.__player1, self.__player2):
            for i, piece in enumerate(pl.getPieces()):
                # If the pieces that might be killed is an enemy piece
                if piece.getX() == x and piece.getY(
                ) == y and piece.getPlayerNumber() != player_nb:
                    # If there is a kill then we leave the loop
                    self.kill_piece(piece.getPlayerNumber(), i)
                    break

    def kill_piece(self, nb_player, piece):
        """
        Method used to kill a piece
        -----------------------------------------------------------------------
        Arguments :
            - nb_player : Number of the piece's player
            - piece : Piece that have to be kill
        -----------------------------------------------------------------------
        Return : None.
        """
        if nb_player == 1:
            self.__player1.kill_piece(piece)
        else:
            self.__player2.kill_piece(piece)

    def get_clicked_square(self, x, y):
        """
        Method that calculate the square from coordinate (x, y)
        -----------------------------------------------------------------------
        Arguments :
            - x : X coordinate
            - y : Y coordinate
        -----------------------------------------------------------------------
        Return :
            - x : X within the grid (from 0 to 7)
            - y : Y within the grid (from 0 to 7)
        """
        x = int(x / 62.5)
        y = int(y / 62.5)
        return x, y
Esempio n. 2
0
class GameState(BaseState):
    """
    This class is the main game class.
    ---------------------------------------------------------------------------
    Attributes :
        - __main : Main object
        - __grid : The grid of the game (8x8)
        - __player1 : The player 1 of the game
        - __player2 : The player 2 of the game
        - __piece_to_mouse : The piece that has been clicked dans that the player is moving
    """
    def __init__(self, cfg, main):
        """
        Constructor
        -----------------------------------------------------------------------
        Arguments :
            - cfg : Config of the class
            - main : Main class
            - See attributes above.
        -----------------------------------------------------------------------
        Return : None.
        """
        super(GameState, self).__init__(cfg=cfg, main=main)
        self._main = main
        self.__grid = []
        self.__player1 = Player(cfg=self._ownConfig["players"]["1"],
                                game=self,
                                number=1)
        self.__player2 = Player(cfg=self._ownConfig["players"]["2"],
                                game=self,
                                number=2)
        self.__piece_to_mouse = None

    def set_up(self):
        """
        Method used to set_up everything
        -----------------------------------------------------------------------
        Arguments : None.
        -----------------------------------------------------------------------
        Return : None.
        """
        # Set up the grid
        self.set_up_grid()

        # Set up pieces
        self.set_up_pieces()

        # start player
        self.__player1.set_playing(True)

    def launch(self):
        """
        Method called to launch the game
        -----------------------------------------------------------------------
        Arguments : None.
        -----------------------------------------------------------------------
        Return : None.
        """
        self.set_up()

    def set_up_grid(self):
        """
        Method called to set up the grid
        -----------------------------------------------------------------------
        Arguments : None.
        -----------------------------------------------------------------------
        Return : None.
        """
        # Setting the grid 8x8
        for i in range(8):
            self.__grid.append(i)

    def set_up_pieces(self):
        """
        Method called to set up the pieces
        It is not done with loop because it could need so much effort
        for nothing as the pieces are always the same and at the same square
        -----------------------------------------------------------------------
        Arguments : None.
        -----------------------------------------------------------------------
        Return : None.
        """
        pieces = []

        # Player 1
        pieces.append(
            Rook(y=0, x=0, code=Piece.ROOK_CODE, player=self.__player1))
        pieces.append(
            Knight(y=0, x=1, code=Piece.KNIGHT_CODE, player=self.__player1))
        pieces.append(
            Bishop(y=0, x=2, code=Piece.BISHOP_CODE, player=self.__player1))
        pieces.append(
            King(y=0, x=3, code=Piece.KING_CODE, player=self.__player1))
        pieces.append(
            Queen(y=0, x=4, code=Piece.QUEEN_CODE, player=self.__player1))
        pieces.append(
            Bishop(y=0, x=5, code=Piece.BISHOP_CODE, player=self.__player1))
        pieces.append(
            Knight(y=0, x=6, code=Piece.KNIGHT_CODE, player=self.__player1))
        pieces.append(
            Rook(y=0, x=7, code=Piece.ROOK_CODE, player=self.__player1))

        for i in range(8):
            pieces.append(
                Pawn(y=1, x=i, code=Piece.PAWN_CODE, player=self.__player1))
            # pass
        self.__player1.setPieces(pieces)

        pieces = []

        # Player 2
        pieces.append(
            Rook(y=7, x=0, code=Piece.ROOK_CODE, player=self.__player2))
        pieces.append(
            Knight(y=7, x=1, code=Piece.KNIGHT_CODE, player=self.__player2))
        pieces.append(
            Bishop(y=7, x=2, code=Piece.BISHOP_CODE, player=self.__player2))
        pieces.append(
            King(y=7, x=3, code=Piece.KING_CODE, player=self.__player2))
        pieces.append(
            Queen(y=7, x=4, code=Piece.QUEEN_CODE, player=self.__player2))
        pieces.append(
            Bishop(y=7, x=5, code=Piece.BISHOP_CODE, player=self.__player2))
        pieces.append(
            Knight(y=7, x=6, code=Piece.KNIGHT_CODE, player=self.__player2))
        pieces.append(
            Rook(y=7, x=7, code=Piece.ROOK_CODE, player=self.__player2))

        for i in range(8):
            pieces.append(
                Pawn(y=6, x=i, code=Piece.PAWN_CODE, player=self.__player2))
            # pass
        self.__player2.setPieces(pieces)

    def handle_events(self, events):
        """
        This method is used to handle events.
        -----------------------------------------------------------------------
        Arguments :
            - events : List of event from pygame.event.get()
        -----------------------------------------------------------------------
        Return : None.
        """
        # Event from pygame
        for event in events:
            # Window quit event
            if event.type == pygame.QUIT:
                self._main.stop_gui()

            # Click event
            elif event.type == pygame.MOUSEBUTTONUP:
                # Getting mouse coordinates
                mx, my = pygame.mouse.get_pos()

                # Checking button click
                for b in self._main.get_buttons():
                    if mx > b.get_x() and mx < b.get_x() + b.get_width(
                    ) and my > b.get_y() and my < b.get_y() + b.get_height():
                        b.action()

                # Checking if it's the first player is playing
                if self.__player1.is_playing():

                    # If it's him then we can check what to do with his click
                    played = self.check_clicked_pieces(
                        self.__player1.getPieces(), mx, my,
                        self.__player1.getNumber())
                    if played:
                        # self.check_check(1)

                        # Change playing player
                        self.__player1.set_playing(False)
                        self.__player2.set_playing(True)
                        self.check_check(2)

                else:
                    played = self.check_clicked_pieces(
                        self.__player2.getPieces(), mx, my,
                        self.__player2.getNumber())
                    if played:
                        # Change playing player
                        self.__player2.set_playing(False)
                        self.__player1.set_playing(True)
                        self.check_check(1)
            else:
                # Getting mouse coordinates
                mx, my = pygame.mouse.get_pos()

                for b in self._main.get_buttons():
                    b.hover(mx, my)

    def check_clicked_pieces(self, pieces, mx, my, player_nb):
        """
        This method handle the click on the pieces.
        It will check which piece is clicked and how to handle it with
        the current player and pieces pos.
        -----------------------------------------------------------------------
        Arguments :
            - pieces : Current player pieces
            - mx : X pos of the mouse
            - my : Y pos of the mouse
            - player_nb : current number of the player
        -----------------------------------------------------------------------
        Return :
            - True : If the player moved his piece
            - False : If not
        """
        # We players's pos
        current_pl_pos, other_pl_pos = self.get_players_pos(player_nb)

        # There we go for each piece of the player to check if he clicked on one
        for p in pieces:
            # Get the coordintes of the piece
            y = p.getY() * 62.5
            x = p.getX() * 62.5

            # We use x, y, mx, my to check if the current piece of the loop is being clicked and if there is no piece already
            # selected
            if mx > x and mx < x + p.getWidth(
            ) and my > y and my < y + p.getWidth(
            ) and self.__piece_to_mouse == None:
                # If so, we change the state of the piece
                p.selected()
                # And we keep a reference to the piece
                self.__piece_to_mouse = p
                return False
            # Same than above but with a piece already selected, so we need to check if the square is empty or if the is
            # an enemy on it
            elif mx > x and mx < x + p.getWidth(
            ) and my > y and my < y + p.getWidth(
            ) and self.__piece_to_mouse != None:
                self.__piece_to_mouse.selected()
                self.__piece_to_mouse = None
                return False

            # If there is already a piece selected
            elif self.__piece_to_mouse is not None:
                # If the selected piece is the current
                if p.is_selected():
                    # We get the clicked square
                    x, y = self.get_clicked_square(mx, my)

                    # We call the method of the piece to check if the moce is avaible
                    if p.is_move_available(
                            x,
                            y,
                            current_pl_pos=current_pl_pos,
                            other_pl_pos=other_pl_pos,
                            for_check=False) and not self.check_check(
                                player_nb=player_nb,
                                add_msg=True,
                                x=x,
                                y=y,
                                piece_moving=p):
                        # Check if there is a kill
                        self.check_kill(x, y, player_nb)

                        # Update the pos of the piece
                        p.new_pos(x, y)
                        # Update the selected attribute of the piece
                        p.selected()
                        # Remove the reference
                        self.__piece_to_mouse = None
                        self.add_msg_to_logger(
                            "Player " + str(player_nb) + " moved " +
                            str(p.code_to_str()).capitalize() + " to " +
                            str(x) + "," + str(y) + ".")
                        return True

                    # If the move is not available we reset and put back the piece where it belongs
                    p.selected()
                    self.__piece_to_mouse = None
                    return False
        return False

    def check_check(self,
                    player_nb,
                    add_msg=False,
                    piece_moving=None,
                    x=None,
                    y=None):
        """
        This method is used to check if there is a check
        -----------------------------------------------------------------------
        Arguments :
            - player_nb : [int] Number of the player you want to check the check state
            - add_msg: [bool] True if you want to display FlashMessage to the screen
            - piece_moving : [Piece object or child] Need to be set if the method is called
            because it will set up a new list with updated pos of the piece
            - x : x target of the piece_moving
            - y : y target of the piece_moving
        -----------------------------------------------------------------------
        Return :
            - True : If the player mis under check
            - False : If he is not
        """

        # There we set up the var depending on the player
        if player_nb == 1:
            cur_pl, other_pl = self.get_players_pieces(1)
            cur_pl_pos = self.__player1.get_pieces_pos()
            # Get the currently playing king pos
            king_pos = self.__player1.get_king_pos()
        else:
            cur_pl, other_pl = self.get_players_pieces(2)
            # Get the currently playing king pos
            cur_pl_pos = self.__player2.get_pieces_pos()
            king_pos = self.__player2.get_king_pos()

        # If the method is called with a piece that need to have its
        # pos updated
        if piece_moving != None:
            # Creating a temporary lsit
            temp_pl_pos = []

            # filling it with all the pos of the current player except the piece_moving one
            for i in cur_pl_pos:
                if i != piece_moving.getPos():
                    temp_pl_pos.append(i)

            # Then we add the next pos of the moving_piece
            temp_pl_pos.append((x, y))

            # transfer the data between lists
            cur_pl_pos = temp_pl_pos

            if piece_moving.getCode() == KING_CODE:
                king_pos = (x, y)

        # save_king_pos = king_pos
        # Then we go through all the other pieces to check if he can reach the king
        for piece_moving in other_pl:

            # If it can then we return True and set the check_state of the player to
            # True and return to leave the method.
            if piece_moving.is_move_available(king_pos[0], king_pos[1],
                                              other_pl, cur_pl_pos, True):
                print(piece_moving)
                if add_msg and piece_moving is not None:
                    text = "This move is not allowed because of Check"
                    self._flash_msgs.append(
                        FlashMessage(size=12,
                                     text=text,
                                     x=0,
                                     y=0,
                                     code=WARNING_CODE,
                                     duration=4))

                elif add_msg and piece_moving is None:
                    text = "Check"
                    self._flash_msgs.append(
                        FlashMessage(size=15,
                                     text=text,
                                     x=0,
                                     y=0,
                                     code=WARNING_CODE,
                                     duration=4))

                if player_nb == 1:
                    self.__player1.set_check(True)
                else:
                    self.__player2.set_check(True)
                return True

        # If the return True above is never called during the loop, it means that the player
        # is not under check so we set it to false and return False
        if player_nb == 1:
            self.__player1.set_check(False)
        else:
            self.__player2.set_check(False)
        return False

    def add_msg_to_logger(self, msg):
        self._main.add_msg_to_logger(msg)

    # GETTERS SETTERS
    def get_grid(self):
        return self.__grid

    def get_pieces(self):
        return self.__player1.getPieces(), self.__player2.getPieces()

    def get_players_pos(self, player_nb):
        """
        Method used to get the player pieces pos
        -----------------------------------------------------------------------
        Arguments :
            - player_nb : Current number of the player
        -----------------------------------------------------------------------
        Return :
            - current_pl_pos : list with current player pieces pos
            - other_pl_pos : list with the player that is not playing pieces pos
        """
        current_pl_pos = []
        other_pl_pos = []

        # Setting up var to loop
        if player_nb == 1:
            player = self.__player1
            other_player = self.__player2
        else:
            player = self.__player2
            other_player = self.__player1

        # Adding pieces to each list
        for p in player.getPieces():
            current_pl_pos.append(p.getPos())

        for p in other_player.getPieces():
            other_pl_pos.append(p.getPos())

        return current_pl_pos, other_pl_pos

    def get_players_pieces(self, player_nb):
        if player_nb == 1:
            cur_pl = self.__player1.getPieces()
            other_pl = self.__player2.getPieces()
        else:
            cur_pl = self.__player2.getPieces()
            other_pl = self.__player1.getPieces()

        return cur_pl, other_pl

    def check_kill(self, x, y, player_nb):
        """
        Method used to check if there is a kill
        -----------------------------------------------------------------------
        Arguments :
            - x : X of the next square
            - y : Y of the next square
        -----------------------------------------------------------------------
        Return : None.
        """
        # Going through all pieces
        for pl in (self.__player1, self.__player2):
            for i, piece in enumerate(pl.getPieces()):
                # If the pieces that might be killed is an enemy piece
                if piece.getX() == x and piece.getY(
                ) == y and piece.getPlayerNumber() != player_nb:
                    # If there is a kill then we leave the loop
                    self.kill_piece(piece.getPlayerNumber(), i)
                    self.add_msg_to_logger(
                        "Player " + str(player_nb) + " killed " +
                        str(piece.code_to_str()).capitalize() + " on " +
                        str(x) + "," + str(y) + ".")
                    break

    def kill_piece(self, nb_player, piece):
        """
        Method used to kill a piece
        -----------------------------------------------------------------------
        Arguments :
            - nb_player : Number of the piece's player
            - piece : Piece that have to be kill
        -----------------------------------------------------------------------
        Return : None.
        """
        if nb_player == 1:
            self.__player1.kill_piece(piece)
        else:
            self.__player2.kill_piece(piece)

    def get_theme(self):
        return self._main.get_theme()

    @staticmethod
    def get_clicked_square(x, y):
        """
        Method that calculate the square from coordinate (x, y)
        -----------------------------------------------------------------------
        Arguments :
            - x : X coordinate
            - y : Y coordinate
        -----------------------------------------------------------------------
        Return :
            - x : X within the grid (from 0 to 7)
            - y : Y within the grid (from 0 to 7)
        """
        x = int(x / 62.5)
        y = int(y / 62.5)
        return x, y

    def get_piece_color_choice(self, nb):
        return self._main.get_piece_color_choice(nb)