from collections import defaultdict from copy import deepcopy E = "_" # no pawn O = "O" # pawn _ = " " # empty space COLS = "ABCDEFG" ROWS = "1234567" STARTING_BOARD = [ [_, _, O, O, O, _, _], [_, _, O, O, O, _, _], [O, O, O, O, O, O, O], [O, O, O, E, O, O, O], [O, O, O, O, O, O, O], [_, _, O, O, O, _, _], [_, _, O, O, O, _, _], ] def translate_rc_pos(r, c): return COLS[c] + ROWS[r] def translate_pos_rc(pos): return ROWS.find(pos[1]), COLS.find(pos[0]) def gen_around(r, c, board): moves = [] pawn = board[r][c] if pawn in [_, E]: return [] # pawn exists cur_pawn = translate_rc_pos(r, c) # bottom pawn if c + 2 < len(board[r]): r_pawn = board[r][c + 1] rr_pawn = board[r][c + 2] if r_pawn == O and rr_pawn == E: next_pawn = translate_rc_pos(r, c + 2) moves.append(cur_pawn + next_pawn) # top pawn if c - 2 >= 0: r_pawn = board[r][c - 1] rr_pawn = board[r][c - 2] if r_pawn == O and rr_pawn == E: next_pawn = translate_rc_pos(r, c - 2) moves.append(cur_pawn + next_pawn) # right pawn if r + 2 < len(board): r_pawn = board[r + 1][c] rr_pawn = board[r + 2][c] if r_pawn == O and rr_pawn == E: next_pawn = translate_rc_pos(r + 2, c) moves.append(cur_pawn + next_pawn) # left pawn if r - 2 >= 0: r_pawn = board[r - 1][c] rr_pawn = board[r - 2][c] if r_pawn == O and rr_pawn == E: next_pawn = translate_rc_pos(r - 2, c) moves.append(cur_pawn + next_pawn) return moves def gen_moves(board): moves = [] for r, row in enumerate(board): for c, pawn in enumerate(row): if pawn == O: pos_moves = gen_around(r, c, board) moves += pos_moves return moves def play_move(move, board): move = move.upper() start_pos, end_pos = move[0:2], move[2:4] # start row, start column; end row, end column sr, sc = translate_pos_rc(start_pos) er, ec = translate_pos_rc(end_pos) assert board[sr][sc] == O, "starting position is not pawn" assert board[er][ec] == E, "ending position is not empty" if ec == sc: if er - sr == 2: assert board[er - 1][ec] == O, "No pawn in between (ec==sc, er-sr)" board[er - 1][ec] = E elif sr - er == 2: assert board[er + 1][ec] == O, "No pawn in between (ec==sc, sr-er)" board[er + 1][ec] = E else: raise Exception("There must be a pawn in between.") elif er == sr: if ec - sc == 2: assert board[er][ec - 1] == O, "No pawn in between (er==sr, ec-sc)" board[er][ec - 1] = E elif sc - ec == 2: assert board[er][ec + 1] == O, "No pawn in between (er==sr, sc-ec)" board[er][ec + 1] = E else: raise Exception("There must be a pawn in between.") else: raise Exception("You can only jump 1.") board[sr][sc] = E board[er][ec] = O return board def undo_move(move, board): move = move.upper() start_pos, end_pos = move[2:4], move[0:2] sr, sc = translate_pos_rc(start_pos) er, ec = translate_pos_rc(end_pos) assert board[sr][sc] == O, "starting position is not pawn" assert board[er][ec] == E, "ending position is not empty" if ec == sc: if er - sr == 2: assert board[er - 1][ec] == E, "pawn in between (ec==sc, er-sr)" board[er - 1][ec] = O elif sr - er == 2: assert board[er + 1][ec] == E, "pawn in between (ec==sc, sr-er)" board[er + 1][ec] = O else: raise Exception("There must NOT be a pawn in between.") elif er == sr: if ec - sc == 2: assert board[er][ec - 1] == E, "pawn in between (er==sr, ec-sc)" board[er][ec - 1] = O elif sc - ec == 2: assert board[er][ec + 1] == E, "pawn in between (er==sr, sc-ec)" board[er][ec + 1] = O else: raise Exception("There must NOT be a pawn in between.") else: raise Exception("You can only jump 1.") board[sr][sc] = E board[er][ec] = O return board def print_board(board): print(" ", end="") for r in COLS: print(" ", r, " ", end="") print() for c, row in zip(ROWS, board): print(c, row, end="") print() def count_pawns(board): count = 0 for row in board: for pawn in row: if pawn == O: count += 1 return count def play(): moves_this_game = [] stat = dict( moves=defaultdict(int), num_moves=0, ) board = deepcopy(STARTING_BOARD) i = 0 while True: print("MOVE: {}".format(i)) print_board(board) moves = gen_moves(board) stat["moves"][len(moves)] += 1 print("MOVES: {}".format(moves)) if len(moves) == 0: print("No valid moves left") break # this_move = random.choice(moves)\ # print("Chose Move: {}".format(this_move)) this_move = input("> ") moves_this_game.append(this_move) try: board = play_move(this_move, board) except Exception as e: print("invalid move") print(e) continue i += 1 stat["num_moves"] = i return board, moves_this_game, stat def main_play(): game_no = 1 gauss = defaultdict(int) while True: board, moves_this_game, stat = play() count = count_pawns(board) # print("{} Left pawns: {} | {} | {}".format(game_no, count, stat["num_moves"], sorted([(a,b) for a, b in stat['moves'].items()], key=lambda x: x[1], reverse=True))) print("{} Left pawns: {}".format(game_no, count)) gauss[count] += 1 game_no += 1 if count == 1: print("Moves this game: {}".format(moves_this_game)) print("FINISHED!") break HASHES = {} def rot_board(board): A = deepcopy(board) N = len(A[0]) for i in range(N // 2): for j in range(i, N - i - 1): temp = A[i][j] A[i][j] = A[N - 1 - j][i] A[N - 1 - j][i] = A[N - 1 - i][N - 1 - j] A[N - 1 - i][N - 1 - j] = A[j][N - 1 - i] A[j][N - 1 - i] = temp return A def hash_board(board): the_hash, cnt = "", 0 prev_cell = None for row in board: for cell in row: if cell == _: continue if prev_cell is not None and prev_cell != cell: the_hash += "{}{}|".format(cnt, prev_cell) cnt = 0 prev_cell = cell cnt += 1 if cnt != 0: the_hash += "{}{}".format(cnt, prev_cell) return the_hash def rot_hash_board(board): value = len(HASHES) for i in range(4): hash0 = hash_board(board) HASHES[hash0] = value board = rot_board(board) class Node(object): def __init__(self, board, move, parent_node): self.parent = parent_node self.board = board self.move = move if self.parent: self.moves = self.parent.moves + [move] else: if move: self.moves = [move] else: self.moves = [] self.visited = False self.complete = False self.children = gen_moves(self.board) def iterative_main(): board = deepcopy(STARTING_BOARD) moves_this_game = [] while True: moves = gen_moves(board) if len(moves) <= 0: print("finished") pawns = count_pawns(board) if pawns == 1: print(moves_this_game) break print_board(board) print(moves_this_game) rot_hash_board(board) this_move = moves_this_game[-1] board = undo_move(this_move, board) else: this_move = moves[0] moves_this_game.append(this_move) board = play_move(this_move, board) def main(): root = Node(board=STARTING_BOARD, move=None, parent_node=None) node = root while True: if len(node.moves) == 0: pawns_left = count_pawns(node.board) if pawns_left == 1: print("WIN") break else: # backtrack node.visited = True board = undo_move(node.move, node.board) else: # there is at least one move move = moves[0] new_board = play_move(move, node.board) node = Node(new_board, move, node) if __name__ == "__main__": main()