class Connect4GetPlayerNameTest(unittest.TestCase):
    """Test the Get Player Name prompt from the View"""

    def setUp(self):
        self.view = View()

    def tearDown(self):
        del self.view

    @patch('builtins.input', return_value='Rob-E')
    def test_normal_name(self, inputted_value):
        """Ensure that the view will return a string that is input."""
        name = self.view.get_player_name()
        self.assertEqual(name, 'Rob-E')

    @patch('builtins.input', return_value='')
    @patch('sys.stdout', new_callable=StringIO)
    def test_no_name(self, output, inputted_value):
        """
        Ensure that the view chooses a random name if the user enters
        an empty string.
        :param output: catches the stdout text
        :param inputted_value: strings passed in by mock.patch
        :return: Returns None
        """
        with open('bin/names.txt') as f:
            names = [line.rstrip() for line in f]
        name = self.view.get_player_name()
        self.assertIn(name, names, "Random name generation failed")

    @patch('builtins.input', return_value=long_name)
    @patch('sys.stdout', new_callable=StringIO)
    def test_long_name(self, output, inputted_value):
        """Ensure that the view will return a more reasonably sized name."""
        name = self.view.get_player_name()

        long_name_error = "Wow, that's an impressive name.\n" \
                          "How about we call you Lorem? Hi, Lorem!\n\n"

        self.assertEqual(output.getvalue(), long_name_error,
                         "The long name was not shortened")
        if len(name) > 20:
            self.assertTrue(False, "The name is still too long.")
            return

        self.assertIn(name, long_name)
示例#2
0
 def __init__(self):
     self.view = View()
     self.model = Game()
示例#3
0
class Connect4:
    """The Controller for the Connect 4 game."""
    def __init__(self):
        self.view = View()
        self.model = Game()

    def main(self):

        # Clear the console, and print the instructions.
        self.view.show_instructions()

        # Create the two players
        self.create_player('\u25cf')
        self.create_player('\u25cb')

        self.view.welcome_players(self.model.get_current_player().name)

        while not self.update_player():
            move = -1
            msg = ""
            while move < 0:
                self.view.print_board(self.model.get_board())
                move = self.get_move(self.model.get_current_player().name, msg)
                if self.check_move(self.model.get_board(), move):
                    row = self.model.update_board(move)
                    self.model.get_board()[move][row] = ' '
                    self.view.animate_turn(
                        move, row,
                        self.model.get_current_player().token,
                        self.model.get_board())
                else:
                    msg = "That move is not legal; the column is full."
                    move = -1
            is_won = self.winner_check(self.model.get_board(),
                                       self.model.get_current_player().token)
            if is_won:
                self.view.declare_awesome(self.model.get_current_player().name)
                break
        else:
            self.view.declare_sadness()

    def create_player(self, token):
        """
        Create a player by prompting for their name,
        and then storing that in the model Game.
        :param token: color this player's pieces will be
        :return: Returns None
        """
        name = self.view.get_player_name()
        self.model.add_player(name, token)

    def get_move(self, name, msg=""):
        """
        Gets a move from the user to pass to the game.
        :return: the column of Player's choice (int)
        """
        return self.view.get_player_move(name, msg) - 1

    def check_move(self, board, column):
        """
        Verifies that a chosen move is legal.
        :param board: current state of the game board
        :param column: which column the player wants
        :return: whether the move is legal (bool)
        """
        # Check to make sure the column is not full.
        if board[column][5] == ' ':
            return True

        return False

    def winner_check(self, board, token):
        """
        Looks to see if the player that just moved won.
        :param board: current state of the game board
        :return: whether the move is legal (bool)
        """

        # Vertical
        # for each column, make it a string, look for substring of four in a row
        for col in board:
            if (token * 4) in ''.join(col):
                return True

        # Horizontal
        for i in range(6):
            if (token * 4) in ''.join(column[i] for column in board):
                return True

        # Diagonal Right

        for i, j in product(range(4), range(3)):
            if (token * 4) in ''.join(board[i + k][j + k] for k in range(4)):
                return True

        # Diagonal Left
        for i, j in product(range(4), range(3, 6)):
            if (token * 4) in ''.join(board[i + k][j - k] for k in range(4)):
                return True

        # No solution found, so return False
        return False

    def update_player(self):
        """
        Asks the game to update the turn and whether the
        game has ended in a tie.
        :return: whether the game ended in a tie (bool)
        """
        self.model.update_player()

        if self.model.turn == 42:
            return True

        return False
 def setUp(self):
     self.view = View()
class Connect4GetPlayerMoveTest(unittest.TestCase):
    """Test the Get Player Move method from the View"""

    def setUp(self):
        self.view = View()

    def tearDown(self):
        del self.view

    @patch('builtins.input', return_value="1")
    def test_with_no_message(self, inputted_value):
        """
        Ensures that the view correctly handles a standard move input.
        :param inputted_value: string passed in by mock.patch
        :return: Returns None
        """
        return_value = self.view.get_player_move("Rob-E")
        self.assertEqual(return_value, 1, "get_player_move should return 1")

    @patch('builtins.input', return_value="3")
    @patch('sys.stdout', new_callable=StringIO)
    def test_with_message(self, output, inputted_value):
        """
        Ensures that the view correctly handles a passed in message.
        :param inputted_value: string passed in by mock.patch
        :param output: string printed to stdout by the function
        :return: Returns None
        """
        return_value = self.view.get_player_move("Rob-E", msg="Not so much.")
        self.assertEqual(
            output.getvalue(),
            "Not so much.\n",
            "Message is not printing correctly"
        )
        self.assertEqual(return_value, 3, "get_player_move should return 3")

    @patch('builtins.input', side_effect=["", "4"])
    @patch('sys.stdout', new_callable=StringIO)
    def test_with_no_response(self, output, inputted_value):
        """
        Ensures that the view will reject an empty string as a move
        and press for a new answer.
        :param inputted_value: strings passed in by mock.patch
        :param output: strings printed to stdout by the function
        :return: Returns None
        """
        return_value = self.view.get_player_move("Rob-E")
        self.assertEqual(
            output.getvalue(),
            "Please type only an integer from 1 to 7, Rob-E.\n",
            "Empty string warning is incorrect"
        )
        self.assertEqual(return_value, 4, "get_player_move should return 4")

    @patch('builtins.input', side_effect=["8", "0", "2"])
    @patch('sys.stdout', new_callable=StringIO)
    def test_with_invalid_int(self, output, inputted_value):
        """
        Ensures that the view properly rejects invalid integers.
        :param inputted_value: strings passed in by mock.patch
        :return: Returns None
        """
        return_value = self.view.get_player_move("Rob-E")
        self.assertEqual(
            output.getvalue(),
            "Please type only an integer from 1 to 7, Rob-E.\n"
            "Please type only an integer from 1 to 7, Rob-E.\n",
            "Fails to berate for integers outside of board's range"
        )
        self.assertEqual(
            return_value,
            2,
            "Fails to get correct integer after invalid one"
        )

    @patch('builtins.input', side_effect=["seven", "6"])
    @patch('sys.stdout', new_callable=StringIO)
    def test_with_invalid_int(self, output, inputted_value):
        """
        Ensures that the view properly rejects invalid integers.
        :param inputted_value: strings passed in by mock.patch
        :return: Returns None
        """
        return_value = self.view.get_player_move("Rob-E")
        self.assertEqual(
            output.getvalue(),
            "Please type only an integer from 1 to 7, Rob-E.\n",
            "Fails to berate for strs that cannot be cast as ints"
            )
        self.assertEqual(
            return_value,
            6,
            "Fails to get correct integer after invalid str"
        )
示例#6
0
class StaticPrintStatements(unittest.TestCase):
    """Test that the needed static strings are printed correctly."""
    def setUp(self):
        self.view = View()

    def tearDown(self):
        del self.view

    @patch('sys.stdout', new_callable=StringIO)
    def test_show_instructions(self, output):
        """
        Prints the instructions for how to play the game.
        :return: Returns None
        """

        self.view.show_instructions()

        instructions = "Let's play Connect 4! The first player to connect 4" \
                       "tokens of their color vertically, horizontally, " \
                       "or diagonally, wins. Players will alternate turns " \
                       "dropping checkers into the board, trying their " \
                       "best to win.\n\nOn a player's turn, they will be " \
                       "prompted to enter the column they want their piece " \
                       "dropped into.\n"

        self.assertEqual(instructions, output.getvalue())

    @patch('sys.stdout', new_callable=StringIO)
    def test_declare_sadness(self, output):
        """
        Prints a very sad message that the players have tied.
        :return: Returns None
        """
        self.view.declare_sadness()
        sadness = "Well, you both should be filled with an immense sadness," \
                  " as there is no winner. You have tied.\n"

        self.assertEqual(sadness, output.getvalue())

    @patch('sys.stdout', new_callable=StringIO)
    def test_declare_awesome(self, output):
        """
        Prints that someone is AWESOME, because they won the game.
        :return: Returns None
        """
        self.view.declare_awesome("Vlaad")

        awesome = "Woo! Who's awesome? Vlaad's AWESOME, cause Vlaad won!!\n"

        self.assertEqual(output.getvalue(), awesome)

    @patch('sys.stdout', new_callable=StringIO)
    def test_print_board(self, output):
        board = [['X', 'O', 'X', ' ', ' ',
                  ' '], ['O', 'X', 'O', ' ', ' ', ' '],
                 ['X', 'O', 'X', ' ', ' ',
                  ' '], ['O', 'X', 'O', 'X', ' ', ' '],
                 ['X', 'O', 'X', ' ', ' ',
                  ' '], ['X', 'O', 'X', ' ', ' ', ' '],
                 ['O', 'X', ' ', ' ', ' ', ' ']]

        self.view.print_board(board)

        board_output = "\rConnect 4 Game:\n\n"\
                       "    1 2 3 4 5 6 7 \n"\
                       "   | | | | | | | |\n"\
                       "   | | | | | | | |\n"\
                       "   | | | |X| | | |\n"\
                       "   |X|O|X|O|X|X| |\n"\
                       "   |O|X|O|X|O|O|X|\n"\
                       "   |X|O|X|O|X|X|O|\n"\
                       "   |-------------|\n"\
                       "   -             -\n"

        self.assertEqual(board_output, output.getvalue())