Save player mode.
[naja.git] / naja / gameboard.py
index 2d138b2dbe74fceb3bf313fca5eaf05755b2f22b..8a1daa7673b28d34dc1c264f5c5d0c3b3b3d5325 100644 (file)
@@ -3,6 +3,7 @@ from random import choice
 from naja.constants import(
     BITS, DIRECTION_BITS, CONDITION_BITS, PLAYER_DEFAULTS,
     ACT, EXAMINE, ROTATION)
+from naja.options import options
 from naja.player import Player
 from naja import actions
 
@@ -18,26 +19,30 @@ class GameBoard(object):
         self.health = state['health']
         self.wins = state['wins']
         self.locations = [item.copy() for item in state['locations']]
+        self.puzzle = state.get('puzzle', False)
         self.player = player
         self.board_locations = board_locations
-        self.player_mode = EXAMINE
+        self.player_mode = state.get('player_mode', EXAMINE)
 
     @classmethod
-    def new_game(cls, locations_definition,
+    def new_game(cls, deck,
                  initial_bits=PLAYER_DEFAULTS.INITIAL_BITS,
                  initial_pos=PLAYER_DEFAULTS.INITIAL_POS,
                  max_health=PLAYER_DEFAULTS.MAX_HEALTH,
                  wins_required=PLAYER_DEFAULTS.WINS_REQUIRED):
+        if options.initial_bits:
+            initial_bits = options.initial_bits
         state = {
             'max_health': max_health,
             'health': max_health,
             'wins_required': wins_required,
             'wins': 0,
-            'locations': locations_definition,
+            'locations': deck['cards'],
+            'puzzle': deck.get('puzzle', False),
         }
         player = Player(initial_bits, initial_pos)
         board_locations = cls.import_board_locations(
-            cls.generate_board(locations_definition))
+            cls.generate_board(deck))
         return cls(state, player, board_locations)
 
     @classmethod
@@ -55,8 +60,10 @@ class GameBoard(object):
             'wins_required': self.wins_required,
             'wins': self.wins,
             'locations': [item.copy() for item in self.locations],
+            'puzzle': self.puzzle,
             'player': self.player.export(),
             'board_locations': self.export_board_locations(),
+            'player_mode': self.player_mode,
         }
 
     @classmethod
@@ -66,24 +73,41 @@ class GameBoard(object):
             for definition in locations_definition]
 
     def export_board_locations(self):
-        return dict(
+        return sorted(
             (position, location.export())
             for position, location in self.board_locations.iteritems())
 
     @classmethod
     def import_board_locations(cls, board_locations_definition):
         return dict(
-            (position, LocationCard.import_location(definition))
-            for position, definition in board_locations_definition.iteritems())
+            (tuple(position), LocationCard.import_location(definition))
+            for position, definition in board_locations_definition)
+
+    @classmethod
+    def generate_board(cls, deck):
+        if deck.get('puzzle', False):
+            return cls.generate_puzzle_board(deck)
+        else:
+            return cls.generate_random_board(deck)
+
+    @classmethod
+    def generate_puzzle_board(cls, deck):
+        assert len(deck['cards']) == 5 * 5
+        board_locations = [
+            [(i % 5, i // 5),
+             LocationCard.new_location(card.copy()).export()]
+            for i, card in enumerate(deck['cards'])
+        ]
+        return board_locations
 
     @classmethod
-    def generate_board(cls, locations_definition):
-        board_locations = {}
+    def generate_random_board(cls, deck):
+        board_locations = []
         for x in range(5):
             for y in range(5):
                 board_location = LocationCard.new_location(
-                    choice(locations_definition).copy())
-                board_locations[(x, y)] = board_location.export()
+                    choice(deck['cards']).copy())
+                board_locations.append([(x, y), board_location.export()])
         return board_locations
 
     def lose_health(self):
@@ -100,6 +124,10 @@ class GameBoard(object):
         if self.wins >= self.wins_required:
             self.end_game(win=True)
 
+    def card_used(self, position):
+        if not self.puzzle:
+            self.replace_card(position)
+
     def replace_card(self, position):
         location = LocationCard.new_location(choice(self.locations).copy())
         self.board_locations[position] = location
@@ -135,23 +163,24 @@ class GameBoard(object):
         rotated_locations = {}
 
         if py > 0:
-            for i in range(max(0, px -1), min(5, px + 2)):
+            for i in range(max(0, px - 1), min(5, px + 2)):
                 locations_to_rotate.append((i, py - 1))
 
-        if px > 0:
-            locations_to_rotate.append((px - 1, py))
-
         if px < 4:
             locations_to_rotate.append((px + 1, py))
 
         if py < 4:
-            for i in range(max(0, px -1), min(5, px + 2)):
+            for i in reversed(range(max(0, px - 1), min(5, px + 2))):
                 locations_to_rotate.append((i, py + 1))
 
-        if direction == ROTATION.CLOCKWISE:
-            new_positions = locations_to_rotate[1:] + locations_to_rotate[0]
-        elif direction == ROTATION.ANTICLOCKWISE:
-            new_positions = locations_to_rotate[-1] + locations_to_rotate[:-1]
+        if px > 0:
+            locations_to_rotate.append((px - 1, py))
+
+        if ROTATION[direction] == ROTATION.CLOCKWISE:
+            new_positions = locations_to_rotate[1:] + [locations_to_rotate[0]]
+        elif ROTATION[direction] == ROTATION.ANTICLOCKWISE:
+            new_positions = (
+                [locations_to_rotate[-1]] + locations_to_rotate[:-1])
 
         for old, new in zip(locations_to_rotate, new_positions):
             rotated_locations[old] = self.board_locations[new]
@@ -223,7 +252,7 @@ class LocationCard(object):
 
     def export(self):
         return {
-            'bitwise_operand': self.bitwise_operand,
+            'bitwise_operand': sorted(self.bitwise_operand),
             'actions': [action.export() for action in self.actions],
         }