Start of some game board stuff.
authorJeremy Thurgood <firxen@gmail.com>
Sun, 11 May 2014 14:17:51 +0000 (16:17 +0200)
committerJeremy Thurgood <firxen@gmail.com>
Sun, 11 May 2014 14:17:51 +0000 (16:17 +0200)
naja/attrdict.py [new file with mode: 0644]
naja/constants.py
naja/gameboard.py [new file with mode: 0644]
naja/options.py
naja/tests/test_gameboard.py [new file with mode: 0644]
naja/tests/test_player.py

diff --git a/naja/attrdict.py b/naja/attrdict.py
new file mode 100644 (file)
index 0000000..3bdae4e
--- /dev/null
@@ -0,0 +1,4 @@
+class AttrDict(dict):
+    '''A dict with attribute access'''
+    def __getattr__(self, attr):
+        return self[attr]
index 0dc6b84726fd370b7079d666c589040c7c4bdc84..25a8cfcb45c9348773f3c35fac1bc67514d2ed01 100644 (file)
@@ -1,3 +1,6 @@
+from naja.attrdict import AttrDict
+
+
 SCREEN = (800, 600)
 FPS = 40
 FONT = 'DejaVuSans.ttf'
@@ -18,11 +21,17 @@ DEFAULT_SOUND_VOLUME = 1.0  # sound volume
 DEFAULT_MUSIC_VOLUME = 0.3  # music volume
 
 # Player bits
-NORTH = 0
-SOUTH = 1
-EAST = 2
-WEST = 3
-CYAN = 4
-MAGENTA = 5
-YELLOW = 6
-MSB = 7
+BITS = AttrDict({
+    # Direction bits
+    'NORTH': 0,
+    'SOUTH': 1,
+    'EAST': 2,
+    'WEST': 3,
+    # Condition bits
+    'CYAN': 4,
+    'MAGENTA': 5,
+    'YELLOW': 6,
+    'MSB': 7,
+})
+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)
diff --git a/naja/gameboard.py b/naja/gameboard.py
new file mode 100644 (file)
index 0000000..a107b16
--- /dev/null
@@ -0,0 +1,92 @@
+from random import choice
+
+from naja.constants import BITS, DIRECTION_BITS, CONDITION_BITS
+
+
+class GameBoard(object):
+    """
+    A representation of the game board.
+    """
+
+    def __init__(self, player, health, wins, locations=None, state=None):
+        self.player = player
+        self.max_health = health
+        self.wins_required = wins
+
+        if locations is None:
+            locations = self.generate_locations()
+        self.locations = locations
+
+        if state is None:
+            state = self.generate_state()
+        self.update_state(state)
+
+    @classmethod
+    def generate_locations(cls):
+        raise NotImplementedError("TODO")
+
+    def generate_state(self):
+        return {
+            'health': self.max_health,
+            'wins': 0,
+        }
+
+
+class LocationCard(object):
+    """
+    A particular set of options available on a location.
+    """
+
+    def __init__(self, bitwise_operation, bitwise_operand, actions):
+        self.bitwise_operation = bitwise_operation
+        self.bitwise_operand = bitwise_operand
+        self.actions = actions
+
+    @staticmethod
+    def generate_location():
+        raise NotImplementedError("TODO")
+
+    @staticmethod
+    def generate_bitwise_operand():
+        """
+        Generate a set of two or three bits. At least one direction and one
+        condition bit will be included. There is a low probability of choosing
+        a third bit from the complete set.
+        """
+        bits = set()
+        bits.add(choice(DIRECTION_BITS.values()))
+        bits.add(choice(CONDITION_BITS.values()))
+        # One in three chance of adding a third bit, with a further one in four
+        # chance that it will match a bit already chosen.
+        if choice(range(3)) == 0:
+            bits.add(choice(BITS.values()))
+        return frozenset(bits)
+
+    @staticmethod
+    def generate_location_actions():
+        raise NotImplementedError("TODO")
+
+    def apply_bitwise_operation(self, player):
+        operator = {
+            'SET': player.bits.set_bits,
+            'CLEAR': player.bits.clear_bits,
+            'TOGGLE': player.bits.toggle_bits,
+        }[self.bitwise_operation]
+        operator(self.bitwise_operand)
+
+
+class LocationAction(object):
+    """
+    An action that may be performed on a location.
+    """
+
+    REQUIRED_BITS = frozenset()
+
+    def __init__(self, **data):
+        self.data = data
+
+    def check_available(self, player):
+        return player.bits.check_bits(self.REQUIRED_BITS)
+
+    def perform_action(self, player, board):
+        raise NotImplementedError("TODO")
index cf5715dde1faa36d7dcf81628648458434c3b3fc..816d91ca3c29f87329a2b8f6b9428d899e851280 100644 (file)
@@ -1,15 +1,10 @@
 import optparse
 import os
 
+from naja.attrdict import AttrDict
 from naja.constants import DEFAULTS
 
 
-class AttrDict(dict):
-    '''A dict with attribute access'''
-    def __getattr__(self, attr):
-        return self[attr]
-
-
 options = AttrDict()
 
 
diff --git a/naja/tests/test_gameboard.py b/naja/tests/test_gameboard.py
new file mode 100644 (file)
index 0000000..a895e18
--- /dev/null
@@ -0,0 +1,22 @@
+from unittest import TestCase
+
+from naja.constants import BITS
+from naja.gameboard import LocationCard
+
+
+class TestLocationCard(TestCase):
+    def test_generate_bitwise_operand(self):
+        # This is testing a random process, so it may fail occasionally.
+        operand_sets = []
+        for _ in range(100):
+            operand_sets.append(LocationCard.generate_bitwise_operand())
+        sizes = {2: 0, 3: 0}
+        bits = set()
+        for operand_set in operand_sets:
+            sizes[len(operand_set)] += 1
+            bits.update(operand_set)
+            # TODO: Test that there's at least one condition and one direction.
+        self.assertTrue(sizes[2] > 0)
+        self.assertTrue(sizes[3] > 0)
+        self.assertTrue(sizes[2] > sizes[3])
+        self.assertEqual(bits, set(BITS.values()))
index 48b2ef8fa9af7cf7202b0c3cbe23bdb813279d93..8373eee2d53a5cc35d9049854646bf6a0ea947d8 100644 (file)
@@ -1,6 +1,6 @@
 from unittest import TestCase
 
-from naja.constants import NORTH, SOUTH, CYAN, MSB
+from naja.constants import BITS
 from naja.player import PlayerBits
 
 
@@ -23,63 +23,64 @@ class TestPlayerBits(TestCase):
 
     def test_check_bit(self):
         bits = PlayerBits(0x01)
-        self.assertEqual(bits.check_bit(NORTH), True)
-        self.assertEqual(bits.check_bit(SOUTH), False)
+        self.assertEqual(bits.check_bit(BITS.NORTH), True)
+        self.assertEqual(bits.check_bit(BITS.SOUTH), False)
 
     def test_set_bit(self):
         bits = PlayerBits(0x00)
         self.assertEqual(bits._bits, 0x00)
-        bits.set_bit(NORTH)
+        bits.set_bit(BITS.NORTH)
         self.assertEqual(bits._bits, 0x01)
-        bits.set_bit(NORTH)
+        bits.set_bit(BITS.NORTH)
         self.assertEqual(bits._bits, 0x01)
 
     def test_clear_bit(self):
         bits = PlayerBits(0x01)
         self.assertEqual(bits._bits, 0x01)
-        bits.clear_bit(NORTH)
+        bits.clear_bit(BITS.NORTH)
         self.assertEqual(bits._bits, 0x00)
-        bits.clear_bit(NORTH)
+        bits.clear_bit(BITS.NORTH)
         self.assertEqual(bits._bits, 0x00)
 
     def test_toggle_bit(self):
         bits = PlayerBits(0x00)
         self.assertEqual(bits._bits, 0x00)
-        bits.toggle_bit(NORTH)
+        bits.toggle_bit(BITS.NORTH)
         self.assertEqual(bits._bits, 0x01)
-        bits.toggle_bit(NORTH)
+        bits.toggle_bit(BITS.NORTH)
         self.assertEqual(bits._bits, 0x00)
 
     def test_check_bits(self):
         bits = PlayerBits(0x03)
-        self.assertEqual(bits.check_bits(NORTH), True)
-        self.assertEqual(bits.check_bits(NORTH, SOUTH), True)
-        self.assertEqual(bits.check_bits(CYAN), False)
-        self.assertEqual(bits.check_bits(CYAN, MSB), False)
-        self.assertEqual(bits.check_bits(NORTH, SOUTH, CYAN), False)
+        self.assertEqual(bits.check_bits(BITS.NORTH), True)
+        self.assertEqual(bits.check_bits(BITS.NORTH, BITS.SOUTH), True)
+        self.assertEqual(bits.check_bits(BITS.CYAN), False)
+        self.assertEqual(bits.check_bits(BITS.CYAN, BITS.MSB), False)
+        self.assertEqual(
+            bits.check_bits(BITS.NORTH, BITS.SOUTH, BITS.CYAN), False)
 
     def test_set_bits(self):
         bits = PlayerBits(0x03)
         self.assertEqual(bits._bits, 0x03)
-        bits.set_bits(NORTH, CYAN)
+        bits.set_bits(BITS.NORTH, BITS.CYAN)
         self.assertEqual(bits._bits, 0x13)
-        bits.set_bits(NORTH, CYAN, MSB)
+        bits.set_bits(BITS.NORTH, BITS.CYAN, BITS.MSB)
         self.assertEqual(bits._bits, 0x93)
 
     def test_clear_bits(self):
         bits = PlayerBits(0x03)
         self.assertEqual(bits._bits, 0x03)
-        bits.clear_bits(NORTH, CYAN)
+        bits.clear_bits(BITS.NORTH, BITS.CYAN)
         self.assertEqual(bits._bits, 0x02)
-        bits.clear_bits(NORTH, CYAN, MSB)
+        bits.clear_bits(BITS.NORTH, BITS.CYAN, BITS.MSB)
         self.assertEqual(bits._bits, 0x02)
 
     def test_toggle_bits(self):
         bits = PlayerBits(0x03)
         self.assertEqual(bits._bits, 0x03)
-        bits.toggle_bits(NORTH, CYAN)
+        bits.toggle_bits(BITS.NORTH, BITS.CYAN)
         self.assertEqual(bits._bits, 0x12)
-        bits.toggle_bits(NORTH, CYAN)
+        bits.toggle_bits(BITS.NORTH, BITS.CYAN)
         self.assertEqual(bits._bits, 0x03)
-        bits.toggle_bits(NORTH, CYAN, MSB)
+        bits.toggle_bits(BITS.NORTH, BITS.CYAN, BITS.MSB)
         self.assertEqual(bits._bits, 0x92)