chess moves are working; need more tests
authoradrianna <adrianna.pinska@gmail.com>
Fri, 16 May 2014 00:40:49 +0000 (02:40 +0200)
committeradrianna <adrianna.pinska@gmail.com>
Fri, 16 May 2014 00:42:54 +0000 (02:42 +0200)
data/location_decks/test.yaml
naja/actions.py
naja/constants.py
naja/gameboard.py
naja/player.py
naja/tests/test_player.py

index a2a6e496a5c3a00a18598bd8d752a2169ae6e42e..3c650320faf3563956cd98f6d971995840f2b378 100644 (file)
@@ -47,4 +47,16 @@ cards:
   - bits: [RED, GREEN]  # colour-blind robot!
     actions:
     - action_class: 'ToggleBits'
-      required_bits: [GREEN]
\ No newline at end of file
+      required_bits: [GREEN]
+  - actions:
+    - action_class: 'AllowChessMove'
+      required_bits: [RED, BLUE]
+      data: {'chesspiece': KNIGHT}
+  - actions:
+    - action_class: 'AllowChessMove'
+      required_bits: [RED, BLUE]
+      data: {'chesspiece': BISHOP}
+  - actions:
+    - action_class: 'AllowChessMove'
+      required_bits: [RED, BLUE]
+      data: {'chesspiece': CASTLE}
index 0535c8be1b37964d752773636d2538c877adc78b..f92961cd4bdfc38e61d8e5eb33b521aa55446d11 100644 (file)
@@ -1,4 +1,4 @@
-from naja.constants import BITS
+from naja.constants import BITS, CHESS_PIECES
 
 
 class LocationAction(object):
@@ -15,6 +15,7 @@ class LocationAction(object):
 
     def get_text(self):
         substitutions = self.data.copy()
+
         if 'direction' in self.data:
             substitutions['rowcol'] = {
                 'NORTH': 'column',
@@ -22,6 +23,10 @@ class LocationAction(object):
                 'EAST': 'row',
                 'WEST': 'row',
             }[self.data['direction']]
+
+        if 'chesspiece' in self.data:
+            substitutions['chesspiece_name'] = self.data['chesspiece'].lower()
+
         return self.TEXT % substitutions
 
     def check_available(self, player):
@@ -108,3 +113,12 @@ class ShiftLocations(LocationAction):
 
     def perform_action(self, board, location):
         board.shift_locations(self.data['direction'])
+
+
+class AllowChessMove(LocationAction) :
+    TEXT = "Move like a %(chesspiece_name)s for one turn."
+
+    def perform_action(self, board, location):
+        if self.data['chesspiece'] in CHESS_PIECES:
+            chesspiece = CHESS_PIECES[self.data['chesspiece']]
+            board.allow_chess_move(chesspiece)
index 96824f4042dc530aa9da433c70fa64c7023bfc54..f81cb8f725a935c2fabb40784f80c9880d66eae2 100644 (file)
@@ -39,6 +39,17 @@ BITS = AttrDict({
 DIRECTION_BITS = AttrDict((k, v) for k, v in BITS.items() if v < 4)
 CONDITION_BITS = AttrDict((k, v) for k, v in BITS.items() if v >= 4)
 
+# PLAYER MOVES
+MOVES = AttrDict({
+    # Default move
+    'ADJACENT': 0,
+    # Chess moves
+    'KNIGHT': 1,
+    'BISHOP': 2,
+    'CASTLE': 3,
+})
+CHESS_PIECES = AttrDict((k, v) for k, v in MOVES.items() if v > 0)
+
 # Player defaults
 PLAYER_DEFAULTS = AttrDict({
     'INITIAL_BITS': 0x0f,
index 3717b564dcf0809a5ebda745f283bdfd7dd73ca8..367a9e15118b4cbd6b9fe3248a691c141f66831d 100644 (file)
@@ -130,6 +130,9 @@ class GameBoard(object):
         elif BITS[direction] == BITS.WEST:
             self.shift_location_row(-1, is_vertical=False)
 
+    def allow_chess_move(self, chesspiece):
+        self.player.allow_chess_move(chesspiece)
+
     def change_mode(self, new_mode):
         """Advance to the next mode"""
         if new_mode == self.player_mode:
index f502b640ffd94ddd999022931425e77248794141..2f6fdcfa45e3c618a3005641d6eb29dfc16f566c 100644 (file)
@@ -1,4 +1,4 @@
-from naja.constants import BITS
+from naja.constants import BITS, MOVES, CHESS_PIECES
 
 
 class PlayerBits(object):
@@ -55,53 +55,97 @@ class Player(object):
     A representation of the player.
     """
 
-    def __init__(self, bits, position):
+    def __init__(self, bits, position, movement_mode=None):
         self.bits = PlayerBits(bits)
         self.position = position
+        self.movement_mode = movement_mode if movement_mode else MOVES.ADJACENT
 
     @classmethod
     def import_player(cls, definition):
-        return cls(definition['bits'], tuple(definition['position']))
+        return cls(definition['bits'], tuple(definition['position']), definition['movement_mode'])
 
     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 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:
-            self.position = new_position
-            return True
-        return False
+
+        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
+
+        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 legal_moves(self):
-        positions = [self.position]
-        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,
+        }
+        return POSITION_FUNCTION[self.movement_mode]()
+
+    def allow_chess_move(self, chesspiece):
+        self.movement_mode = chesspiece
index 1d11637b3cf9df8638617b24c23fdf21791a028e..d45c09eadcdad3957862611d5f337b41919c4f56 100644 (file)
@@ -96,67 +96,27 @@ class TestPlayer(TestCase):
         player = Player.import_player({
             'bits': 0xaa,
             'position': [1, 2],
+            'movement_mode': MOVES.CASTLE,
         })
         self.assertEqual(player.bits.bits, 0xaa)
         self.assertEqual(player.position, (1, 2))
+        self.assertEqual(player.movement_mode, MOVES.CASTLE)
 
     def test_export_player(self):
-        player = Player(0xaa, (1, 2))
+        player = Player(0xaa, (1, 2), MOVES.CASTLE)
         self.assertEqual(player.export(), {
             'bits': 0xaa,
             'position': [1, 2],
+            'movement_mode': MOVES.CASTLE,
         })
 
-    def test_move(self):
-        player = Player(0x0f, (2, 2))
-        self.assertEqual(player.move(BITS.NORTH), True)
-        self.assertEqual(player.position, (2, 1))
-
-        player = Player(0x0f, (2, 2))
-        self.assertEqual(player.move(BITS.SOUTH), True)
-        self.assertEqual(player.position, (2, 3))
-
-        player = Player(0x0f, (2, 2))
-        self.assertEqual(player.move(BITS.WEST), True)
-        self.assertEqual(player.position, (1, 2))
-
-        player = Player(0x0f, (2, 2))
-        self.assertEqual(player.move(BITS.EAST), True)
-        self.assertEqual(player.position, (3, 2))
-
-    def test_move_flags_clear(self):
-        player = Player(0x00, (2, 2))
-        self.assertEqual(player.move(BITS.NORTH), False)
-        self.assertEqual(player.position, (2, 2))
-
-        player = Player(0x00, (2, 2))
-        self.assertEqual(player.move(BITS.SOUTH), False)
-        self.assertEqual(player.position, (2, 2))
-
-        player = Player(0x00, (2, 2))
-        self.assertEqual(player.move(BITS.WEST), False)
-        self.assertEqual(player.position, (2, 2))
-
-        player = Player(0x00, (2, 2))
-        self.assertEqual(player.move(BITS.EAST), False)
-        self.assertEqual(player.position, (2, 2))
-
-    def test_move_flags_edges(self):
-        player = Player(0x0f, (2, 0))
-        self.assertEqual(player.move(BITS.NORTH), False)
-        self.assertEqual(player.position, (2, 0))
-
-        player = Player(0x0f, (2, 4))
-        self.assertEqual(player.move(BITS.SOUTH), False)
-        self.assertEqual(player.position, (2, 4))
-
-        player = Player(0x0f, (0, 2))
-        self.assertEqual(player.move(BITS.WEST), False)
-        self.assertEqual(player.position, (0, 2))
-
-        player = Player(0x0f, (4, 2))
-        self.assertEqual(player.move(BITS.EAST), False)
-        self.assertEqual(player.position, (4, 2))
+    def test_export_player_default_movement_mode(self):
+        player = Player(0xaa, (1, 2))
+        self.assertEqual(player.export(), {
+            'bits': 0xaa,
+            'position': [1, 2],
+            'movement_mode': MOVES.ADJACENT,
+        })
 
     def test_legal_moves_all_available(self):
         player = Player(0x0f, (2, 2))
@@ -167,3 +127,22 @@ class TestPlayer(TestCase):
         player = Player(0x0f, (0, 2))
         player.bits.clear_bit(BITS.NORTH)
         self.assertEqual(player.legal_moves(), [(0, 2), (0, 3), (1, 2)])
+
+    def test_legal_moves_castle(self):
+        player = Player(0x0f, (1, 3), MOVES.CASTLE)
+        self.assertEqual(player.legal_moves(), [(0, 3), (1, 0), (1, 1), (1, 2),
+        (1, 3), (1, 4), (2, 3), (3, 3), (4, 3)])
+
+    def test_legal_moves_bishop(self):
+        player = Player(0x0f, (1, 3), MOVES.BISHOP)
+        self.assertEqual(player.legal_moves(), [(0, 2), (0, 4), (1, 3), (2, 2),
+        (2, 4), (3, 1), (3, 4), (4, 0)])
+
+    def test_legal_moves_knight(self):
+        player = Player(0x0f, (1, 3), MOVES.KNIGHT)
+        self.assertEqual(player.legal_moves(), [(0, 1), (2, 1), (3, 2), (3, 4)])
+
+    def test_set_position(self):
+        player = Player(0x0f, (3, 3), MOVES.BISHOP)
+        player.set_position((4, 4))
+        self.assertEqual(player.movement_mode, MOVES.ADJACENT)