+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")