is_move_valid should be complete(-ish) and tested

This commit is contained in:
Christoffer Müller Madsen 2018-02-15 12:21:42 +01:00
parent dbd18b603f
commit 77f5e74785
2 changed files with 185 additions and 41 deletions

View File

@ -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
View File

@ -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()