is_move_valid should be complete(-ish) and tested
This commit is contained in:
parent
dbd18b603f
commit
77f5e74785
63
board.py
63
board.py
|
@ -23,6 +23,14 @@ class Board:
|
|||
# bar. A fix of this is of course to check if the from_idx = bar and if so,
|
||||
# allow some extra stuff!
|
||||
|
||||
@staticmethod
|
||||
def idxs_with_checkers_of_player(board, player):
|
||||
idxs = []
|
||||
for idx, checker_count in enumerate(board):
|
||||
if checker_count * player >= 1:
|
||||
idxs.append(idx)
|
||||
return idxs
|
||||
|
||||
# TODO: write tests
|
||||
# FIXME: make sure to disallow backwards movement
|
||||
# TODO: implement double roll feature (4 dice if dice are equal)
|
||||
|
@ -43,7 +51,8 @@ class Board:
|
|||
delta = to_idx - from_idx
|
||||
direction = sign(delta)
|
||||
bearing_off = None
|
||||
|
||||
|
||||
# FIXME: Use get instead of array-like indexing
|
||||
if to_idx >= 1 and to_idx <= 24:
|
||||
to_state = board[to_idx]
|
||||
bearing_off = False
|
||||
|
@ -85,8 +94,24 @@ class Board:
|
|||
return True
|
||||
|
||||
def can_bear_off():
|
||||
checker_idxs = Board.idxs_with_checkers_of_player(board, player)
|
||||
def is_moving_backmost_checker():
|
||||
if player == 1:
|
||||
return all([(idx >= from_idx) for idx in checker_idxs])
|
||||
else:
|
||||
return all([(idx <= from_idx) for idx in checker_idxs])
|
||||
|
||||
def all_checkers_in_last_quadrant():
|
||||
if player == 1:
|
||||
return all([(idx >= 19) for idx in checker_idxs])
|
||||
else:
|
||||
return all([(idx >= 6) for idx in checker_idxs])
|
||||
|
||||
return all([ is_moving_backmost_checker(),
|
||||
all_checkers_in_last_quadrant() ])
|
||||
|
||||
# TODO
|
||||
return True
|
||||
# TODO: add switch here instead of wonky ternary in all
|
||||
|
||||
|
||||
return all([ is_forward_move(),
|
||||
|
@ -94,15 +119,12 @@ class Board:
|
|||
bear_in_if_checker_on_bar(),
|
||||
checkers_at_from_idx(),
|
||||
no_block_at_to_idx(),
|
||||
can_bear_off() if bearing_off else True])
|
||||
can_bear_off() if bearing_off else True ])
|
||||
|
||||
@staticmethod
|
||||
def is_winner(board, player):
|
||||
for i in range(1,25):
|
||||
if player * board[i] > 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
return Board.idxs_with_checkers_of_player(board, player) == []
|
||||
|
||||
@staticmethod
|
||||
def calculate_legal_states(board, player, roll):
|
||||
# Find all pips with things on them belonging to the player
|
||||
|
@ -114,25 +136,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 idxs_with_checkers_of_current_player(board):
|
||||
idxs = []
|
||||
for idx, checker_count in enumerate(board):
|
||||
if checker_count * player >= 1:
|
||||
idxs.append(idx)
|
||||
return idxs
|
||||
|
||||
def calc_moves(board, face_value):
|
||||
idxs_with_checkers = idxs_with_checkers_of_current_player(board)
|
||||
idxs_with_checkers = Board.idxs_with_checkers_of_player(board, player)
|
||||
boards = [(do_move(board,
|
||||
player,
|
||||
(idx, idx + (face_value * player))) if
|
||||
is_move_valid(board,
|
||||
player,
|
||||
face_value,
|
||||
(idx, idx + (face_value * player))) else None)
|
||||
for idx
|
||||
in idxs_with_checkers]
|
||||
(idx, idx + (face_value * player)))
|
||||
if 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):
|
||||
|
@ -152,7 +167,7 @@ class Board:
|
|||
# Calculate boards resulting from first move
|
||||
boards = calc_moves(board, pair[0])
|
||||
|
||||
for x in dice_permutations[1:None]:
|
||||
for x in dice_permutations[1:]:
|
||||
# Calculate boards resulting from second move
|
||||
nested_boards = [calc_moves(board, x) for board in boards]
|
||||
boards = [board for boards in nested_boards for board in boards]
|
||||
|
|
163
test.py
163
test.py
|
@ -2,21 +2,21 @@ import unittest
|
|||
from board import Board
|
||||
|
||||
class TestIsMoveValid(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.initial = Board.initial_state
|
||||
|
||||
|
||||
def test_simple_movement(self):
|
||||
board = Board.initial_state
|
||||
self.assertEqual(Board.is_move_valid(board, 1, 2, (1, 3)), True) # White
|
||||
self.assertEqual(Board.is_move_valid(board, -1, 3, (24, 21)), True) # Black
|
||||
self.assertEqual(Board.is_move_valid(self.initial, 1, 2, (1, 3)), True) # White
|
||||
self.assertEqual(Board.is_move_valid(self.initial, -1, 3, (24, 21)), True) # Black
|
||||
|
||||
def test_backwards_movement_invalid(self):
|
||||
board = Board.initial_state
|
||||
self.assertEqual(Board.is_move_valid(board, 1, 2, (12, 10)), False)
|
||||
self.assertEqual(Board.is_move_valid(board, -1, 3, (8, 11)), False)
|
||||
self.assertEqual(Board.is_move_valid(self.initial, 1, 2, (12, 10)), False)
|
||||
self.assertEqual(Board.is_move_valid(self.initial, -1, 3, (8, 11)), False)
|
||||
|
||||
def test_face_value_match_move_length(self):
|
||||
board = Board.initial_state
|
||||
self.assertEqual(Board.is_move_valid(board, 1, 2, (1, 3)), True)
|
||||
self.assertEqual(Board.is_move_valid(board, 1, 2, (1, 4)), False)
|
||||
self.assertEqual(Board.is_move_valid(self.initial, 1, 2, (1, 3)), True)
|
||||
self.assertEqual(Board.is_move_valid(self.initial, 1, 2, (1, 4)), False)
|
||||
|
||||
def test_bear_in(self):
|
||||
board = [ 1,
|
||||
|
@ -57,16 +57,14 @@ class TestIsMoveValid(unittest.TestCase):
|
|||
|
||||
|
||||
def test_owned_checker_at_from(self):
|
||||
board = Board.initial_state
|
||||
self.assertEqual(Board.is_move_valid(board, 1, 2, (3, 5)), False) # No checkers
|
||||
self.assertEqual(Board.is_move_valid(board, -1, 2, (23, 21)), False) # No checkers
|
||||
self.assertEqual(Board.is_move_valid(board, 1, 2, (8, 10)), False) # Opponent checkers
|
||||
self.assertEqual(Board.is_move_valid(board, -1, 2, (1, 3)), False) # Opponent checkers
|
||||
self.assertEqual(Board.is_move_valid(self.initial, 1, 2, (3, 5)), False) # No checkers
|
||||
self.assertEqual(Board.is_move_valid(self.initial, -1, 2, (23, 21)), False) # No checkers
|
||||
self.assertEqual(Board.is_move_valid(self.initial, 1, 2, (8, 10)), False) # Opponent checkers
|
||||
self.assertEqual(Board.is_move_valid(self.initial, -1, 2, (1, 3)), False) # Opponent checkers
|
||||
|
||||
def test_no_block_at_to(self):
|
||||
board = Board.initial_state
|
||||
self.assertEqual(Board.is_move_valid(board, 1, 5, (1, 6)), False)
|
||||
self.assertEqual(Board.is_move_valid(board, -1, 5, (24, 19)), False)
|
||||
self.assertEqual(Board.is_move_valid(self.initial, 1, 5, (1, 6)), False)
|
||||
self.assertEqual(Board.is_move_valid(self.initial, -1, 5, (24, 19)), False)
|
||||
|
||||
def test_able_to_hit_opponent_checkers(self):
|
||||
board = [ 0,
|
||||
|
@ -88,7 +86,138 @@ class TestIsMoveValid(unittest.TestCase):
|
|||
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,
|
||||
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 ]
|
||||
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,
|
||||
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 ]
|
||||
self.assertEqual(Board.is_move_valid(board, 1, 1, (24, 25)), False)
|
||||
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 ]
|
||||
self.assertEqual(Board.is_move_valid(board, 1, 1, (24, 25)), False)
|
||||
|
||||
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 ]
|
||||
self.assertEqual(Board.is_move_valid(board, -1, 1, (1, 0)), False)
|
||||
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 ]
|
||||
self.assertEqual(Board.is_move_valid(board, -1, 1, (1, 0)), False)
|
||||
|
||||
# TODO: More tests for bearing off are needed
|
||||
|
||||
|
||||
class TestIsWinner(unittest.TestCase):
|
||||
def test_is_winner(self):
|
||||
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 ]
|
||||
self.assertEqual(Board.is_winner(board, 1), False)
|
||||
self.assertEqual(Board.is_winner(board, -1), True)
|
||||
|
||||
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 ]
|
||||
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,
|
||||
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,
|
||||
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 ]
|
||||
self.assertEqual(Board.do_move(board, -1, (3, 2)), expected_board)
|
||||
|
||||
def test_bear_in(self):
|
||||
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,
|
||||
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 ]
|
||||
self.assertEqual(Board.do_move(board, 1, (0, 1)), expected_board)
|
||||
|
||||
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,
|
||||
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 ]
|
||||
self.assertEqual(Board.do_move(board, -1, (25, 24)), expected_board)
|
||||
|
||||
def test_bear_off(self):
|
||||
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 ]
|
||||
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,
|
||||
-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 ]
|
||||
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)
|
||||
self.assertEqual(Board.do_move(board, -1, (1, -4)), expected_board)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
Loading…
Reference in New Issue
Block a user