def rightGridButtonClick(self, textual_coordinates):
        """Slot used when the right grid's QCustomPushButton is clicked.

        :param textual_coordinates: position of the button represented as a
            string

        """
        numerical_coordinates = Coordinates.parse_coordinates(
            textual_coordinates, self._grid_size
        )
        session_phase = self._session.session_phase
        player_one = self.session.player_one
        player_two = self.session.player_two

        if session_phase == SessionPhase.battle:
            if not player_one.shoot(player_two.grid, numerical_coordinates):
                return
            else:
                if player_two.fleet.is_sunk():
                    self._paint_both_player_grids(player_one, player_two, True)
                    self._declare_winner(player_one)
                    return

            if not player_two.shoot(player_one.grid):
                return
            else:
                if player_one.fleet.is_sunk():
                    self._paint_both_player_grids(player_one, player_two, True)
                    self._declare_winner(player_two)
                    return

            self._paint_both_player_grids(player_one, player_two)
    def leftGridButtonClick(self, textual_coordinates):
        """Slot used when the left grid's QCustomPushButton is clicked.

        :param textual_coordinates: position of the button represented as a
            string

        """
        numerical_coordinates = Coordinates.parse_coordinates(
            textual_coordinates, self._grid_size
        )
        session_phase = self._session.session_phase

        if session_phase == SessionPhase.fleet_layout:
            grid = self._session.player_one.grid
            fleet = self._session.player_one.fleet
            ship = fleet.ships[self._current_ship_index]

            if fleet.position_ship(grid,
                                   ship,
                                   self._current_orientation,
                                   numerical_coordinates):
                self._current_ship_index += 1

                if self._current_ship_index == len(fleet.ships):
                    self._session.session_phase = SessionPhase.battle

                    self._session.player_one.initialize_fleet()
                    self._session.player_two.initialize_fleet()

            self._update_status_bar()
        self._paint_player_grid(self.ui.gridLayoutLeft,
                                self._session.player_one)
    def _populate_grid_at_position(self,
                                   grid_position,
                                   mapper,
                                   layout,
                                   coordinate_pair):
        # creates a button and positions it on the grid

        x, y = coordinate_pair[0], coordinate_pair[1]
        textual_coordinates = "{0}-{1}".format(x, y)
        button = QCustomPushButton(
            self,
            grid_position,
            Coordinates.parse_coordinates(textual_coordinates,
                                          self._grid_size)
        )

        Helpers.paint_grid_button(button, style.FIELD_BLUE)
        button.setObjectName("GridButton")
        button.setFixedSize(style.FIELD_ICON_SIZE + 10,
                            style.FIELD_ICON_SIZE + 10)
        button.setIconSize(QSize(style.FIELD_ICON_SIZE, style.FIELD_ICON_SIZE))

        # set the QSignalMapper's mapping to work with strings
        mapper.setMapping(button, textual_coordinates)
        # connecting the button's clicked signal to the QSignalMappers
        # mapped slot
        button.clicked.connect(mapper.map)
        # finally, add the button to the QGridLayout
        layout.addWidget(button, x, y)
    def coordinates_input(grid_size):
        """Asks the user to choose coordinates.

        :param grid_size: a member of the GridSize enum, used to
            additionally validate the input
        :return: an instance of type Coordinates, chosen coordinates

        """
        chosen_coordinates = None

        while True:
            print(Style.RESET_ALL)

            choice = raw_input("Choose coordinates [row-column]: ")
            choice = choice.strip()

            try:
                # convert the input to an instance of type Coordinates
                chosen_coordinates = Coordinates.parse_coordinates(
                    choice,
                    grid_size,
                    True
                )
                break
            # invalid input, continue the next iteration
            except InvalidCoordinatesFormatError as e:
                print(Fore.RED + e.message)
            except CoordinatesOutOfBoundsError as e:
                print(Fore.RED + e.message)

        print(Style.RESET_ALL, end="")

        return chosen_coordinates
    def test_parse_coordinates(self):
        coordinates = Coordinates(5, 5)

        test = Coordinates.parse_coordinates("5-5", GridSize.small)
        self.assertEqual(test, coordinates)

        self.assertRaises(InvalidCoordinatesFormatError,
                          Coordinates.parse_coordinates,
                          "5/5",
                          GridSize.small)

        self.assertRaises(CoordinatesOutOfBoundsError,
                          Coordinates.parse_coordinates,
                          "50-50",
                          GridSize.small)