2db02a78b436d8bdf72dabb9c5f888e0fd547285
[naja.git] / naja / tests / test_gameboard.py
1 from unittest import TestCase
2
3 from naja.constants import BITS, MOVES, EXAMINE
4 from naja.gameboard import GameBoard, LocationCard
5 from naja.options import parse_args
6 from naja import actions
7
8
9 class TestGameBoard(TestCase):
10     def setUp(self):
11         parse_args([])
12
13     def make_deck(self, cards=None):
14         if cards is None:
15             cards = [{'actions': []}]
16         return {'cards': cards}
17
18     def assert_state(self, state1, state2, exclude=(), player_exclude=()):
19         def filter_dict(source, exclude_keys):
20             return dict((k, v) for k, v in source.items()
21                         if k not in exclude_keys)
22
23         state1 = filter_dict(state1, exclude)
24         if 'player' in state1:
25             state1['player'] = filter_dict(state1['player'], player_exclude)
26         state2 = filter_dict(state2, exclude)
27         if 'player' in state2:
28             state2['player'] = filter_dict(state2['player'], player_exclude)
29
30         self.assertEqual(state1, state2)
31
32     def test_export_new_board(self):
33         board = GameBoard.new_game({'cards': [{'actions': [
34             {
35                 'action_class': 'LoseHealthOrMSB',
36                 'required_bits': [],
37             }, {
38                 'action_class': 'GainHealth',
39                 'required_bits': [BITS.RED],
40             },
41         ]}]})
42         exported_state = board.export()
43         board_locations = exported_state.pop('board_locations')
44         self.assertEqual(exported_state, {
45             'max_health': 4,
46             'health': 4,
47             'wins_required': 4,
48             'wins': 0,
49             'locations': [{'actions': [
50                 {
51                     'action_class': 'LoseHealthOrMSB',
52                     'required_bits': [],
53                 }, {
54                     'action_class': 'GainHealth',
55                     'required_bits': [BITS.RED],
56                 },
57             ]}],
58             'player': board.player.export(),
59             'puzzle': False,
60             'player_mode': EXAMINE,
61         })
62         positions = []
63         for position, location_state in board_locations:
64             positions.append(position)
65             self.assertEqual(
66                 sorted(location_state.keys()), ['actions', 'bitwise_operand'])
67             self.assertEqual(location_state['actions'], [
68                 {
69                     'action_class': 'LoseHealthOrMSB',
70                     'required_bits': [],
71                     'data': {},
72                 }, {
73                     'action_class': 'GainHealth',
74                     'required_bits': [BITS.RED],
75                     'data': {},
76                 },
77             ])
78             self.assertTrue(2 <= len(location_state['bitwise_operand']) <= 3)
79         self.assertEqual(
80             positions, sorted((x, y) for x in range(5) for y in range(5)))
81
82     def test_lose_health(self):
83         board = GameBoard.new_game(self.make_deck())
84         self.assertEqual(board.health, 4)
85         state_1 = board.export()
86
87         board.lose_health()
88         self.assertEqual(board.health, 3)
89         state_2 = board.export()
90
91         self.assert_state(state_1, state_2, exclude=['health'])
92
93     def test_gain_health(self):
94         board = GameBoard.new_game(self.make_deck())
95         board.health = 2
96         self.assertEqual(board.health, 2)
97         state_1 = board.export()
98
99         board.gain_health()
100         self.assertEqual(board.health, 3)
101         state_2 = board.export()
102
103         self.assert_state(state_1, state_2, exclude=['health'])
104
105     def test_gain_health_at_max(self):
106         board = GameBoard.new_game(self.make_deck())
107         self.assertEqual(board.health, 4)
108         state_1 = board.export()
109
110         board.gain_health()
111         self.assertEqual(board.health, 4)
112         state_2 = board.export()
113
114         self.assert_state(state_1, state_2)
115
116     def generate_locations(self, override_dict=None):
117         locations_dict = dict(((x, y), '%s%s' % (x, y))
118                               for x in range(5) for y in range(5))
119         if override_dict:
120             locations_dict.update(override_dict)
121         return locations_dict
122
123     def test_shift_locations_north(self):
124         board = GameBoard.new_game(self.make_deck())
125         board.board_locations = self.generate_locations()
126         board.shift_locations('NORTH')
127         self.assertEqual(board.board_locations, self.generate_locations({
128             (2, 0): '21', (2, 1): '23', (2, 3): '24', (2, 4): '20',
129         }))
130
131     def test_shift_locations_south(self):
132         board = GameBoard.new_game(self.make_deck())
133         board.board_locations = self.generate_locations()
134         board.shift_locations('SOUTH')
135         self.assertEqual(board.board_locations, self.generate_locations({
136             (2, 0): '24', (2, 1): '20', (2, 3): '21', (2, 4): '23',
137         }))
138
139     def test_shift_locations_east(self):
140         board = GameBoard.new_game(self.make_deck())
141         board.board_locations = self.generate_locations()
142         board.shift_locations('EAST')
143         self.assertEqual(board.board_locations, self.generate_locations({
144             (0, 2): '42', (1, 2): '02', (3, 2): '12', (4, 2): '32',
145         }))
146
147     def test_shift_locations_west(self):
148         board = GameBoard.new_game(self.make_deck())
149         board.board_locations = self.generate_locations()
150         board.shift_locations('WEST')
151         self.assertEqual(board.board_locations, self.generate_locations({
152             (0, 2): '12', (1, 2): '32', (3, 2): '42', (4, 2): '02',
153         }))
154
155     def test_rotate_locations_anticlockwise(self):
156         board = GameBoard.new_game(self.make_deck())
157         board.board_locations = self.generate_locations()
158         board.rotate_locations('ANTICLOCKWISE')
159         self.assertEqual(board.board_locations, self.generate_locations({
160             (1, 1): '21', (2, 1): '31', (3, 1): '32',
161             (1, 2): '11',               (3, 2): '33',
162             (1, 3): '12', (2, 3): '13', (3, 3): '23',
163         }))
164
165     def test_rotate_locations_anticlockwise_top(self):
166         board = GameBoard.new_game(self.make_deck(), initial_pos=(2, 0))
167         board.board_locations = self.generate_locations()
168         board.rotate_locations('ANTICLOCKWISE')
169         self.assertEqual(board.board_locations, self.generate_locations({
170             (1, 0): '30',               (3, 0): '31',
171             (1, 1): '10', (2, 1): '11', (3, 1): '21',
172         }))
173
174     def test_rotate_locations_anticlockwise_right(self):
175         board = GameBoard.new_game(self.make_deck(), initial_pos=(0, 2))
176         board.board_locations = self.generate_locations()
177         board.rotate_locations('ANTICLOCKWISE')
178         self.assertEqual(board.board_locations, self.generate_locations({
179             (0, 1): '11', (1, 1): '12',
180                           (1, 2): '13',
181             (0, 3): '01', (1, 3): '03',
182         }))
183
184     def test_rotate_locations_anticlockwise_corner(self):
185         board = GameBoard.new_game(self.make_deck(), initial_pos=(0, 4))
186         board.board_locations = self.generate_locations()
187         board.rotate_locations('ANTICLOCKWISE')
188         self.assertEqual(board.board_locations, self.generate_locations({
189             (0, 3): '13', (1, 3): '14',
190                           (1, 4): '03',
191         }))
192
193     def test_rotate_locations_clockwise(self):
194         board = GameBoard.new_game(self.make_deck())
195         board.board_locations = self.generate_locations()
196         board.rotate_locations('CLOCKWISE')
197         self.assertEqual(board.board_locations, self.generate_locations({
198             (1, 1): '12', (2, 1): '11', (3, 1): '21',
199             (1, 2): '13',               (3, 2): '31',
200             (1, 3): '23', (2, 3): '33', (3, 3): '32',
201         }))
202
203     def test_rotate_locations_clockwise_1_3(self):
204         board = GameBoard.new_game(self.make_deck(), initial_pos=(1, 3))
205         board.board_locations = self.generate_locations()
206         board.rotate_locations('CLOCKWISE')
207         self.assertEqual(board.board_locations, self.generate_locations({
208             (0, 2): '03', (1, 2): '02', (2, 2): '12',
209             (0, 3): '04',               (2, 3): '22',
210             (0, 4): '14', (1, 4): '24', (2, 4): '23',
211         }))
212
213     def test_allow_chess_move_knight(self):
214         board = GameBoard.new_game(self.make_deck())
215         board.allow_chess_move(MOVES.KNIGHT)
216         self.assertEqual(board.player.movement_mode, MOVES.KNIGHT)
217
218     def test_allow_chess_move_bishop(self):
219         board = GameBoard.new_game(self.make_deck())
220         board.allow_chess_move(MOVES.BISHOP)
221         self.assertEqual(board.player.movement_mode, MOVES.BISHOP)
222
223     def test_allow_chess_move_castle(self):
224         board = GameBoard.new_game(self.make_deck())
225         board.allow_chess_move(MOVES.CASTLE)
226         self.assertEqual(board.player.movement_mode, MOVES.CASTLE)
227
228
229 class TestLocationCard(TestCase):
230     def test_generate_bitwise_operand(self):
231         # This is testing a random process, so it may fail occasionally.
232         operand_sets = []
233         for _ in range(100):
234             operand_sets.append(LocationCard.generate_bitwise_operand())
235         sizes = {2: 0, 3: 0}
236         bits = set()
237         for operand_set in operand_sets:
238             sizes[len(operand_set)] += 1
239             bits.update(operand_set)
240             # TODO: Test that there's at least one condition and one direction.
241         self.assertTrue(sizes[2] > 0)
242         self.assertTrue(sizes[3] > 0)
243         self.assertTrue(sizes[2] > sizes[3])
244         self.assertEqual(bits, set(BITS.values()))
245
246     def test_new_location_no_actions(self):
247         location = LocationCard.new_location({'actions': []})
248         [action] = location.actions
249         self.assertEqual(type(action), actions.DoNothing)
250         self.assertEqual(action.required_bits, set())
251
252     def test_new_location_one_action(self):
253         location = LocationCard.new_location({'actions': [
254             {'required_bits': [], 'action_class': 'DoNothing'},
255         ]})
256         [action] = location.actions
257         self.assertEqual(type(action), actions.DoNothing)
258         self.assertEqual(action.required_bits, set())
259
260     def test_parse_bits(self):
261         self.assertEqual(
262             LocationCard.parse_bits([]), frozenset([]))
263         self.assertEqual(
264             LocationCard.parse_bits(['RED']), frozenset([BITS.RED]))
265         self.assertEqual(
266             LocationCard.parse_bits([BITS.BLUE]), frozenset([BITS.BLUE]))
267         self.assertEqual(
268             LocationCard.parse_bits([BITS.NORTH, 'MSB']),
269             frozenset([BITS.NORTH, BITS.MSB]))