Skip to content

Instantly share code, notes, and snippets.

@aflaag
Last active December 17, 2022 19:10
Show Gist options
  • Save aflaag/a3ef5c714fefcbb963bf3f0599b3e9c6 to your computer and use it in GitHub Desktop.
Save aflaag/a3ef5c714fefcbb963bf3f0599b3e9c6 to your computer and use it in GitHub Desktop.
def find_neighbours_opponent(board, x, y, w, h, opponent):
neighbours = set()
up, down, left, right = y > 0, y < h - 1, x > 0, x < w - 1
checks = {
(0, 0): False,
(0, -1): up,
(+1, -1): up and right,
(+1, 0): right,
(+1, +1): down and right,
(0, +1): down,
(-1, +1): down and left,
(-1, 0): left,
(-1, -1): up and left,
}
for increment_y in [-1, 0, 1]:
incremented_y = y + increment_y
for increment_x in [-1, 0, 1]:
incremented_x = x + increment_x
if checks[(increment_x, increment_y)] and board[incremented_y][incremented_x] == opponent:
neighbours.add((incremented_x, incremented_y))
return neighbours
def evaluate_result(board, dim, curr_whites, curr_blacks):
return (1, 0, 0) if curr_blacks > curr_whites else ((0, 1, 0) if curr_blacks < curr_whites else (0, 0, 1))
def solve(board, empty, turn, nodes, w, h, dim, white_pieces, black_pieces):
has_moved = False
blacks, whites, ties = 0, 0, 0
for x, y in empty:
board[y][x] = turn
opponent = not turn
neighbours_opponent = find_neighbours_opponent(board, x, y, w, h, opponent)
l = len(neighbours_opponent)
if l:
for nx, ny in neighbours_opponent:
board[ny][nx] = turn
has_moved = True
key = (tuple(map(tuple, board)), turn)
_b, _w, _t = 0, 0, 0
if key in nodes:
_b, _w, _t = nodes[key]
else:
_b, _w, _t = (solve(board, empty - {(x, y)}, opponent, nodes, w, h, dim, white_pieces + 1 + l, black_pieces - l) if turn else solve(board, empty - {(x, y)}, opponent, nodes, w, h, dim, white_pieces - l, black_pieces + 1 + l))
nodes[key] = _b, _w, _t
blacks += _b
whites += _w
ties += _t
for nx, ny in neighbours_opponent:
board[ny][nx] = opponent
board[y][x] = None
return evaluate_result(board, dim, white_pieces, black_pieces) if not has_moved or not len(empty) else (blacks, whites, ties)
def solve_squared(board, empty, turn, nodes, side, dim, white_pieces, black_pieces):
has_moved = False
blacks, whites, ties = 0, 0, 0
for x, y in empty:
board[y][x] = turn
opponent = not turn
neighbours_opponent = find_neighbours_opponent(board, x, y, side, side, opponent)
l = len(neighbours_opponent)
if l:
for nx, ny in neighbours_opponent:
board[ny][nx] = turn
has_moved = True
key = (tuple(map(tuple, board)), turn)
transposed = tuple(zip(*board))
_b, _w, _t = 0, 0, 0
if key in nodes or transposed in nodes:
_b, _w, _t = nodes[key]
else:
_b, _w, _t = (solve_squared(board, empty - {(x, y)}, opponent, nodes, side, dim, white_pieces + 1 + l, black_pieces - l) if turn else solve_squared(board, empty - {(x, y)}, opponent, nodes, side, dim, white_pieces - l, black_pieces + 1 + l))
nodes[key] = _b, _w, _t
nodes[transposed] = _b, _w, _t
blacks += _b
whites += _w
ties += _t
for nx, ny in neighbours_opponent:
board[ny][nx] = opponent
board[y][x] = None
return evaluate_result(board, dim, white_pieces, black_pieces) if not has_moved or not len(empty) else (blacks, whites, ties)
def dumbothello(filename: str) -> tuple[int, int, int]:
with open(filename) as F:
board = list(map(lambda line: list(map(lambda c: True if c == 'W' else (False if c == 'B' else None), line.split())), F.readlines()))
empty = set((x, y) for y, line in enumerate(board) for x, cell in enumerate(line) if cell == None)
nodes = {}
w = len(board[0])
h = len(board)
dim = w * h
white_pieces = sum(line.count(True) for line in board)
return solve(board, empty, False, nodes, w, h, dim, white_pieces, dim - white_pieces - len(empty)) if w != h else solve_squared(board, empty, False, nodes, w, dim, white_pieces, dim - white_pieces - len(empty))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment