コード例 #1
0
 def parse_and_decode(cls, data: bytes) -> "InvalidMove":
     if len(data) < cls.calc_size() + 1:
         raise NotEnoughData()
     if data[0] != cls.type:
         raise InvalidType()
     res = unpack('<' + cls.fmt, data[1:cls.calc_size() + 1])
     return cls(Move.from_bytes(res[0]), Board.from_bytes(res[1]))
コード例 #2
0
 def test_get_required_moves(self):
     b = Board([BoardLocation(False, False, False)] * 64)
     b[0, 2] = BoardLocation(True, True, True)
     b[1, 3] = BoardLocation(True, True, False)
     self.assertListEqual([Move(0, 2, Direction.Positive, Direction.Positive)],
                          b.get_required_moves(Direction.Positive, True))
     self.assertListEqual([], b.get_required_moves(Direction.Positive, False))
コード例 #3
0
    def __init__(self, player_one: "Session", player_two: "Session",
                 logger: Logger):
        """
        A Game takes two players, assign the one with lower rating to be player one and go first
        Also generate a default board start
        :param player_one: The first player in the game
        :param player_two: The second player in the game
        """
        if player_one.username == player_two.username:
            logger.warning(
                "Attempting to start game between two of {user}".format(
                    user=player_one.username))
            raise InvalidGameException()
        if player_one.rating < player_two.rating:
            self.__player_one = player_one
            self.__player_two = player_two
        else:
            self.__player_one = player_two
            self.__player_two = player_one
        self.__logger = logger
        self.__board = Board.generate_game_start()
        self.game_active = True
        player_one.on_game_start(player_two.username, player_two.rating, self)
        player_two.on_game_start(player_one.username, player_one.rating, self)

        self.__next_to_go = self.__player_one
        # Request a move from the first player
        self.__next_to_go.on_request_move(
            Move(0, 0, Direction.Negative, Direction.Negative), self.__board)
コード例 #4
0
    def get_move(self) -> Move:
        def get_location():
            try:
                x = int(input("X value for piece to move:"))
                y = int(input("Y value for piece to move:"))
                return x - 1, y - 1
            except ValueError:
                self.display_message("Please enter values from 1-8")
                return get_location()

        def get_direction():
            def get_x_dir():
                first_input = input("Would you like to move the piece left or right? (left/right): ")
                if first_input == "left":
                    return Direction.Negative
                elif first_input == "right":
                    return Direction.Positive
                else:
                    return get_x_dir()

            def get_y_dir():
                first_input = input("Would you like to move the piece up or down? (up/down): ")
                if first_input == "up":
                    return Direction.Negative
                elif first_input == "down":
                    return Direction.Positive
                else:
                    return get_y_dir()

            return get_x_dir(), get_y_dir()

        return Move(*get_location(), *get_direction())
コード例 #5
0
 def test_game_over(self):
     b = Board([BoardLocation(False, False, False)] * 64)
     b[0, 2] = BoardLocation(True, True, True)
     b[1, 3] = BoardLocation(True, True, False)
     self.assertFalse(b.check_game_over(True))
     self.assertFalse(b.check_game_over(False))
     b.apply_move(Move(0, 2, Direction.Positive, Direction.Positive), Direction.Negative, True)
     self.assertTrue(b.check_game_over(True))
     self.assertFalse(b.check_game_over(False))
コード例 #6
0
    def __msg_on_processing_game_state(self, msg: Message):
        """
        Logic to do while in the Processing Game State state
        :param msg: Message received
        """
        if isinstance(msg, YourTurn):
            # This is the edge of the DFA from Processing Game State -> User Move (Your Turn)
            self.__protocol_state = ProtocolState.USER_MOVE
            # Check if this is the beginning of the game
            if msg.last_move == Move(0, 0, Direction.Negative,
                                     Direction.Negative):
                self.__ui.display_message("You go first!")
            else:
                self.__ui.display_message("Last Move was : {move}".format(
                    move=msg.last_move.__repr__()))
            self.__ui.display(msg.board)
            self.__send(MakeMove(self.__ui.get_move()))
            self.__protocol_state = ProtocolState.PROCESSING_GAME_STATE
        elif isinstance(msg, CompulsoryMove):
            # This is the edge of the DFA from Processing Game State -> Processing Game State (Compulsory Move)
            self.__ui.display_message(
                "Compulsory Move: {move}".format(move=msg.move.__repr__()))
            self.__ui.display(msg.board)
        elif isinstance(msg, InvalidMove):
            # This is the edge of the DFA from Processing Game State -> User Move (Invalid Move)
            self.__protocol_state = ProtocolState.USER_MOVE
            self.__ui.display_message(
                "{move} Is an invalid move".format(move=msg.move.__repr__()))
            self.__ui.display(msg.board)
            self.__send(MakeMove(self.__ui.get_move()))
            self.__protocol_state = ProtocolState.PROCESSING_GAME_STATE
        elif isinstance(msg, GameOver):
            # This is the edge of the DFA from Processing Game State -> Game End (Game Over)
            self.__protocol_state = ProtocolState.GAME_END
            self.__ui.game_over(msg.board, msg.old_rating, msg.new_rating,
                                msg.you_won != 0)
            if self.__ui.prompt_play_again():
                self.__protocol_state = ProtocolState.IN_QUEUE
                self.__send(ReQueue())
            else:
                self.shutdown()

        elif isinstance(msg, OpponentDisconnect):
            # This is the edge of the DFA from Processing Game State -> Game End (Opponent Disconnect)
            self.__protocol_state = ProtocolState.GAME_END
            self.__ui.opponent_left()
            if self.__ui.prompt_play_again():
                self.__protocol_state = ProtocolState.IN_QUEUE
                self.__send(ReQueue())
            else:
                self.shutdown()
        else:
            self.__logger.fatal(
                "Received invalid message of type {type} for state {state}".
                format(type=msg.__class__.__name__,
                       state=self.__protocol_state.name))
            self.shutdown()
コード例 #7
0
 def test_game_over_message(self):
     move = Move(1, 2, Direction.Positive, Direction.Positive)
     board = Board([BoardLocation(True, False, True)] * 64)
     m = GameOver(0xFF, 1338, 1337, move, board)
     self.assertEqual(0xFF, m.you_won)
     self.assertEqual(1338, m.new_rating)
     self.assertEqual(1337, m.old_rating)
     self.assertEqual(move, m.winning_move)
     self.assertEqual(board, m.board)
コード例 #8
0
 def test_move(self):
     m = Move(1, 2, Direction.Negative, Direction.Positive)
     self.assertEqual(m.to_bytes(), b"\x29")
     self.assertEqual(m.to_bytes(), Move.from_bytes(m.to_bytes()).to_bytes())
     self.assertEqual(m.x_pos, 1)
     self.assertEqual(m.y_pos, 2)
     self.assertEqual(m.x_direction, Direction.Negative)
     self.assertEqual(m.y_direction, Direction.Positive)
     self.assertEqual((1, 2), m.pos)
     self.assertEqual((0, 3), m.after_move_pos)
     self.assertEqual((-1, 4), m.after_double_move_pos)
     self.assertEqual("(2, 3) -> (1, 4)", m.__repr__())
コード例 #9
0
    def apply_move(self, move: Move, user: "******"):
        """
        Apply a Move, raise InvalidMoveException if the move is invalid.
        Process internal state until user input is again needed
        :param move: The move to apply
        :param user: The user that made the move
        """
        self.__logger.info("{user} is trying to apply move {move}".format(
            user=user.username, move=move.__repr__()))
        # If it is an invalid move for that user
        if self.__next_to_go != user:
            self.__logger.info(
                "{user} failed to apply a move because it was not their turn".
                format(user=user.username))
            raise InvalidMoveException()
        allowed_y_direction = self.__get_allowed_direction(user)
        is_primary_player = self.__is_primary(user)
        # Try applying the move to the lower level Board type, raise InvalidMoveException if it fails
        try:
            self.__board.apply_move(move, allowed_y_direction,
                                    is_primary_player)
        except InvalidMove:
            raise InvalidMoveException()

        # After applying the move, switch to the next player

        self.__next_to_go = self.__get_opponent(user)
        # Process game state (making compulsory moves and switching players turns as needed)

        last_move = self.__process_game_state()
        # The last move made was either the one process_game_state returned or the one the last user made
        last_move = last_move or move
        # Check if either player won
        if self.__board.check_game_over(True):
            self.__finish_game(self.__player_one, last_move)
        elif self.__board.check_game_over(False):
            self.__finish_game(self.__player_two, last_move)
        else:
            # Lastly, get a move from whichever player needs to go next
            self.__next_to_go.on_request_move(
                last_move, self.get_board(self.__next_to_go))
コード例 #10
0
    def test_apply_move(self):
        b = Board.generate_game_start()
        b.apply_move(Move(0, 2, Direction.Positive, Direction.Positive), Direction.Positive, False)
        self.assertEqual(BoardLocation(False, False, False), b[0, 2])
        self.assertEqual(BoardLocation(True, False, False), b[1, 3])
        with self.assertRaises(InvalidMove):
            # Try moving a piece that doesn't exist
            b.apply_move(Move(0, 2, Direction.Positive, Direction.Positive), Direction.Positive, False)
        with self.assertRaises(InvalidMove):
            # Try jumping your own piece
            b.apply_move(Move(0, 0, Direction.Positive, Direction.Positive), Direction.Positive, False)
        # Move a piece right
        b.apply_move(Move(1, 3, Direction.Positive, Direction.Positive), Direction.Positive, False)
        # Move a piece left
        b.apply_move(Move(2, 2, Direction.Negative, Direction.Positive), Direction.Positive, False)
        with self.assertRaises(InvalidMove):
            # Try moving a piece the wrong direction
            b.apply_move(Move(1, 3, Direction.Positive, Direction.Negative), Direction.Positive, False)
        with self.assertRaises(InvalidMove):
            # Try moving an opponent's piece
            b.apply_move(Move(3, 5, Direction.Negative, Direction.Negative), Direction.Positive, False)
        b.apply_move(Move(1, 3, Direction.Negative, Direction.Positive), Direction.Positive, False)
        # Jump!
        b.apply_move(Move(3, 5, Direction.Negative, Direction.Negative), Direction.Negative, True)
        # Cheat a little bit to delete some pieces and check that promotion works
        b[2, 6] = BoardLocation(True, False, False)
        b[3, 7] = BoardLocation(False, False, False)
        # Move to the edge and promote
        b.apply_move(Move(2, 6, Direction.Positive, Direction.Positive), Direction.Positive, False)
        self.assertTrue(b[3, 7].promoted)

        # Cheat a little to check moving to the bottom
        b[4, 2] = BoardLocation(True, False, True)
        b[2, 0] = BoardLocation(False, False, False)
        b.apply_move(Move(4, 2, Direction.Negative, Direction.Negative), Direction.Negative, True)
        self.assertTrue(b[2, 0].promoted)

        # Try to move out of bounds
        with self.assertRaises(InvalidMove):
            b.apply_move(Move(2, 0, Direction.Negative, Direction.Negative), Direction.Negative, True)
コード例 #11
0
 def test_get_all_moves(self):
     b = Board([BoardLocation(False, False, False)] * 64)
     b[0, 2] = BoardLocation(True, True, True)
     self.assertListEqual(
         [Move(0, 2, Direction.Positive, Direction.Positive), Move(0, 2, Direction.Positive, Direction.Negative)],
         b.get_possible_moves(Direction.Negative, True))
コード例 #12
0
class TestAllMessages(TestCase):
    messages_to_test = [
        (Connect, [1, b"username", b"password"],
         b"\x01\x01username\x00\x00\x00\x00\x00\x00\x00\x00password\x00\x00\x00\x00\x00\x00\x00\x00"
         ),
        (InvalidLogin, [InvalidLogin.Reasons.AccountDoesNotExist],
         b"\x02\x00"),
        (InvalidVersion, [1, 2], b"\x0D\x01\x02"),
        (QueuePosition, [1, 2, 3],
         b"\x03\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00"),
        (GameStart, [b"opponent", 16],
         b'\x04opponent\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00'),
        (YourTurn, [
            Move(1, 2, Direction.Positive, Direction.Negative),
            Board([BoardLocation(True, False, True)] * 64)
        ],
         b"\x05*\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm"
         ),
        (MakeMove, [Move(2, 1, Direction.Negative,
                         Direction.Positive)], b"\x06\x45"),
        (CompulsoryMove, [
            Move(1, 2, Direction.Positive, Direction.Negative),
            Board([BoardLocation(True, False, True)] * 64)
        ],
         b"\x07*\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm"
         ),
        (InvalidMove, [
            Move(1, 2, Direction.Positive, Direction.Negative),
            Board([BoardLocation(True, False, True)] * 64)
        ],
         b"\x08*\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm"
         ),
        (OpponentDisconnect, [], b"\x09"),
        (GameOver, [
            255, 2, 1,
            Move(1, 2, Direction.Positive, Direction.Negative),
            Board([BoardLocation(True, False, True)] * 64)
        ],
         b"\n\xff\x02\x00\x00\x00\x01\x00\x00\x00*\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm\xb6\xdbm"
         ),
        (ReQueue, [], b"\x0B"),
        (LogOut, [], b"\x0C"),
    ]

    def test_messages(self):
        for constructor, args, packed in TestAllMessages.messages_to_test:
            obj = constructor(*args)
            self.assertEqual(packed,
                             obj.encode(),
                             msg="packed vs encode for {}".format(
                                 constructor.__name__))
            self.assertEqual(obj.encode(),
                             constructor.parse_and_decode(packed).encode(),
                             msg="encode vs repack for {}".format(
                                 constructor.__name__))
            self.assertEqual(obj.__dict__,
                             constructor.parse_and_decode(packed).__dict__,
                             msg="compare dict for {}".format(
                                 constructor.__name__))
            with self.assertRaises(
                    NotEnoughData,
                    msg="Message {} still works with too little data".format(
                        constructor.__name__)):
                constructor.parse_and_decode(packed[:-1])
            with self.assertRaises(
                    InvalidType,
                    msg="Message {} still works with wrong type number".format(
                        constructor.__name__)):
                constructor.parse_and_decode(b'\x00' + packed[1:])

    def test_strip(self):
        self.assertEqual(bytes_strip(b"abc\x00"), b"abc")
        self.assertEqual(bytes_strip(b"abc"), b"abc")

    def test_connect_message(self):
        m = Connect(1, b"cameron", b"password")
        self.assertEqual(1, m.version)
        self.assertEqual(b"cameron", m.username)
        self.assertEqual(b"password", m.password)

    def test_invalid_login_message(self):
        m = InvalidLogin(InvalidLogin.Reasons.AccountDoesNotExist)
        self.assertEqual(InvalidLogin.Reasons.AccountDoesNotExist, m.reason)

    def test_invalid_version_message(self):
        m = InvalidVersion(3, 2)
        self.assertEqual(3, m.highest_supported_version)
        self.assertEqual(2, m.lowest_supported_version)

    def test_queue_position_message(self):
        m = QueuePosition(3, 2, 1337)
        self.assertEqual(3, m.queue_size)
        self.assertEqual(2, m.queue_pos)
        self.assertEqual(1337, m.rating)

    def test_game_start_message(self):
        m = GameStart(b"opp", 24)
        self.assertEqual(b"opp", m.opponent_name)
        self.assertEqual(24, m.opponent_rating)

    def test_your_turn_message(self):
        move = Move(1, 2, Direction.Positive, Direction.Positive)
        board = Board([BoardLocation(True, False, True)] * 64)
        m = YourTurn(move, board)
        self.assertEqual(move, m.last_move)
        self.assertEqual(board, m.board)

    def test_make_move_message(self):
        move = Move(1, 2, Direction.Positive, Direction.Positive)
        m = MakeMove(move)
        self.assertEqual(move, m.move)

    def test_compulsory_move_message(self):
        move = Move(1, 2, Direction.Positive, Direction.Positive)
        board = Board([BoardLocation(True, False, True)] * 64)
        m = CompulsoryMove(move, board)
        self.assertEqual(move, m.move)
        self.assertEqual(board, m.board)

    def test_invalid_move_message(self):
        move = Move(1, 2, Direction.Positive, Direction.Positive)
        board = Board([BoardLocation(True, False, True)] * 64)
        m = InvalidMove(move, board)
        self.assertEqual(move, m.move)
        self.assertEqual(board, m.board)

    def test_opponent_disconnect_message(self):
        m = OpponentDisconnect()
        # No fields to test

    def test_game_over_message(self):
        move = Move(1, 2, Direction.Positive, Direction.Positive)
        board = Board([BoardLocation(True, False, True)] * 64)
        m = GameOver(0xFF, 1338, 1337, move, board)
        self.assertEqual(0xFF, m.you_won)
        self.assertEqual(1338, m.new_rating)
        self.assertEqual(1337, m.old_rating)
        self.assertEqual(move, m.winning_move)
        self.assertEqual(board, m.board)

    def test_re_queue_message(self):
        m = ReQueue()
        # no fields to test

    def test_log_out_message(self):
        m = LogOut()
コード例 #13
0
 def test_invalid_move_message(self):
     move = Move(1, 2, Direction.Positive, Direction.Positive)
     board = Board([BoardLocation(True, False, True)] * 64)
     m = InvalidMove(move, board)
     self.assertEqual(move, m.move)
     self.assertEqual(board, m.board)
コード例 #14
0
 def test_make_move_message(self):
     move = Move(1, 2, Direction.Positive, Direction.Positive)
     m = MakeMove(move)
     self.assertEqual(move, m.move)
コード例 #15
0
 def test_your_turn_message(self):
     move = Move(1, 2, Direction.Positive, Direction.Positive)
     board = Board([BoardLocation(True, False, True)] * 64)
     m = YourTurn(move, board)
     self.assertEqual(move, m.last_move)
     self.assertEqual(board, m.board)