00e6133ed720486bd19d878136abcdcd5087b86a
[naja.git] / naja / player.py
1 from naja.constants import BITS
2
3
4 class PlayerBits(object):
5     """
6     A glorified byte.
7     """
8
9     def __init__(self, bits):
10         self.bits = bits
11
12     @property
13     def bits(self):
14         return self._bits
15
16     @bits.setter
17     def bits(self, value):
18         assert 0 <= value <= 0xff
19         self._bits = value
20
21     # Operate on individual bits
22
23     def check_bit(self, bit):
24         return bool(self.bits & (1 << bit))
25
26     def set_bit(self, bit):
27         self.bits |= (1 << bit)
28
29     def clear_bit(self, bit):
30         self.bits &= (0xff ^ (1 << bit))
31
32     def toggle_bit(self, bit):
33         self.bits ^= (1 << bit)
34
35     # Operate on sets of bits
36
37     def check_bits(self, bits):
38         return all(self.check_bit(bit) for bit in bits)
39
40     def set_bits(self, bits):
41         for bit in bits:
42             self.set_bit(bit)
43
44     def clear_bits(self, bits):
45         for bit in bits:
46             self.clear_bit(bit)
47
48     def toggle_bits(self, bits):
49         for bit in bits:
50             self.toggle_bit(bit)
51
52
53 class Player(object):
54     """
55     A representation of the player.
56     """
57
58     def __init__(self, bits, position):
59         self.bits = PlayerBits(bits)
60         self.position = position
61
62     @classmethod
63     def import_player(cls, definition):
64         return cls(definition['bits'], tuple(definition['position']))
65
66     def export(self):
67         return {
68             'bits': self.bits.bits,
69             'position': list(self.position),
70         }
71
72     def get_adjacent_position(self, direction):
73         x, y = self.position
74         if direction == BITS.NORTH and y > 0:
75             return (x, y - 1)
76         elif direction == BITS.SOUTH and y < 4:
77             return (x, y + 1)
78         elif direction == BITS.EAST and x < 4:
79             return (x + 1, y)
80         elif direction == BITS.WEST and x > 0:
81             return (x - 1, y)
82         else:
83             # Not a legal space.
84             return None
85
86     def move(self, direction):
87         if not self.bits.check_bit(direction):
88             return False
89         new_position = self.get_adjacent_position(direction)
90         if new_position is not None:
91             self.position = new_position
92             return True
93         return False
94
95     def legal_moves(self):
96         positions = [self.position]
97         for direction in [BITS.NORTH, BITS.SOUTH, BITS.EAST, BITS.WEST]:
98             position = self.get_adjacent_position(direction)
99             if position is not None and self.bits.check_bit(direction):
100                 positions.append(position)
101         return positions