1 from unittest import TestCase
3 from naja.constants import BITS, MOVES
4 from naja.gameboard import GameBoard, LocationCard
5 from naja.options import parse_args
6 from naja import actions
9 class TestGameBoard(TestCase):
13 def make_deck(self, cards=None):
15 cards = [{'card_name': 'card', 'actions': []}]
16 return {'cards': cards}
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)
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)
30 self.assertEqual(state1, state2)
32 def test_export_new_board(self):
33 board = GameBoard.new_game({'cards': [
34 {'card_name': 'card1', 'actions': [
36 'action_class': 'LoseHealthOrMSB',
39 'action_class': 'GainHealth',
40 'required_bits': [BITS.RED],
43 exported_state = board.export()
44 board_locations = exported_state.pop('board_locations')
45 self.assertEqual(exported_state, {
51 'locations': [{'card_name': 'card1', 'actions': [
53 'action_class': 'LoseHealthOrMSB',
56 'action_class': 'GainHealth',
57 'required_bits': [BITS.RED],
60 'player': board.player.export(),
62 'replacement_params': None,
65 for position, location_state in board_locations:
66 positions.append(position)
67 self.assertEqual(sorted(location_state.keys()), [
68 'actions', 'bitwise_operand', 'card_name', 'max_number',
70 self.assertEqual(location_state['actions'], [
72 'action_class': 'LoseHealthOrMSB',
76 'action_class': 'GainHealth',
77 'required_bits': [BITS.RED],
81 self.assertTrue(2 <= len(location_state['bitwise_operand']) <= 3)
83 positions, sorted((x, y) for x in range(5) for y in range(5)))
85 def test_max_number(self):
86 def _check_counts(board):
88 exported_state = board.export()
89 board_locations = exported_state.pop('board_locations')
90 for _position, location_state in board_locations:
92 location_state['actions'][0]['action_class'], 0)
93 counts[location_state['actions'][0]['action_class']] += 1
94 self.assertTrue(counts.get('LoseHealthOrMSB', 0) <= 5)
96 board = GameBoard.new_game({'cards': [
97 {'card_name': 'card1', 'actions': [{
98 'action_class': 'LoseHealthOrMSB',
99 'required_bits': [], }],
101 {'card_name': 'card2', 'actions': [{
102 'action_class': 'DoNothing',
103 'required_bits': [], }],
105 # check creation constraints
108 # Replace center card 12 times and assert invariant still holds
110 board.replace_card((2, 2))
112 # replace a diagonal of cards
114 board.replace_card((x, x))
117 def test_max_number_complex(self):
118 def _check_counts(board):
120 exported_state = board.export()
121 board_locations = exported_state.pop('board_locations')
122 for _position, location_state in board_locations:
124 location_state['actions'][0]['action_class'], 0)
125 counts[location_state['actions'][0]['action_class']] += 1
126 self.assertTrue(counts.get('LoseHealthOrMSB', 0) <= 5)
127 self.assertTrue(counts.get('DoNothing', 0) <= 3)
128 self.assertTrue(counts.get('AcquireWinToken', 0) <= 4)
129 self.assertTrue(counts.get('GainHealth', 0) <= 3)
131 board = GameBoard.new_game({'cards': [
132 {'card_name': 'card1', 'actions': [{
133 'action_class': 'LoseHealthOrMSB',
134 'required_bits': [], }],
136 {'card_name': 'card2', 'actions': [{
137 'action_class': 'AcquireWinToken',
138 'required_bits': [], }],
140 {'card_name': 'card3', 'actions': [{
141 'action_class': 'GainHealth',
142 'required_bits': [], }],
144 {'card_name': 'card4', 'actions': [{
145 'action_class': 'RotateLocations',
146 'required_bits': [], }],
148 {'card_name': 'card5', 'actions': [{
149 'action_class': 'AllowChessMove',
150 'required_bits': [], }],
152 {'card_name': 'card6', 'actions': [{
153 'action_class': 'DoNothing',
154 'required_bits': [], }],
156 # check creation constraints
159 # Replace center card 12 times and assert invariant still holds
161 board.replace_card((2, 2))
163 # replace a diagonal of cards
165 board.replace_card((x, x))
168 def test_lose_health(self):
169 board = GameBoard.new_game(self.make_deck())
170 self.assertEqual(board.health, 4)
171 state_1 = board.export()
174 self.assertEqual(board.health, 3)
175 state_2 = board.export()
177 self.assert_state(state_1, state_2, exclude=['health'])
179 def test_gain_health(self):
180 board = GameBoard.new_game(self.make_deck())
182 self.assertEqual(board.health, 2)
183 state_1 = board.export()
186 self.assertEqual(board.health, 3)
187 state_2 = board.export()
189 self.assert_state(state_1, state_2, exclude=['health'])
191 def test_gain_health_at_max(self):
192 board = GameBoard.new_game(self.make_deck())
193 self.assertEqual(board.health, 4)
194 state_1 = board.export()
197 self.assertEqual(board.health, 4)
198 state_2 = board.export()
200 self.assert_state(state_1, state_2)
202 def generate_locations(self, override_dict=None):
203 locations_dict = dict(((x, y), '%s%s' % (x, y))
204 for x in range(5) for y in range(5))
206 locations_dict.update(override_dict)
207 return locations_dict
209 def test_shift_locations_north(self):
210 board = GameBoard.new_game(self.make_deck())
211 board.board_locations = self.generate_locations()
212 board.shift_locations('NORTH')
213 self.assertEqual(board.board_locations, self.generate_locations({
214 (2, 0): '21', (2, 1): '23', (2, 3): '24', (2, 4): '20',
217 def test_shift_locations_south(self):
218 board = GameBoard.new_game(self.make_deck())
219 board.board_locations = self.generate_locations()
220 board.shift_locations('SOUTH')
221 self.assertEqual(board.board_locations, self.generate_locations({
222 (2, 0): '24', (2, 1): '20', (2, 3): '21', (2, 4): '23',
225 def test_shift_locations_east(self):
226 board = GameBoard.new_game(self.make_deck())
227 board.board_locations = self.generate_locations()
228 board.shift_locations('EAST')
229 self.assertEqual(board.board_locations, self.generate_locations({
230 (0, 2): '42', (1, 2): '02', (3, 2): '12', (4, 2): '32',
233 def test_shift_locations_west(self):
234 board = GameBoard.new_game(self.make_deck())
235 board.board_locations = self.generate_locations()
236 board.shift_locations('WEST')
237 self.assertEqual(board.board_locations, self.generate_locations({
238 (0, 2): '12', (1, 2): '32', (3, 2): '42', (4, 2): '02',
241 def test_rotate_locations_anticlockwise(self):
242 board = GameBoard.new_game(self.make_deck())
243 board.board_locations = self.generate_locations()
244 board.rotate_locations('ANTICLOCKWISE')
245 self.assertEqual(board.board_locations, self.generate_locations({
246 (1, 1): '21', (2, 1): '31', (3, 1): '32',
247 (1, 2): '11', (3, 2): '33',
248 (1, 3): '12', (2, 3): '13', (3, 3): '23',
251 def test_rotate_locations_anticlockwise_top(self):
252 board = GameBoard.new_game(self.make_deck(), initial_pos=(2, 0))
253 board.board_locations = self.generate_locations()
254 board.rotate_locations('ANTICLOCKWISE')
255 self.assertEqual(board.board_locations, self.generate_locations({
256 (1, 0): '30', (3, 0): '31',
257 (1, 1): '10', (2, 1): '11', (3, 1): '21',
260 def test_rotate_locations_anticlockwise_right(self):
261 board = GameBoard.new_game(self.make_deck(), initial_pos=(0, 2))
262 board.board_locations = self.generate_locations()
263 board.rotate_locations('ANTICLOCKWISE')
264 self.assertEqual(board.board_locations, self.generate_locations({
265 (0, 1): '11', (1, 1): '12',
267 (0, 3): '01', (1, 3): '03',
270 def test_rotate_locations_anticlockwise_corner(self):
271 board = GameBoard.new_game(self.make_deck(), initial_pos=(0, 4))
272 board.board_locations = self.generate_locations()
273 board.rotate_locations('ANTICLOCKWISE')
274 self.assertEqual(board.board_locations, self.generate_locations({
275 (0, 3): '13', (1, 3): '14',
279 def test_rotate_locations_clockwise(self):
280 board = GameBoard.new_game(self.make_deck())
281 board.board_locations = self.generate_locations()
282 board.rotate_locations('CLOCKWISE')
283 self.assertEqual(board.board_locations, self.generate_locations({
284 (1, 1): '12', (2, 1): '11', (3, 1): '21',
285 (1, 2): '13', (3, 2): '31',
286 (1, 3): '23', (2, 3): '33', (3, 3): '32',
289 def test_rotate_locations_clockwise_1_3(self):
290 board = GameBoard.new_game(self.make_deck(), initial_pos=(1, 3))
291 board.board_locations = self.generate_locations()
292 board.rotate_locations('CLOCKWISE')
293 self.assertEqual(board.board_locations, self.generate_locations({
294 (0, 2): '03', (1, 2): '02', (2, 2): '12',
295 (0, 3): '04', (2, 3): '22',
296 (0, 4): '14', (1, 4): '24', (2, 4): '23',
299 def test_allow_chess_move_knight(self):
300 board = GameBoard.new_game(self.make_deck())
301 board.allow_chess_move(MOVES.KNIGHT)
302 self.assertEqual(board.player.movement_mode, MOVES.KNIGHT)
304 def test_allow_chess_move_bishop(self):
305 board = GameBoard.new_game(self.make_deck())
306 board.allow_chess_move(MOVES.BISHOP)
307 self.assertEqual(board.player.movement_mode, MOVES.BISHOP)
309 def test_allow_chess_move_castle(self):
310 board = GameBoard.new_game(self.make_deck())
311 board.allow_chess_move(MOVES.CASTLE)
312 self.assertEqual(board.player.movement_mode, MOVES.CASTLE)
315 class TestLocationCard(TestCase):
316 def test_generate_bitwise_operand(self):
317 # This is testing a random process, so it may fail occasionally.
320 operand_sets.append(LocationCard.generate_bitwise_operand())
323 for operand_set in operand_sets:
324 sizes[len(operand_set)] += 1
325 bits.update(operand_set)
326 # TODO: Test that there's at least one condition and one direction.
327 self.assertTrue(sizes[2] > 0)
328 self.assertTrue(sizes[3] > 0)
329 self.assertTrue(sizes[2] > sizes[3])
330 self.assertEqual(bits, set(BITS.values()))
332 def test_new_location_no_actions(self):
333 location = LocationCard.new_location(
334 {'card_name': 'card', 'actions': []}, None)
335 [action] = location.actions
336 self.assertEqual(type(action), actions.DoNothing)
337 self.assertEqual(action.required_bits, set())
338 self.assertEqual(location.replacement_time, None)
340 def test_new_location_replacement_params(self):
341 location = LocationCard.new_location(
342 {'card_name': 'card', 'actions': []},
343 {'chance': 1, 'min': 2, 'max': 2})
344 [action] = location.actions
345 self.assertEqual(type(action), actions.DoNothing)
346 self.assertEqual(action.required_bits, set())
347 self.assertEqual(location.replacement_time, 2)
349 def test_new_location_one_action(self):
350 location = LocationCard.new_location({
351 'card_name': 'card1',
353 {'required_bits': [], 'action_class': 'DoNothing'},
355 [action] = location.actions
356 self.assertEqual(type(action), actions.DoNothing)
357 self.assertEqual(action.required_bits, set())
358 self.assertEqual(location.replacement_time, None)