Ability to move player with location.
[naja.git] / naja / player.py
index 2156a3665c8f64e21452f5e8bffd6b1750bc8146..d47e82682cce298a57424eaae1918d3f100e9615 100644 (file)
@@ -1,4 +1,4 @@
-from naja.constants import BITS
+from naja.constants import BITS, MOVES
 
 
 class PlayerBits(object):
@@ -49,53 +49,137 @@ class PlayerBits(object):
         for bit in bits:
             self.toggle_bit(bit)
 
+    def shift_bits_left(self, shift):
+        wrap = self.bits >> (8 - shift)
+        self.bits = (self.bits << shift & 0xff | wrap)
+
+    def shift_bits_right(self, shift):
+        wrap = self.bits << (8 - shift) & 0xff
+        self.bits = (self.bits >> shift | wrap)
+
 
 class Player(object):
     """
     A representation of the player.
     """
 
-    def __init__(self, bits, position):
+    def __init__(self, bits, position, movement_mode=None, gameboard=None):
         self.bits = PlayerBits(bits)
         self.position = position
+        self.movement_mode = movement_mode if movement_mode else MOVES.ADJACENT
+        self.gameboard = gameboard
 
     @classmethod
-    def import_player(cls, definition):
-        return cls(definition['bits'], tuple(definition['position']))
+    def import_player(cls, definition, gameboard=None):
+        return cls(
+            definition['bits'],
+            tuple(definition['position']),
+            definition['movement_mode'],
+            gameboard=gameboard)
 
     def export(self):
         return {
             'bits': self.bits.bits,
             'position': list(self.position),
+            'movement_mode': self.movement_mode,
         }
 
-    def get_adjacent_position(self, direction):
+    def get_adjacent_positions(self):
+        positions = [self.position]
+
+        x, y = self.position
+
+        if self.bits.check_bit(BITS.NORTH) and y > 0:
+            positions.append((x, y - 1))
+        if self.bits.check_bit(BITS.SOUTH) and y < 4:
+            positions.append((x, y + 1))
+        if self.bits.check_bit(BITS.EAST) and x < 4:
+            positions.append((x + 1, y))
+        if self.bits.check_bit(BITS.WEST) and x > 0:
+            positions.append((x - 1, y))
+
+        return positions
+
+    def get_knight_positions(self):
+        positions = set([self.position])
+
+        x, y = self.position
+
+        for a in (2, -2):
+            for b in (1, -1):
+                i, j = x + a, y + b
+                if 0 <= i < 5 and 0 <= j < 5:
+                    positions.add((i, j))
+
+                i, j = x + b, y + a
+                if 0 <= i < 5 and 0 <= j < 5:
+                    positions.add((i, j))
+
+        return sorted(list(positions))
+
+    def get_bishop_positions(self):
+        positions = set()
+
         x, y = self.position
-        if direction == BITS.NORTH and y > 0:
-            return (x, y - 1)
-        elif direction == BITS.SOUTH and y < 4:
-            return (x, y + 1)
-        elif direction == BITS.EAST and x < 4:
-            return (x + 1, y)
-        elif direction == BITS.WEST and x > 0:
-            return (x - 1, y)
-        else:
-            # Not a legal space.
-            return None
-
-    def move(self, direction):
-        if not self.bits.check_bit(direction):
-            return False
-        new_position = self.get_adjacent_position(direction)
-        if new_position is not None:
+
+        for i in range(5):
+            j = i + y - x
+            if 0 <= j < 5:
+                positions.add((i, j))
+
+            j = x + y - i
+            if 0 <= j < 5:
+                positions.add((i, j))
+
+        return sorted(list(positions))
+
+    def get_castle_positions(self):
+        positions = set()
+
+        x, y = self.position
+
+        for i in range(5):
+            positions.add((x, i))
+            positions.add((i, y))
+
+        return sorted(list(positions))
+
+    def set_position(self, new_position):
+        if new_position in self.legal_moves():
             self.position = new_position
+            self.movement_mode = MOVES.ADJACENT
             return True
         return False
 
+    def force_position(self, pos, delta=True):
+        if delta:
+            pos = (self.position[0] + pos[0],
+                   self.position[1] + pos[1])
+        if (0 <= pos[0] < 5 and 0 <= pos[1] < 5):
+            self.position = pos
+
+    def set_gameboard(self, gameboard):
+        self.gameboard = gameboard
+
+    def pos_has_action(self, pos):
+        card = self.gameboard.board_locations[pos]
+        for action in card.actions:
+            if self.bits.check_bits(action.required_bits):
+                return True
+        return False
+
+    def filter_moves_with_no_actions(self, positions):
+        return [pos for pos in positions if self.pos_has_action(pos)]
+
     def legal_moves(self):
-        positions = []
-        for direction in [BITS.NORTH, BITS.SOUTH, BITS.EAST, BITS.WEST]:
-            position = self.get_adjacent_position(direction)
-            if position is not None and self.bits.check_bit(direction):
-                positions.append(position)
-        return positions
+        POSITION_FUNCTION = {
+            MOVES.ADJACENT: self.get_adjacent_positions,
+            MOVES.KNIGHT: self.get_knight_positions,
+            MOVES.BISHOP: self.get_bishop_positions,
+            MOVES.CASTLE: self.get_castle_positions,
+        }
+        positions = POSITION_FUNCTION[self.movement_mode]()
+        return self.filter_moves_with_no_actions(positions)
+
+    def allow_chess_move(self, chesspiece):
+        self.movement_mode = chesspiece