def test_cull_dead(self):
     "Culls disconnected/dead games"
     (gid, pid) = b.new_game(b"")
     self.assertIn(gid, b.games)
     b.disconnect(pid)
     b.new_game(b"")
     self.assertNotIn(gid, b.games)
 def test_no_cull_below_maxgames(self):
     "Doesn't cull old games when fewer than maxgames games exist"
     for i in range(b._maxgames - 2):
         b.new_game(b"")
     time.sleep(b._timeout + 1)
     b.new_game(b"")
     # Games should still be in b.games
     self.assertEqual(len(b.games), b._maxgames)
 def test_cull_notifications(self):
     "Culling responds to notifications"
     for i in range(b._maxgames):
         b.new_game(b"")
     (gid, pid) = b.new_game(b"")
     b.request_notify(pid, b.PlayerState.GAME_OVER, None)
     b.request_notify(pid, b.PlayerState.SUBMIT_GRID, None)
     self.assertIn(pid, b.pending_notifications)
     time.sleep(b._timeout + 1)
     b.new_game(b"")
     # The game should have been culled and no dangling
     # notifications should be left
     self.assertNotIn(pid, b.pending_notifications)
 def test_join_twice(self):
     "join_game fails when you try to join twice"
     (gid, pid) = b.new_game(Nicks.testNick)
     b.join_game(gid, Nicks.testNick2)
     b.join_game(gid, Nicks.testNick2)
     self.assertEqual(b.join_game(gid, Nicks.testNick2),
                      b.Error.ALREADY_STARTED)
    def test_normal_game(self):
        "state_codes are correct during a normal game, where one player wins"
        (gid, pid1) = b.new_game(Nicks.testNick)
        me = b.players[pid1]
        self.assertEqual(me.state_code, b.PlayerState.WAIT_FOR_JOIN)
        pid2 = b.join_game(gid, Nicks.testNick2)
        other = b.players[pid2]
        self.assertEqual(me.state_code, b.PlayerState.SUBMIT_GRID)
        self.assertEqual(other.state_code, b.PlayerState.SUBMIT_GRID)

        # they both submit the same grid, for simplicity
        b.submit_grid(pid1, [[0, 0, 1, 0], [0, 1, 2, 1], [0, 2, 2, 2],
                             [0, 3, 3, 3], [0, 4, 4, 4]])
        self.assertEqual(me.state_code, b.PlayerState.WAIT_FOR_SUBMIT)
        b.submit_grid(pid2, [[0, 0, 1, 0], [0, 1, 2, 1], [0, 2, 2, 2],
                             [0, 3, 3, 3], [0, 4, 4, 4]])
        self.assertEqual(me.state_code, b.PlayerState.BOMB)
        self.assertEqual(other.state_code, b.PlayerState.WAIT_FOR_BOMB)

        # here, we just play out some turns, with me bombing each of
        # their ships while they bomb an empty space
        for (x, y) in other.ship_points:
            b.bomb_position(pid1, x, y)
            b.bomb_position(pid2, 5, 5)

        # game should be over
        self.assertEqual(me.state_code, b.PlayerState.GAME_OVER)
        self.assertEqual(other.state_code, b.PlayerState.GAME_OVER)

        # we should have won
        self.assertEqual(b.get_game_end(pid1), (other.grid, 1, 1))

        # they should have lost
        self.assertEqual(b.get_game_end(pid2), (me.grid, 1, 0))
 def test_submit_early(self):
     "submit_grid fails when called too early"
     (gid, pid) = b.new_game(Nicks.testNick)
     self.assertEqual(
         b.submit_grid(pid, [[0, 0, 1, 0], [0, 1, 2, 1], [0, 2, 2, 2],
                             [0, 3, 3, 3], [0, 4, 4, 4]]),
         b.Error.NO_OPPONENT)
    def test_submit_invalid(self):
        "submit_grid fails with bad grids"
        # game starts, other player joins, we place first
        (gid, pid) = b.new_game(Nicks.testNick)

        otherpid = b.join_game(gid, Nicks.testNick2)
        # empty grid
        self.assertEqual(b.submit_grid(pid, []), b.Error.INVALID_GRID)
        # too few ships
        self.assertEqual(b.submit_grid(pid, [[0, 0, 1, 0], [0, 1, 0, 3]]),
                         b.Error.INVALID_GRID)
        # ships overlap but otherwise valid
        self.assertEqual(
            b.submit_grid(pid, [[0, 0, 1, 0], [0, 0, 2, 0], [0, 0, 2, 0],
                                [0, 0, 3, 0], [0, 0, 4, 0]]),
            b.Error.INVALID_GRID)
        # ship is rectangle, not line
        self.assertEqual(
            b.submit_grid(pid, [[0, 0, 1, 0], [0, 1, 2, 1], [0, 2, 2, 2],
                                [0, 3, 3, 3], [0, 4, 4, 5]]),
            b.Error.INVALID_GRID)
        # ok grid, bad pid
        self.assertEqual(
            b.submit_grid(pid + 100, [[0, 0, 1, 0], [0, 1, 2, 1], [0, 2, 2, 2],
                                      [0, 3, 3, 3], [0, 4, 4, 4]]),
            b.Error.INVALID_PLYR_ID)
        # this should work
        self.assertEqual(
            b.submit_grid(pid, [[0, 0, 1, 0], [0, 1, 2, 1], [0, 2, 2, 2],
                                [0, 3, 3, 3], [0, 4, 4, 4]]), 0)
        # but you can't submit twice
        self.assertEqual(
            b.submit_grid(pid, [[0, 0, 1, 0], [0, 1, 2, 1], [0, 2, 2, 2],
                                [0, 3, 3, 3], [0, 4, 4, 4]]),
            b.Error.OUT_OF_TURN)
 def test_notify_immediate_join(self):
     "Player gets notified immediately when other player is already in game"
     (gid, pid) = b.new_game(Nicks.testNick)
     b.join_game(gid, Nicks.testNick2)
     b.request_notify(pid, b.PlayerState.SUBMIT_GRID, None)
     # the notification should never have been registered at all
     self.assertFalse(
         pid in b.pending_notifications and
         (b.PlayerState.SUBMIT_GRID, None) in b.pending_notifications[pid])
 def test_join_full(self):
     "Player.join fails if game is full"
     # note: this should never happen if the user uses the API
     # provided. join_game checks and returns an error before the
     # join call reaches the player.
     (gid, pid) = b.new_game(Nicks.testNick)
     b.join_game(gid, Nicks.testNick2)
     with self.assertRaises(b.GameFullException):
         b.players[pid].join(b.games[gid])
Beispiel #10
0
 def test_disconnect_notifies(self):
     "Opponent is notified when you disconnect"
     (gid, pid1) = b.new_game(b"")
     pid2 = b.join_game(gid, b"")
     b.request_notify(pid2, b.PlayerState.GAME_DIED, None)
     self.assertIn(pid2, b.pending_notifications)
     self.assertIn(b.PlayerState.GAME_DIED,
                   [state for (state, x) in b.pending_notifications[pid2]])
     b.disconnect(pid1)
     # Check notification has been responded to
     self.assertNotIn(
         b.PlayerState.GAME_DIED,
         [state for (state, x) in b.pending_notifications[pid2]])
Beispiel #11
0
 def test_no_early_cull_dead(self):
     "Don't cull games before _both_ players leave"
     (gid, pid1) = b.new_game(b"")
     pid2 = b.join_game(gid, b"")
     self.assertIn(gid, b.games)
     b.disconnect(pid1)
     b.cull_inactive()
     # 1 player left: game should not be culled
     self.assertIn(gid, b.games)
     b.disconnect(pid2)
     b.cull_inactive()
     # 2 players left: should have been culled
     self.assertNotIn(gid, b.games)
Beispiel #12
0
 def test_notify_delayed_join(self):
     "Player gets notified when other player joins after some time"
     (gid, pid) = b.new_game(Nicks.testNick)
     b.request_notify(pid, b.PlayerState.SUBMIT_GRID, None)
     # notification has been registered as waiting
     self.assertTrue(pid in b.pending_notifications)
     self.assertTrue(b.PlayerState.SUBMIT_GRID in
                     [x for (x, y) in b.pending_notifications[pid]])
     b.join_game(gid, Nicks.testNick2)
     # now the notification should be gone. As per above, we assume
     # it was responded to
     self.assertFalse(
         pid in b.pending_notifications and
         (b.PlayerState.SUBMIT_GRID, None) in b.pending_notifications[pid])
Beispiel #13
0
    def test_bomb_history(self):
        "get_bomb_history fails with bad args but is correct otherwise"
        self.assertEqual(b.get_bombed_positions(123),
                         (b.Error.INVALID_PLYR_ID, 0, []))
        (gid, pid1) = b.new_game(Nicks.testNick)
        pid2 = b.join_game(gid, Nicks.testNick2)
        b.submit_grid(pid1, [[0, 0, 1, 0], [0, 1, 2, 1], [0, 2, 2, 2],
                             [0, 3, 3, 3], [0, 4, 4, 4]])
        b.submit_grid(pid2, [[0, 0, 1, 0], [0, 1, 2, 1], [0, 2, 2, 2],
                             [0, 3, 3, 3], [0, 4, 4, 4]])
        b.bomb_position(pid1, 0, 0)
        b.bomb_position(pid2, 0, 4)
        b.bomb_position(pid1, 0, 1)

        self.assertEqual(b.get_bombed_positions(pid1), (0, 1, [0, 4]))
        self.assertEqual(b.get_bombed_positions(pid2), (0, 2, [0, 0, 0, 1]))
Beispiel #14
0
 def test_bomb_pos_invalid(self):
     "bomb_position fails with bad arguments or if called too early"
     # bad pid
     self.assertEqual(b.bomb_position(123, 0, 0), b.Error.INVALID_PLYR_ID)
     (gid, pid1) = b.new_game(Nicks.testNick)
     # before opponent joins
     self.assertEqual(b.bomb_position(pid1, 0, 0), b.Error.NO_OPPONENT)
     pid2 = b.join_game(gid, Nicks.testNick2)
     # before the bombing phase starts
     self.assertEqual(b.bomb_position(pid1, 0, 0), b.Error.OUT_OF_TURN)
     # players submit grid
     b.submit_grid(pid1, [[0, 0, 1, 0], [0, 1, 2, 1], [0, 2, 2, 2],
                          [0, 3, 3, 3], [0, 4, 4, 4]])
     b.submit_grid(pid2, [[0, 0, 1, 0], [0, 1, 2, 1], [0, 2, 2, 2],
                          [0, 3, 3, 3], [0, 4, 4, 4]])
     # bad position
     self.assertEqual(b.bomb_position(pid1, 100, 100),
                      b.Error.INVALID_BOMB_TARGET)
     # this should work and hit
     self.assertEqual(b.bomb_position(pid1, 0, 0), 1)
Beispiel #15
0
 def test_multiple_notifications(self):
     "Player waiting for multiple states is notified correctly"
     (gid, pid) = b.new_game(Nicks.testNick)
     # we wait for the same thing twice: both should be responded
     # to at the same time
     b.request_notify(pid, b.PlayerState.SUBMIT_GRID, None)
     b.request_notify(pid, b.PlayerState.SUBMIT_GRID, None)
     self.assertTrue(pid in b.pending_notifications)
     self.assertTrue(2, [x for (x, y) in b.pending_notifications[pid]
                         ].count(b.PlayerState.SUBMIT_GRID))
     # we also wait for something else: this should not be
     # responded to at the same time as the others
     b.request_notify(pid, b.PlayerState.BOMB, None)
     self.assertTrue(b.PlayerState.BOMB in
                     [x for (x, y) in b.pending_notifications[pid]])
     b.join_game(gid, Nicks.testNick2)
     # wait for join notifications should be gone
     self.assertFalse(
         pid in b.pending_notifications and
         (b.PlayerState.SUBMIT_GRID, None) in b.pending_notifications[pid])
     # bomb notifications should still be here
     self.assertTrue(b.PlayerState.BOMB in
                     [x for (x, y) in b.pending_notifications[pid]])
Beispiel #16
0
 def test_new_game(self):
     "new_game generates a valid gid and pid"
     (gid, pid) = b.new_game(Nicks.testNick)
     self.assertTrue(gid in b.games)
     self.assertTrue(pid in b.players)
Beispiel #17
0
 def test_get_game_end(self):
     "get_game_end fails when called inappropriately"
     # before opponent joins (but we have)
     (gid, pid) = b.new_game(Nicks.testNick)
Beispiel #18
0
 def test_get_plyr_state(self):
     "get_plyr_state succeeds if pid is valid"
     (gid, pid) = b.new_game(Nicks.testNick)
     self.assertEqual(b.get_plyr_state(pid), b.players[pid].state_code)
Beispiel #19
0
 def test_get_opponent_nickname(self):
     "get_opponent_nickname works"
     (gid, pid) = b.new_game(Nicks.testNick)
     pid2 = b.join_game(gid, Nicks.testNick2)
     self.assertEqual(Nicks.testNick, b.get_opponent_nickname(pid2))
     self.assertEqual(Nicks.testNick2, b.get_opponent_nickname(pid))
Beispiel #20
0
 def test_join_invalid(self):
     "join_game fails with invalid gid"
     (gid, pid) = b.new_game(Nicks.testNick)
     self.assertEqual(b.join_game(gid + 1, Nicks.testNick2),
                      b.Error.NO_SUCH_GAME)
Beispiel #21
0
 def test_cull_inactive_normal(self):
     for i in range(b._maxgames + 1):
         b.new_game(b"")
     time.sleep(b._timeout + 1)
     b.new_game(b"")
     self.assertEqual(len(b.games), 1)