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