diff --git a/board.py b/board.py index d55f92a..0f1d701 100644 --- a/board.py +++ b/board.py @@ -3,12 +3,12 @@ import itertools class Board: - initial_state = [ 0, + initial_state = ( 0, 2, 0, 0, 0, 0, -5, 0, -3, 0, 0, 0, 5, -5, 0, 0, 0, 3, 0, 5, 0, 0, 0, 0, -2, - 0 ] + 0 ) # TODO: Remember to handle pushing other pieces to home # TODO: Also remember that a player can't move backwards and the one @@ -145,23 +145,18 @@ class Board: # TODO: make sure that it is not possible to do nothing on first part of # turn and then do something with the second die - print("Find legal moves: ",roll,"-"*20) def calc_moves(board, face_value): idxs_with_checkers = Board.idxs_with_checkers_of_player(board, player) - boards = [(do_move(board, + boards = [(Board.do_move(board, player, (idx, idx + (face_value * player))) - if is_move_valid(board, - player, - face_value, - (idx, idx + (face_value * player))) + if Board.is_move_valid(board, + player, + face_value, + (idx, idx + (face_value * player))) else None) for idx in idxs_with_checkers] - - # If no move can be made, make sure to include current board - if is_move_valid(board, player, face_value, None): - boards.append(board) return list(filter(None, boards)) # Remove None-values @@ -171,15 +166,18 @@ class Board: legal_moves = set() + if not Board.any_move_valid(board, player, roll): + return { board } + dice_permutations = list(itertools.permutations(roll)) if roll[0] != roll[1] else [[roll[0]]*4] - for pair in dice_permutations: + for roll in dice_permutations: # Calculate boards resulting from first move - boards = calc_moves(board, pair[0]) + boards = calc_moves(board, roll[0]) - for x in dice_permutations[1:]: + for die in roll[1:]: # Calculate boards resulting from second move - nested_boards = [calc_moves(board, x) for board in boards] + nested_boards = [calc_moves(board, die) for board in boards] boards = [board for boards in nested_boards for board in boards] # Add resulting unique boards to set of legal boards resulting from roll legal_moves = legal_moves | set(boards) @@ -217,14 +215,14 @@ class Board: board[25] += player board[to_idx] = 0 - return board + return tuple(board) # TODO: Moving in from bar is handled by the representation # TODONE: Handle bearing off from_idx = move[0] to_idx = move[1] - board = list(board) # Clone board + board = list(board) # Make mutable copy of board # 'Lift' checker board[from_idx] -= player @@ -240,4 +238,4 @@ class Board: # Put down checker board[to_idx] += player - return board + return tuple(board) diff --git a/test.py b/test.py index 3467d56..c9c40a9 100644 --- a/test.py +++ b/test.py @@ -19,39 +19,39 @@ class TestIsMoveValid(unittest.TestCase): self.assertEqual(Board.is_move_valid(self.initial, 1, 2, (1, 4)), False) def test_bear_in(self): - board = [ 1, + board = ( 1, 1, 0, 0, 0, 0, -5, 0, -3, 0, 0, 0, 5, -5, 0, 0, 0, 3, 0, 5, 0, 0, 0, 0, -2, - 0 ] + 0 ) self.assertEqual(Board.is_move_valid(board, 1, 2, (0, 2)), True) - board = [ 0, + board = ( 0, 2, 0, 0, 0, 0, -5, 0, -3, 0, 0, 0, 5, -5, 0, 0, 0, 3, 0, 5, 0, 0, 0, 0, -1, - -1 ] + -1 ) self.assertEqual(Board.is_move_valid(board, -1, 2, (25, 23)), True) def test_force_bear_in(self): - board = [ 1, + board = ( 1, 1, 0, 0, 0, 0, -5, 0, -3, 0, 0, 0, 5, -5, 0, 0, 0, 3, 0, 5, 0, 0, 0, 0, -2, - 0 ] + 0 ) self.assertEqual(Board.is_move_valid(board, 1, 2, (1, 3)), False) self.assertEqual(Board.is_move_valid(board, -1, 3, (24, 21)), True) - board = [ 0, + board = ( 0, 2, 0, 0, 0, 0, -5, 0, -3, 0, 0, 0, 5, -5, 0, 0, 0, 3, 0, 5, 0, 0, 0, 0, -1, - -1 ] + -1 ) self.assertEqual(Board.is_move_valid(board, -1, 2, (24, 22)), False) self.assertEqual(Board.is_move_valid(board, 1, 2, (1, 3)), True) @@ -67,65 +67,65 @@ class TestIsMoveValid(unittest.TestCase): self.assertEqual(Board.is_move_valid(self.initial, -1, 5, (24, 19)), False) def test_able_to_hit_opponent_checkers(self): - board = [ 0, + board = ( 0, 2, 0, 0, -1, 0, -4, 0, -3, 0, 0, 0, 5, -5, 0, 0, 0, 3, 0, 4, 0, 1, 0, 0, -2, - 0 ] + 0 ) self.assertEqual(Board.is_move_valid(board, 1, 3, (1, 4)), True) self.assertEqual(Board.is_move_valid(board, -1, 3, (24, 21)), True) def test_bear_off_simple(self): - board = [ 0, + board = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 0 ] + 0 ) self.assertEqual(Board.is_move_valid(board, 1, 2, (24, 26)), True) self.assertEqual(Board.is_move_valid(board, 1, 1, (24, 25)), True) def test_bear_off_with_higher_face_value(self): - board = [ 0, + board = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, - 0 ] + 0 ) self.assertEqual(Board.is_move_valid(board, 1, 5, (23, 28)), False) self.assertEqual(Board.is_move_valid(board, 1, 5, (22, 27)), True) def test_bear_off_all_in_last_quadrant(self): - board = [ 0, + board = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 0 ] + 0 ) self.assertEqual(Board.is_move_valid(board, 1, 1, (24, 25)), False) - board = [ 1, + board = ( 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 0 ] + 0 ) self.assertEqual(Board.is_move_valid(board, 1, 1, (24, 25)), False) - board = [ 0, + board = ( 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - -1 ] + -1 ) self.assertEqual(Board.is_move_valid(board, -1, 1, (1, 0)), False) - board = [ 0, + board = ( 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 ] + 0 ) self.assertEqual(Board.is_move_valid(board, -1, 1, (1, 0)), False) # TODO: More tests for bearing off are needed @@ -133,87 +133,87 @@ class TestIsMoveValid(unittest.TestCase): class TestIsWinner(unittest.TestCase): def test_is_winner(self): - board = [ 0, + board = ( 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 3, 0, 4, 0, 1, 0, 0, 0, - 0 ] + 0 ) self.assertEqual(Board.is_winner(board, 1), False) self.assertEqual(Board.is_winner(board, -1), True) - board = [ 0, + board = ( 0, 0, 0, 0, -1, 0, -4, 0, -3, 0, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, - 0 ] + 0 ) self.assertEqual(Board.is_winner(board, 1), True) self.assertEqual(Board.is_winner(board, -1), False) class TestDoMove(unittest.TestCase): def test_simple_move(self): - board = [ 0, + board = ( 0, 2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 3, 0, 4, 0, 1, 0, 0, 0, - 0 ] - expected_board = [ 0, + 0 ) + expected_board = ( 0, 2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 3, 0, 4, 0, 1, 0, 0, 0, - 0 ] + 0 ) self.assertEqual(Board.do_move(board, -1, (3, 2)), expected_board) def test_bear_in(self): - board = [ 1, + board = ( 1, 1, 0, 0, 0, 0, -5, 0, -3, 0, 0, 0, 5, -5, 0, 0, 0, 3, 0, 5, 0, 0, 0, 0, -2, - 0 ] - expected_board = [ 0, + 0 ) + expected_board = ( 0, 2, 0, 0, 0, 0, -5, 0, -3, 0, 0, 0, 5, -5, 0, 0, 0, 3, 0, 5, 0, 0, 0, 0, -2, - 0 ] + 0 ) self.assertEqual(Board.do_move(board, 1, (0, 1)), expected_board) - board = [ 0, + board = ( 0, 2, 0, 0, 0, 0, -5, 0, -3, 0, 0, 0, 5, -5, 0, 0, 0, 3, 0, 5, 0, 0, 0, 0, -1, - -1 ] - expected_board = [ 0, + -1 ) + expected_board = ( 0, 2, 0, 0, 0, 0, -5, 0, -3, 0, 0, 0, 5, -5, 0, 0, 0, 3, 0, 5, 0, 0, 0, 0, -2, - 0 ] + 0 ) self.assertEqual(Board.do_move(board, -1, (25, 24)), expected_board) def test_bear_off(self): - board = [ 0, + board = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 0 ] + 0 ) expected_board = [0] * 26 self.assertEqual(Board.do_move(board, 1, (24, 30)), expected_board) self.assertEqual(Board.do_move(board, 1, (24, 26)), expected_board) self.assertEqual(Board.do_move(board, 1, (24, 25)), expected_board) - board = [ 0, + board = ( 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 ] + 0 ) expected_board = [0] * 26 self.assertEqual(Board.do_move(board, -1, (1, 0)), expected_board) self.assertEqual(Board.do_move(board, -1, (1, -1)), expected_board) @@ -221,24 +221,24 @@ class TestDoMove(unittest.TestCase): class TestAnyMoveValid(unittest.TestCase): def test_bear_in_but_blocked(self): - board = [ 0, + board = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 2, 2, 2, - -1 ] + -1 ) self.assertEqual(Board.any_move_valid(board, -1, (3,6)), False) self.assertEqual(Board.any_move_valid(board, -1, (6,3)), False) self.assertEqual(Board.any_move_valid(board, -1, (3,4)), True) self.assertEqual(Board.any_move_valid(board, -1, (4,1)), True) def test_simple_block(self): - board = [ 0, + board = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, -1, 0, 0, 0, - 0 ] + 0 ) self.assertEqual(Board.any_move_valid(board, -1, (1,1)), False) self.assertEqual(Board.any_move_valid(board, -1, (2,2)), False) self.assertEqual(Board.any_move_valid(board, -1, (2,1)), False) @@ -246,7 +246,31 @@ class TestAnyMoveValid(unittest.TestCase): self.assertEqual(Board.any_move_valid(board, -1, (3,1)), True) self.assertEqual(Board.any_move_valid(board, -1, (1,3)), True) self.assertEqual(Board.any_move_valid(board, -1, (4,4)), True) - + +class TestLegalMoves(unittest.TestCase): + def test_blocked(self): + board = ( 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2, 2, -1, 0, 0, 0, + 0 ) + expected_board_set_3_1 = {( 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -1, 0, + 2, 2, 0, 0, 0, 0, + 0 )} + expected_board_set_3_4 = {( 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, -1, 0, 0, 0, 0, + 2, 2, 0, 0, 0, 0, + 0 )} + self.assertEqual(Board.calculate_legal_states(board, -1, (1,2)), { board }) + self.assertEqual(Board.calculate_legal_states(board, -1, (1,1)), { board }) + self.assertEqual(Board.calculate_legal_states(board, -1, (3,1)), expected_board_set_3_1) + self.assertEqual(Board.calculate_legal_states(board, -1, (3,4)), expected_board_set_3_4) if __name__ == '__main__': unittest.main()