Commits

Karol Nowak committed e0f2687

Cleanup continues - extracted player_id testing logic.

Comments (0)

Files changed (3)

src/lookout/core/game.py

 from lookout.core.travel import TravelManager, ShipArrivedEvent
                
 def LockProtected(f):
+    """Provides mutually exclusive access at the game level"""
     def decorated(*args):
         self = args[0]
         with self.lock:
     return decorated
 
 
+def PlayerIdValidated(f):
+    """Makes sure player_id provided as the first argument is valid in the game"""
+    def decorated(*args):
+        self = args[0]
+        player_id = args[1]
+        if player_id not in self.players:
+            raise LookoutError("Invalid player ID")
+        return f(*args)
+    
+    return decorated
+
+
 class LookoutError(Exception):
     def __init__(self, *args):
         Exception.__init__(self, *args)
         logging.debug("player " + str(player_id) + " transitioned to " + str(new_state))
         self.game.player_states[player_id] = new_state(self.game)
         
-    def is_current_player(self, player_id):
-        raise NotImplementedError()
-    
     def join(self, player_id, player_name):
         raise NotImplementedError()
     
         
     def get_state(self, player_id):
         game = self.game
-        if player_id in game.players:
-            player = game.players[player_id]
-            ship = player.get_ships()[0]
-            planet = ship.location
-            destinations = [(w.other_planet(planet).name, w.distance) for w in planet.connections()]
-            
-            news = list(game.news_queues[player_id])
-            game.news_queues[player_id] = []
-            
-            return {'current_ship': ship.name, 
-                    'current_planet': planet.name,
-                    'destinations': destinations, 
-                    'cash': player.cash,
-                    'goods': game._list_goods(player_id), 
-                    'cargo': game._list_cargo(player_id),
-                    'capacity': (ship.cargo.current_count(), ship.cargo.capacity),
-                    'news': news
-                    }
-        else:
-            raise LookoutError("Unknown player ID: " + str(player_id))
+        player = game.players[player_id]
+        ship = player.get_ships()[0]
+        planet = ship.location
+        destinations = [(w.other_planet(planet).name, w.distance) for w in planet.connections()]
+        
+        news = list(game.news_queues[player_id])
+        game.news_queues[player_id] = []
+        
+        return {'current_ship': ship.name, 
+                'current_planet': planet.name,
+                'destinations': destinations, 
+                'cash': player.cash,
+                'goods': game._list_goods(player_id), 
+                'cargo': game._list_cargo(player_id),
+                'capacity': (ship.cargo.current_count(), ship.cargo.capacity),
+                'news': news
+                }
         
     def end_turn(self, player_id, destination_id):
         game = self.game
-        if player_id in game.players:
-            self._transition_to(player_id, Traveling)
+        self._transition_to(player_id, Traveling)
+        
+        player = game.players[player_id]
+        ship = player.get_ships()[0]
+        planet = ship.location
+        
+        game.active_ships.remove(ship)
+        game.travel_manager.schedule(ship, planet.connections()[int(destination_id)])
+
+        if not game.active_ships:
+            winners = game._check_winners()
+            if winners:
+                return [{'type': 'player_won', 'player_name': player_name} for player_name in winners]
+        
+            game.travel_manager.move_ships()
             
-            player = game.players[player_id]
-            ship = player.get_ships()[0]
-            planet = ship.location
-            
-            game.active_ships.remove(ship)
-            game.travel_manager.schedule(ship, planet.connections()[int(destination_id)])
-
-            if not game.active_ships:
-                winners = game._check_winners()
-                if winners:
-                    return [{'type': 'player_won', 'player_name': player_name} for player_name in winners]
-            
-                game.travel_manager.move_ships()
-                
-            return [{'type': 'end_turn'}]
-        else:
-            return []
+        return [{'type': 'end_turn'}]
         
     def buy(self, player_id, good_id, amount):
         game = self.game
-        if player_id in game.players:
-            player = game.players[player_id]
-            ship = player.get_ships()[0]
-            planet = ship.location
-            
-            good_id = int(good_id)
-            amount = int(amount)
-            
-            goods = [(good, quantity) for good, quantity in planet.get_goods()]
-            
-            if good_id >= len(goods) or good_id < 0:
-                return False
-            
-            good = goods[good_id][0]
-            available = goods[good_id][1]
-            
-            if amount <= 0 or amount > available or amount > ship.cargo.space_left():
-                return False
-            
-            unit_price = planet.buy_price_of(good)
-            
-            if unit_price * amount > player.cash:
-                return False
-            
-            player.cash -= unit_price * amount
-            ship.cargo.add_good(OwnedGood(good, bought_for=unit_price), amount)
-            planet.add_good(good, -amount)
-            
-            return True
-        else:
+        player = game.players[player_id]
+        ship = player.get_ships()[0]
+        planet = ship.location
+        
+        good_id = int(good_id)
+        amount = int(amount)
+        
+        goods = [(good, quantity) for good, quantity in planet.get_goods()]
+        
+        if good_id >= len(goods) or good_id < 0:
             return False
         
+        good = goods[good_id][0]
+        available = goods[good_id][1]
+        
+        if amount <= 0 or amount > available or amount > ship.cargo.space_left():
+            return False
+        
+        unit_price = planet.buy_price_of(good)
+        
+        if unit_price * amount > player.cash:
+            return False
+        
+        player.cash -= unit_price * amount
+        ship.cargo.add_good(OwnedGood(good, bought_for=unit_price), amount)
+        planet.add_good(good, -amount)
+        
+        return True
+        
         
     def sell(self, player_id, good_id, amount):
         game = self.game
         
-        if player_id in game.players:
-            player = game.players[player_id]
-            ship = player.get_ships()[0]
-            planet = ship.location
-            
-            goods = [(good, qty) for good, qty in ship.cargo.get_goods()]
-            
-            good_id = int(good_id)
-            amount = int(amount)
+        player = game.players[player_id]
+        ship = player.get_ships()[0]
+        planet = ship.location
+        
+        goods = [(good, qty) for good, qty in ship.cargo.get_goods()]
+        
+        good_id = int(good_id)
+        amount = int(amount)
 
-            if good_id >= len(goods) or good_id < 0 or amount <= 0 or amount > goods[good_id][1]:
-                return False
-            
-            good = goods[good_id][0]
-            
-            price = planet.sell_price_of(good)
-            
-            player.cash += price * amount
-            ship.cargo.remove_good(good, amount)
-            
-            return True
-        else:
+        if good_id >= len(goods) or good_id < 0 or amount <= 0 or amount > goods[good_id][1]:
             return False
         
+        good = goods[good_id][0]
+        
+        price = planet.sell_price_of(good)
+        
+        player.cash += price * amount
+        ship.cargo.remove_good(good, amount)
+        
+        return True
+        
     def my_turn(self, player_id):
-        if player_id in self.game.players:
-            return [{'type': 'travel_completed_percentage', 'percentage': 100}, ]
+        return [{'type': 'travel_completed_percentage', 'percentage': 100}, ]
         
         
 class Traveling(PlayerState):
         
     def my_turn(self, player_id):
         game = self.game
-        if player_id in self.game.players:
-            ship = game.players[player_id].get_ships()[0]
-            total, left = game.travel_manager.distance_left(ship)
-            
-            if total == 0:
-                percentage = 100 
-            else:
-                percentage = int(float(total - left) / total * 100)
-            
-            if percentage == 100:
-                self._transition_to(player_id, Landing)
-                return [{'type': 'planet_landing', 'mass': 10, 'gravity': 10, 'fuel': 20, 'fuel_usage': 2}]
-            else:
-                return [{'type': 'travel_completed_percentage', 'percentage': percentage}, ]
+        ship = game.players[player_id].get_ships()[0]
+        total, left = game.travel_manager.distance_left(ship)
+        
+        if total == 0:
+            percentage = 100 
+        else:
+            percentage = int(float(total - left) / total * 100)
+        
+        if percentage == 100:
+            self._transition_to(player_id, Landing)
+            return [{'type': 'planet_landing', 'mass': 10, 'gravity': 10, 'fuel': 20, 'fuel_usage': 2}]
+        else:
+            return [{'type': 'travel_completed_percentage', 'percentage': percentage}, ]
 
 
 class Landing(PlayerState):
         if isinstance(event, ShipArrivedEvent):
             self.active_ships.add(event.ship)
                     
-    def is_current_player(self, player_id):
-        try:
-            return self.players[player_id].get_ships()[0] in self.active_ships
-        except KeyError:
-            return False 
-    
-    # FIXME
     @LockProtected
     def join(self, player_id, player_name):
         return JoiningGame(self).join(player_id, player_name)
 
     @LockProtected
+    @PlayerIdValidated
     def my_turn(self, player_id):
         return self.player_states[player_id].my_turn(player_id)
     
     @LockProtected
+    @PlayerIdValidated
     def get_state(self, player_id):
         return self.player_states[player_id].get_state(player_id)
  
         """Returns the list of player names that have won the game, empty if non has so far."""
         return [player.name for player in self.players.values() if player.cash >= self.cash_to_win] 
     
-    @LockProtected        
+    @LockProtected
+    @PlayerIdValidated   
     def end_turn(self, player_id, destination_id):
         return self.player_states[player_id].end_turn(player_id, destination_id)
                     
     @LockProtected
+    @PlayerIdValidated
     def buy(self, player_id, good_id, amount):
         return self.player_states[player_id].buy(player_id, good_id, amount)
 
-    @LockProtected        
+    @LockProtected    
+    @PlayerIdValidated    
     def sell(self, player_id, good_id, amount):
         return self.player_states[player_id].sell(player_id, good_id, amount)
         
     @LockProtected
+    @PlayerIdValidated
     def crashed(self, player_id):
         return self.player_states[player_id].crashed(player_id)
 
     @LockProtected
+    @PlayerIdValidated
     def landed(self, player_id):
         return self.player_states[player_id].landed(player_id)
     

src/lookout/core/tests/test_game.py

         
 def test_invalid_player_responses():
     game = Game("test game")
-    assert game.buy("invalid", "whatever", "whatever") is False
-    assert game.sell("invalid", "whatever", "whatever") is False
-    assert game.end_turn("invalid", "whatever") == []
+    
+    with Raises(LookoutError):
+        game.buy("invalid", "whatever", "whatever")
+        
+    with Raises(LookoutError):
+        game.sell("invalid", "whatever", "whatever")
+        
+    with Raises(LookoutError):
+        game.end_turn("invalid", "whatever")
     
     with Raises(LookoutError):
         game.get_state("invalid")
+        
+    with Raises(LookoutError):
+        game.crashed("invalid")
+        
+    with Raises(LookoutError):
+        game.landed("invalid")
+        
+    with Raises(LookoutError):
+        game.my_turn("invalid")
 
     
 def test_join_when_username_taken():
     # then
     assert response[0]['type'] == 'travel_completed_percentage'
     assert response[0]['percentage'] == 100
+
     
-    assert response[1]['type'] == 'planet_landing'
-    assert 'mass' in response[1] and 'gravity' in response[1] and 'fuel' in response[1] and 'fuel_usage' in response[1]
-
-
 def test_get_state():
     # given
     game = Game("test game")

src/lookout/core/tests/test_world.py

 from mockito import verify
 
 from lookout.core.trade import Good
-from lookout.core.world import Planet, Wormhole, NewDayEvent, World
+from lookout.core.world import Planet, Wormhole, World
 from lookout.testing.support import Raises 
 
 def test_connecting_planets():
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.