import itertools from pprint import pprint blackMoves = [] whiteMoves = [] boardSize = 19 board = [] blackGroups = [] whiteGroups = [] def get_neighbouring_coordinates(point): neighbours = [] potentialNeighbours = [ (point[0]-1,point[1]), (point[0]+1,point[1]), (point[0],point[1]-1), (point[0],point[1]+1) ] for point in potentialNeighbours: if 1 <= point[0] <= 19 and 1 <= point[1] <= 19: neighbours.append(point) return neighbours def get_neighbouring_groups(position, color): groups = whiteGroups if color == "w" else blackGroups neighbouringGroups = set() neighbours = get_neighbouring_coordinates(position) for point in neighbours: for index, group in enumerate(groups): if point in group: neighbouringGroups.add(index) return list(neighbouringGroups) def get_liberties(group): ret = set() for point in group: neighbours = get_neighbouring_coordinates(point) for neighbour in neighbours: if board[neighbour[0]-1][neighbour[1]-1] == "": ret.add(neighbour) return ret def remove_dead_groups(color): bothGroups = [] # get the order right so that black can kill a white # group by playing into whites only eye (and not killing himself first) if color == "w": bothGroups = whiteGroups + blackGroups else: bothGroups = blackGroups + whiteGroups # remove dead from board for group in bothGroups: if len(get_liberties(group)) == 0: for pos in group: board[pos[0]-1][pos[1]-1] = "" # remove dead from groups lists whiteGroups[:] = [ group for group in whiteGroups if len(get_liberties(group)) != 0 ] blackGroups[:] = [ group for group in blackGroups if len(get_liberties(group)) != 0 ] def play_move(color, move): playerGroups = whiteGroups if color == "w" else blackGroups neighbouringGroups = get_neighbouring_groups(move, color) # no neighbouring groups make new one if len(neighbouringGroups) == 0: playerGroups.append([(move[0], move[1])]) else: # we want to merge everything into the first group and then pop the others in # reverse index order so no indecies are getting wrong neighbouringGroups.sort() neighbouringGroups[1:] = neighbouringGroups[1:][::-1] # 1 or more neighbouring groups -> extend first one playerGroups[neighbouringGroups[0]].append((move[0], move[1])) # if also more than one group -> merge with others for i, group in enumerate(neighbouringGroups[1:]): playerGroups[neighbouringGroups[0]].extend(playerGroups.pop(group)) board[move[0]-1][move[1]-1] = color remove_dead_groups("w" if color == "b" else "b") def simulate_board_up_to(lastMoveNumber): global board global whiteGroups global blackGroups # reset board and groups blackGroups = [] whiteGroups = [] board = [ [ "" for i in range(boardSize) ] for y in range(boardSize) ] moveSequence = [ j for i in itertools.zip_longest(blackMoves,whiteMoves) for j in i ] for i in range(len(blackMoves) + len(whiteMoves)): if i == lastMoveNumber: break # blacks turn if i % 2 == 0: if len(blackMoves) == 0: continue play_move("b", blackMoves[i//2]) else: if len(whiteMoves) == 0: continue play_move("w", whiteMoves[i//2]) def show_board(): print(" "*3 + "A B C D E F G H J K L M N O P Q R S T") i = 0 for y in range(boardSize): i += 1 if boardSize-i+1 < 10: print(f" {boardSize-i+1}", end="") else: print(f"{boardSize-i+1}", end="") for x in range(boardSize): if board[x][boardSize-y-1] == "": print(" .", end="") else: print(" " + board[x][boardSize-y-1], end ="") print(f" {boardSize-i+1}") print(" "*3 + "A B C D E F G H J K L M N O P Q R S T") def get_latex_at_move(fromMove): latexList = [] simulate_board_up_to(fromMove) # just dumping the baord, nothing special for y in range(len(board)): for x in range(len(board)): if board[x][y] != "": color = "white" if board[x][y] == "w" else "black" if ord("a")+x < ord("i"): firstCoordinate = chr(ord("a")+x) else: firstCoordinate = chr(ord("a")+x+1) latexList.append(f"\\stone{{{color}}}{{{firstCoordinate}}}{{{y+1}}}\n") return latexList def produce_latex(fromMove, toMove, continousCounting): # old moves latexList = ["\\begin{psgoboard}\n\t"] latexList.extend(get_latex_at_move(fromMove)) finished = False moveCount = 1 if continousCounting: moveCount = fromMove + 1 # new moves for i in range(fromMove, len(blackMoves) + len(whiteMoves)): if i == toMove: break moves = [] color = "" if i % 2 == 0: # blacks turn moves = blackMoves color = "black" else: # whites turn moves = whiteMoves color = "white" # if this player has no moves left -> continue if len(moves) == 0: continue x, y = moves[i//2] # skip the 'i' coordinate if ord("a")+x-1 < ord("i"): firstCoordinate = chr(ord("a")+x-1) else: firstCoordinate = chr(ord("a")+x) latexList.append(f"\\stone[\\marklb{{{moveCount}}}]{{{color}}}{{{firstCoordinate}}}{{{y}}}") moveCount += 1 else: # played the last move finished = True latexList.append("\n\\end{psgoboard}\n") return latexList, finished if __name__ == '__main__': blackMoves.append((4,4)) whiteMoves.append((4,3)) blackMoves.append((5,3)) whiteMoves.append((5,4)) blackMoves.append((3,3)) whiteMoves.append((3,4)) blackMoves.append((4,2)) whiteMoves.append((4,5)) blackMoves.append((10,10)) whiteMoves.append((4,3)) blackMoves.append((4,4)) whiteMoves.append((4,3)) produce_latex(7, 200) show_board()