backgammon/board.py

129 lines
4.5 KiB
Python

from cup import Cup
import numpy as np
class Board:
# TODO: Remember to handle pushing other pieces to home
# TODO: Also remember that a player can't move backwards and the one
# player goes from 1-47 while the other goes from 47-1
def __init__(self):
self.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, 0 ]
def get_state(self):
return self.state
# Remember to handle edge case when we're on the last moves and you may go
# from position 22 -> 24 on a 6, if you have no pieces behind 22. Simply
# check if any are behind if you're circle or if any are higher if you are
# X, then it can be allowed.
# Also, the check_move will also fail when you're attempting to leave a
# bar. A fix of this is of course to check if the from_idx = bar and if so,
# allow some extra stuff!
# TODO: write tests
# FIXME: make sure to disallow backwards movement
# TODO: implement double roll feature (4 dice if dice are equal)
# TODO: implement moving checkers into home (bearing off)
# TODO: handle barring in a more elengant way
# TODO: allow bearing off with non-exact die roll if this is only possible
# move
def check_move(self, move, player, roll):
from_idx = int(move[0])
to_idx = int(move[1])
to_state = self.state[to_idx]
from_state = self.state[from_idx]
if from_idx == 26:
from_idx = 1
roll -= 1
elif from_idx == 27:
from_idx = 24
roll -= 1
if not (1 <= from_idx <= 24 and
1 <= to_idx <= 24):
return False
elif ( abs( from_idx - to_idx ) != roll ):
return False
elif (from_state * player >= 1 and # Is moving player's own checker?
(to_state * player >= 0 or # Is 'to' empty or has player's own checkers?
to_state * -player == 1)): # Can opponent checker be hit?
return True
def find_pieces_for_player(self, player):
idxs = []
for idx, pip in enumerate(self.state):
if pip * player >= 1:
idxs.append(idx)
return idxs
def is_winner(self, player):
for i in range(1,25):
if player * self.state[i] > 0:
return False
return True
def find_legal_moves(self, player, roll):
# Find all pips with things on them belonging to the player
# Iterate through each index and check if it's a possible move given the roll
# If player is O, then check for idx + roll
# If player is X, then check for idx - roll
# Rewrite this, it's shit.
idxs_with_thing = self.find_pieces_for_player(player)
legal_moves = []
for index in idxs_with_thing:
from_idx = index
to_idx = index+(roll*player)
if self.check_move([from_idx,to_idx], player, roll):
legal_moves.append([from_idx,to_idx])
return legal_moves
def pretty(self):
temp = []
for x in self.state:
if x >= 0:
temp.append(" {}".format(x))
else:
temp.append("{}".format(x))
return """
13 14 15 16 17 18 19 20 21 22 23 24
--------------------------------------------------------------------------
| {12}| {11}| {10}| {9}| {8}| {7}| bar 1: {26} | {6}| {5}| {4}| {3}| {2}| {1}| end -1: {0}|
|---|---|---|---|---|---|-----------|---|---|---|---|---|---|
| {13}| {14}| {15}| {16}| {17}| {18}| bar -1: {27} | {19}| {20}| {21}| {22}| {23}| {24}| end 1: {25}|
--------------------------------------------------------------------------
12 11 10 9 8 7 6 5 4 3 2 1
""".format(*temp)
def move_to_bar(self, to_idx):
# Find the owner of the hit checker
player = self.state[to_idx]
# FIXME: find better bar solution
if player == 1:
self.state[26] += player
else:
self.state[27] += player
self.state[to_idx] = 0
def move_thing(self, player, from_idx, to_idx):
self.state[from_idx] -= player
if self.state[to_idx] * player == -1:
self.move_to_bar(to_idx)
self.state[to_idx] += player