From 8c4eb355bf331615ba920ab91dc956794b881d2f Mon Sep 17 00:00:00 2001 From: Daniel Tsvetkov Date: Wed, 29 Dec 2021 19:28:23 +0200 Subject: [PATCH] initial commit --- .gitignore | 2 + main.py | 291 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 293 insertions(+) create mode 100644 .gitignore create mode 100644 main.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f377c56 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +venv +.idea diff --git a/main.py b/main.py new file mode 100644 index 0000000..6fea9bd --- /dev/null +++ b/main.py @@ -0,0 +1,291 @@ +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): + self.board = board + self.moves = gen_moves(board) + self.visited = False + self.children = [] + + +def 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) + this_move = moves[0] + moves_this_game.append(this_move) + board = play_move(this_move, board) + + +if __name__ == "__main__": + main()