From: adrianna Date: Fri, 16 May 2014 00:40:49 +0000 (+0200) Subject: chess moves are working; need more tests X-Git-Tag: 0.1~243 X-Git-Url: https://git.ctpug.org.za/?p=naja.git;a=commitdiff_plain;h=aac1783aa9c84031bb37d74616ee72a7b32ebeac chess moves are working; need more tests --- diff --git a/data/location_decks/test.yaml b/data/location_decks/test.yaml index a2a6e49..3c65032 100644 --- a/data/location_decks/test.yaml +++ b/data/location_decks/test.yaml @@ -47,4 +47,16 @@ cards: - bits: [RED, GREEN] # colour-blind robot! actions: - action_class: 'ToggleBits' - required_bits: [GREEN] \ No newline at end of file + required_bits: [GREEN] + - actions: + - action_class: 'AllowChessMove' + required_bits: [RED, BLUE] + data: {'chesspiece': KNIGHT} + - actions: + - action_class: 'AllowChessMove' + required_bits: [RED, BLUE] + data: {'chesspiece': BISHOP} + - actions: + - action_class: 'AllowChessMove' + required_bits: [RED, BLUE] + data: {'chesspiece': CASTLE} diff --git a/naja/actions.py b/naja/actions.py index 0535c8b..f92961c 100644 --- a/naja/actions.py +++ b/naja/actions.py @@ -1,4 +1,4 @@ -from naja.constants import BITS +from naja.constants import BITS, CHESS_PIECES class LocationAction(object): @@ -15,6 +15,7 @@ class LocationAction(object): def get_text(self): substitutions = self.data.copy() + if 'direction' in self.data: substitutions['rowcol'] = { 'NORTH': 'column', @@ -22,6 +23,10 @@ class LocationAction(object): 'EAST': 'row', 'WEST': 'row', }[self.data['direction']] + + if 'chesspiece' in self.data: + substitutions['chesspiece_name'] = self.data['chesspiece'].lower() + return self.TEXT % substitutions def check_available(self, player): @@ -108,3 +113,12 @@ class ShiftLocations(LocationAction): def perform_action(self, board, location): board.shift_locations(self.data['direction']) + + +class AllowChessMove(LocationAction) : + TEXT = "Move like a %(chesspiece_name)s for one turn." + + def perform_action(self, board, location): + if self.data['chesspiece'] in CHESS_PIECES: + chesspiece = CHESS_PIECES[self.data['chesspiece']] + board.allow_chess_move(chesspiece) diff --git a/naja/constants.py b/naja/constants.py index 96824f4..f81cb8f 100644 --- a/naja/constants.py +++ b/naja/constants.py @@ -39,6 +39,17 @@ BITS = AttrDict({ DIRECTION_BITS = AttrDict((k, v) for k, v in BITS.items() if v < 4) CONDITION_BITS = AttrDict((k, v) for k, v in BITS.items() if v >= 4) +# PLAYER MOVES +MOVES = AttrDict({ + # Default move + 'ADJACENT': 0, + # Chess moves + 'KNIGHT': 1, + 'BISHOP': 2, + 'CASTLE': 3, +}) +CHESS_PIECES = AttrDict((k, v) for k, v in MOVES.items() if v > 0) + # Player defaults PLAYER_DEFAULTS = AttrDict({ 'INITIAL_BITS': 0x0f, diff --git a/naja/gameboard.py b/naja/gameboard.py index 3717b56..367a9e1 100644 --- a/naja/gameboard.py +++ b/naja/gameboard.py @@ -130,6 +130,9 @@ class GameBoard(object): elif BITS[direction] == BITS.WEST: self.shift_location_row(-1, is_vertical=False) + def allow_chess_move(self, chesspiece): + self.player.allow_chess_move(chesspiece) + def change_mode(self, new_mode): """Advance to the next mode""" if new_mode == self.player_mode: diff --git a/naja/player.py b/naja/player.py index f502b64..2f6fdcf 100644 --- a/naja/player.py +++ b/naja/player.py @@ -1,4 +1,4 @@ -from naja.constants import BITS +from naja.constants import BITS, MOVES, CHESS_PIECES class PlayerBits(object): @@ -55,53 +55,97 @@ class Player(object): A representation of the player. """ - def __init__(self, bits, position): + def __init__(self, bits, position, movement_mode=None): self.bits = PlayerBits(bits) self.position = position + self.movement_mode = movement_mode if movement_mode else MOVES.ADJACENT @classmethod def import_player(cls, definition): - return cls(definition['bits'], tuple(definition['position'])) + return cls(definition['bits'], tuple(definition['position']), definition['movement_mode']) def export(self): return { 'bits': self.bits.bits, 'position': list(self.position), + 'movement_mode': self.movement_mode, } - def get_adjacent_position(self, direction): + def get_adjacent_positions(self): + positions = [self.position] + x, y = self.position - if direction == BITS.NORTH and y > 0: - return (x, y - 1) - elif direction == BITS.SOUTH and y < 4: - return (x, y + 1) - elif direction == BITS.EAST and x < 4: - return (x + 1, y) - elif direction == BITS.WEST and x > 0: - return (x - 1, y) - else: - # Not a legal space. - return None - - def move(self, direction): - if not self.bits.check_bit(direction): - return False - new_position = self.get_adjacent_position(direction) - if new_position is not None: - self.position = new_position - return True - return False + + if self.bits.check_bit(BITS.NORTH) and y > 0: + positions.append((x, y - 1)) + if self.bits.check_bit(BITS.SOUTH) and y < 4: + positions.append((x, y + 1)) + if self.bits.check_bit(BITS.EAST) and x < 4: + positions.append((x + 1, y)) + if self.bits.check_bit(BITS.WEST) and x > 0: + positions.append((x - 1, y)) + + return positions + + def get_knight_positions(self): + positions = set([self.position]) + + x, y = self.position + + for a in (2, -2): + for b in (1, -1): + i, j = x + a, y + b + if 0 <= i < 5 and 0 <= j < 5: + positions.add((i, j)) + + i, j = x + b, y + a + if 0 <= i < 5 and 0 <= j < 5: + positions.add((i, j)) + + return sorted(list(positions)) + + def get_bishop_positions(self): + positions = set() + + x, y = self.position + + for i in range(5): + j = i + y - x + if 0 <= j < 5: + positions.add((i, j)) + + j = x + y - i + if 0 <= j < 5: + positions.add((i, j)) + + return sorted(list(positions)) + + def get_castle_positions(self): + positions = set() + + x, y = self.position + + for i in range(5): + positions.add((x, i)) + positions.add((i, y)) + + return sorted(list(positions)) def set_position(self, new_position): if new_position in self.legal_moves(): self.position = new_position + self.movement_mode = MOVES.ADJACENT return True return False def legal_moves(self): - positions = [self.position] - for direction in [BITS.NORTH, BITS.SOUTH, BITS.EAST, BITS.WEST]: - position = self.get_adjacent_position(direction) - if position is not None and self.bits.check_bit(direction): - positions.append(position) - return positions + POSITION_FUNCTION = { + MOVES.ADJACENT: self.get_adjacent_positions, + MOVES.KNIGHT: self.get_knight_positions, + MOVES.BISHOP: self.get_bishop_positions, + MOVES.CASTLE: self.get_castle_positions, + } + return POSITION_FUNCTION[self.movement_mode]() + + def allow_chess_move(self, chesspiece): + self.movement_mode = chesspiece diff --git a/naja/tests/test_player.py b/naja/tests/test_player.py index 1d11637..d45c09e 100644 --- a/naja/tests/test_player.py +++ b/naja/tests/test_player.py @@ -96,67 +96,27 @@ class TestPlayer(TestCase): player = Player.import_player({ 'bits': 0xaa, 'position': [1, 2], + 'movement_mode': MOVES.CASTLE, }) self.assertEqual(player.bits.bits, 0xaa) self.assertEqual(player.position, (1, 2)) + self.assertEqual(player.movement_mode, MOVES.CASTLE) def test_export_player(self): - player = Player(0xaa, (1, 2)) + player = Player(0xaa, (1, 2), MOVES.CASTLE) self.assertEqual(player.export(), { 'bits': 0xaa, 'position': [1, 2], + 'movement_mode': MOVES.CASTLE, }) - def test_move(self): - player = Player(0x0f, (2, 2)) - self.assertEqual(player.move(BITS.NORTH), True) - self.assertEqual(player.position, (2, 1)) - - player = Player(0x0f, (2, 2)) - self.assertEqual(player.move(BITS.SOUTH), True) - self.assertEqual(player.position, (2, 3)) - - player = Player(0x0f, (2, 2)) - self.assertEqual(player.move(BITS.WEST), True) - self.assertEqual(player.position, (1, 2)) - - player = Player(0x0f, (2, 2)) - self.assertEqual(player.move(BITS.EAST), True) - self.assertEqual(player.position, (3, 2)) - - def test_move_flags_clear(self): - player = Player(0x00, (2, 2)) - self.assertEqual(player.move(BITS.NORTH), False) - self.assertEqual(player.position, (2, 2)) - - player = Player(0x00, (2, 2)) - self.assertEqual(player.move(BITS.SOUTH), False) - self.assertEqual(player.position, (2, 2)) - - player = Player(0x00, (2, 2)) - self.assertEqual(player.move(BITS.WEST), False) - self.assertEqual(player.position, (2, 2)) - - player = Player(0x00, (2, 2)) - self.assertEqual(player.move(BITS.EAST), False) - self.assertEqual(player.position, (2, 2)) - - def test_move_flags_edges(self): - player = Player(0x0f, (2, 0)) - self.assertEqual(player.move(BITS.NORTH), False) - self.assertEqual(player.position, (2, 0)) - - player = Player(0x0f, (2, 4)) - self.assertEqual(player.move(BITS.SOUTH), False) - self.assertEqual(player.position, (2, 4)) - - player = Player(0x0f, (0, 2)) - self.assertEqual(player.move(BITS.WEST), False) - self.assertEqual(player.position, (0, 2)) - - player = Player(0x0f, (4, 2)) - self.assertEqual(player.move(BITS.EAST), False) - self.assertEqual(player.position, (4, 2)) + def test_export_player_default_movement_mode(self): + player = Player(0xaa, (1, 2)) + self.assertEqual(player.export(), { + 'bits': 0xaa, + 'position': [1, 2], + 'movement_mode': MOVES.ADJACENT, + }) def test_legal_moves_all_available(self): player = Player(0x0f, (2, 2)) @@ -167,3 +127,22 @@ class TestPlayer(TestCase): player = Player(0x0f, (0, 2)) player.bits.clear_bit(BITS.NORTH) self.assertEqual(player.legal_moves(), [(0, 2), (0, 3), (1, 2)]) + + def test_legal_moves_castle(self): + player = Player(0x0f, (1, 3), MOVES.CASTLE) + self.assertEqual(player.legal_moves(), [(0, 3), (1, 0), (1, 1), (1, 2), + (1, 3), (1, 4), (2, 3), (3, 3), (4, 3)]) + + def test_legal_moves_bishop(self): + player = Player(0x0f, (1, 3), MOVES.BISHOP) + self.assertEqual(player.legal_moves(), [(0, 2), (0, 4), (1, 3), (2, 2), + (2, 4), (3, 1), (3, 4), (4, 0)]) + + def test_legal_moves_knight(self): + player = Player(0x0f, (1, 3), MOVES.KNIGHT) + self.assertEqual(player.legal_moves(), [(0, 1), (2, 1), (3, 2), (3, 4)]) + + def test_set_position(self): + player = Player(0x0f, (3, 3), MOVES.BISHOP) + player.set_position((4, 4)) + self.assertEqual(player.movement_mode, MOVES.ADJACENT)