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.cup = Cup() 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