def test_get_setup_and_moves(tc): g1 = sgf.Sgf_game.from_string(SAMPLE_SGF) board1, plays1 = sgf_moves.get_setup_and_moves(g1) tc.assertBoardEqual(board1, DIAGRAM1) tc.assertEqual(plays1, [('b', (2, 3)), ('w', (3, 4)), ('b', None), ('w', None)]) g2 = sgf.Sgf_game(size=9) root = g2.get_root() root.set("AB", [(1, 2), (3, 4)]) node = g2.extend_main_sequence() node.set("B", (5, 6)) node = g2.extend_main_sequence() node.set("W", (5, 7)) board2, plays2 = sgf_moves.get_setup_and_moves(g2) tc.assertBoardEqual(board2, DIAGRAM2) tc.assertEqual(plays2, [('b', (5, 6)), ('w', (5, 7))]) g3 = sgf.Sgf_game.from_string("(;AB[ab][ba]AW[aa])") tc.assertRaisesRegex(ValueError, "setup position not legal", sgf_moves.get_setup_and_moves, g3) g4 = sgf.Sgf_game.from_string("(;SZ[9];B[ab];AW[bc])") tc.assertRaisesRegex(ValueError, "setup properties after the root node", sgf_moves.get_setup_and_moves, g4) g5 = sgf.Sgf_game.from_string("(;SZ[26];B[ab];W[bc])") board5, plays5 = sgf_moves.get_setup_and_moves(g5) tc.assertEqual(plays5, [('b', (24, 0)), ('w', (23, 1))])
def find_patterns_in_game_str(self, sgf_src, game_id, fail_if_no_date=False): """ Similar to find_patterns_in_game but takes the game record directly as a string. sgf_src: SGF as a sting """ sgf_game = None try: sgf_game = sgf.Sgf_game.from_bytes(sgf_src) root = sgf_game.get_root() if root.has_property('SZ'): size = root.get_raw('SZ').decode(root.get_encoding()) if size != '19': logging.warning("Skipping game with size: %s", size) return ([], None) except Exception as e: logging.warning("Warning: cannot open game", sgf_src, ", reason:", e) return ([], None) try: board, plays = sgf_moves.get_setup_and_moves(sgf_game) except Exception as e: logging.warning("Warning: cannot setup game", sgf_game, ", reason:", e) return ([], None) patterns_found = [] num_moves = 0 num_found = 0 date = None try: date = get_game_date_from_sgf(sgf_game, game_id) except (Exception, e): logging.warning("Could not find date in game id: %s sgf: %s. Reason: %s", game_id, sgf_game, e) pass if fail_if_no_date and date is None: return ([], None) for colour, move in plays: if self.max_moves_ is not None and num_moves > self.max_moves_: break if move is None: continue row, col = move num_moves += 1 try: board.play(row, col, colour) for pattern in self.extract_board_patterns_after_move_(game_id, num_moves, board, row, col): # TODO also add info about who played last move to create this pattern, B or W (colour) patterns_found.append(pattern) except ValueError as e: logging.warning("Error processing game", game_id, "sgf:", sgf_src, "at move:", num_moves, ":", e) break return (patterns_found, date)
def show_sgf_file(pathname, move_number): f = open(pathname, "rb") sgf_src = f.read() f.close() try: sgf_game = sgf.Sgf_game.from_bytes(sgf_src) except ValueError: raise Exception("bad sgf file") try: board, plays = sgf_moves.get_setup_and_moves(sgf_game) except ValueError as e: raise Exception(str(e)) if move_number is not None: move_number = max(0, move_number-1) plays = plays[:move_number] for colour, move in plays: if move is None: continue row, col = move try: board.play(row, col, colour) except ValueError: raise Exception("illegal move in sgf file") print(ascii_boards.render_board(board)) print()
def doLoadSGFfile(self, pathname, move_number=None): stones = [] # print('pathname ',pathname) f = open(pathname, "rb") sgf_src = f.read() f.close() # print('sgfsrc', sgf_src) try: sgf_game = sgf.Sgf_game.from_bytes(sgf_src) text = [] if sgf_game.get_gamename() is None: text.append( sgf_game.get_player_name('b') + ' VS ' + sgf_game.get_player_name('w') + '\n') else: text.append((str(sgf_game.get_gamename())) + '\n') text.append('Winner: ' + str(sgf_game.get_winner()) + '\n') text.append('size: ' + str(sgf_game.get_size()) + '\n') text.append('komi: ' + str(sgf_game.get_komi()) + '\n') text.append('handicap: ' + str(sgf_game.get_handicap()) + '\n') text.append('TotalTime:' + ( str(sgf_game.get_times() / 3600) if sgf_game.get_times() is not None else '0') + '\n') text.append('overtime: ' + str(sgf_game.get_overtime()) + '\n') text.append(str(sgf_game.get_common()) + '\n') self.infopanel.mTextEditor.setText(''.join(text)) self.infopanel.black.Name = sgf_game.get_player_name('b') self.infopanel.white.Name = sgf_game.get_player_name('w') except ValueError: raise Exception("bad sgf file") try: board, plays = sgf_moves.get_setup_and_moves(sgf_game) except ValueError as e: raise Exception(str(e)) if move_number is not None: move_number = max(0, move_number - 1) plays = plays[:move_number] for colour, move in plays: if move is None: continue # print('move ', move) if colour is 'w': stones.append([move[0], move[1], 'white']) elif colour is 'b': stones.append([move[0], move[1], 'black']) else: print('color error') # row, col = move # print("stones:",row,' ',col, ' ', colour) return stones # print('board ', board) # print(ascii_boards.render_board(board)) pass
def extract_corners(game_path): ''' returns a Counter("sequence", count) of all sequences/subsequences in all corners of a given game_path ''' with open(game_path) as sgf_file: game_data = sgf_file.read().encode('utf-8') try: g = sgf.Sgf_game.from_bytes(game_data) _, moves = sgf_moves.get_setup_and_moves(g) except BaseException: print("bad file: ", game_path) return Counter() corner_trackers = [[], [], [], []] stop = [] for m in moves: corners, m = move_to_corner(m) if not corners: continue for c in corners: if c in stop: continue corner_trackers[c].append(m) if len(corner_trackers[c]) > MAX_JOSEKI_LENGTH: stop.append(c) if len(stop) == 4: break # we now have the sequences of the four corners of the board extracted, but # not 'canonical', i.e., the reflections across y=x would be distinct. # so, canonicalize them sequence_counts = Counter() for c in corner_trackers: seq = "" canonical = None for idx, (color, m) in enumerate(c): y, x = m if y < x and canonical is None: canonical = True elif y > x and canonical is None: x, y = y, x canonical = False elif canonical is False: x, y = y, x seq += sgf_format((color, (18 - y, x))) if idx > MIN_JOSEKI_LENGTH: sequence_counts[seq] += 1 return sequence_counts
def sgf2list(sgf_file): """From the input sgf file named -sgf_file- sgf2list returns the moves as a Python list of strings, each containing a position in the format ["Color", "vertex"], e.g. ['["W","P5"]','["B","P6"]'] """ SGFstring = '' with open(sgf_file, "r") as myfile: SGFstring = myfile.read().replace('\n', '') SGFobject = sgf.Sgf_game.from_string(SGFstring) moves = sgf_moves.get_setup_and_moves(SGFobject)[1] listmoves = [] for move in moves: Color = move[0].upper() vertex = sgfmill.common.format_vertex(move[1]) listmoves.append('["' + Color + '","' + vertex + '"]') return listmoves
def test_get_setup_and_moves_board_provided(tc): b = boards.Board(9) g1 = sgf.Sgf_game.from_string(SAMPLE_SGF) board1, plays1 = sgf_moves.get_setup_and_moves(g1, b) tc.assertIs(board1, b) tc.assertBoardEqual(board1, DIAGRAM1) tc.assertEqual(plays1, [('b', (2, 3)), ('w', (3, 4)), ('b', None), ('w', None)]) tc.assertRaisesRegex(ValueError, "board not empty", sgf_moves.get_setup_and_moves, g1, b) b2 = boards.Board(19) tc.assertRaisesRegex(ValueError, "wrong board size, must be 9$", sgf_moves.get_setup_and_moves, g1, b2)
def get_pro_tables(): out = [] all_filenames = get_file_names() count_prob = 0 count_ok = 0 for filename in all_filenames: f = open(filename, "rb") sgf_src = f.read() f.close() try: sgf_game = sgf.Sgf_game.from_bytes(sgf_src) board, plays = sgf_moves.get_setup_and_moves(sgf_game) except Exception: continue if len(plays) < 5: continue end_idx = random.randint(5, len(plays)) new_game = {'list_of_moves': [], 'black_stones': [], 'white_stones': []} skip = False turn = 0 for play in plays[:end_idx]: if play[1] == None: skip = True continue else: new_game['list_of_moves'].append(rev_coord_to_name(play[1])) if turn == 0: new_game['black_stones'].append(rev_coord_to_name(play[1])) turn = 1 elif turn == 1: new_game['white_stones'].append(rev_coord_to_name(play[1])) turn = 0 if not skip: assert len(new_game['black_stones']) + len(new_game['white_stones']) == len(new_game['list_of_moves']) new_game['depth'] = len(new_game['list_of_moves']) out.append(new_game) return out
def read_sgf(filename): """Parse sgf.""" with open(filename, "rb") as f: sgf_src = f.read() try: sgf_game = sgf.Sgf_game.from_bytes(sgf_src) except ValueError: raise Exception("bad sgf file") try: sgf_board, plays = sgf_moves.get_setup_and_moves(sgf_game) except ValueError as e: raise Exception(str(e)) return sgf_board, plays, sgf_game
def extract_from_game(game_path): """ In addition to the corner information returned, we also add the winner, returning a tuple of ((sequence_counts, nextmove_counts), winner) where `winner` == 1 for B win, 0 otherwise. """ with open(game_path) as sgf_file: game_data = sgf_file.read().encode('utf-8') try: g = sgf.Sgf_game.from_bytes(game_data) _, moves = sgf_moves.get_setup_and_moves(g) except BaseException: print("bad file: ", game_path) return Counter(), {} return (extract_corners(moves), 1 if g.get_winner().lower() == 'b' else 0)
def open_sgf(filename): f = open(filename, "rb") sgf_src = f.read() f.close() #print("Just read this sgf:", sgf_src) sgf_game = sgf.Sgf_game.from_bytes(sgf_src) board, plays = sgf_moves.get_setup_and_moves(sgf_game) sz = sgf_game.get_size() # makes new game new_game = Game(sz) my_array = new_game.board print(plays) for color, move in plays: if move is None: continue row, col = move row = (new_game.board_sz - 1) - row if color == 'b': color = 'black' if color == 'w': color = 'white' try: my_array[row, col] = moves.GridSquare(row, col, color, sz) #board.play(row, col, colour) except ValueError: raise Exception("illegal move in sgf file") game_nodes = sgf_game.get_main_sequence() for node in game_nodes: if node.has_property("LB"): node_vals = node.get("LB")[0] row = (new_game.board_sz - 1) - node_vals[0][0] col = node_vals[0][1] sym = node_vals[1] # print("Printing label symbols in open_sgf") # print(sym, row, col) my_array[row, col] = moves.GridSquare(row, col, sym, sz) return new_game
def test_get_setup_and_moves_move_in_root(tc): # A move in the root node is allowed (though deprecated) if there are no # setup stones. g1 = sgf.Sgf_game(size=9) root = g1.get_root() root.set("B", (1, 2)) node = g1.extend_main_sequence() node.set("W", (3, 4)) board1, plays1 = sgf_moves.get_setup_and_moves(g1) tc.assertTrue(board1.is_empty()) tc.assertEqual(plays1, [('b', (1, 2)), ('w', (3, 4))]) g2 = sgf.Sgf_game(size=9) root = g2.get_root() root.set("B", (1, 2)) root.set("AW", [(3, 3)]) node = g2.extend_main_sequence() node.set("W", (3, 4)) tc.assertRaisesRegex(ValueError, "mixed setup and moves in root node", sgf_moves.get_setup_and_moves, g2)
def sgf_to_mat(pathname, move_number=None): """Converts game position from sgf file to in-memory matrix representation. Only follows left branch of game tree. Move number one is the empty board, default is the last node. Returns numpy matrix with '1's for black stones and '2' for white ones. """ with open(pathname, "rb") as f: sgf_src = f.read() try: sgf_game = sgf.Sgf_game.from_bytes(sgf_src) except ValueError: raise Exception("bad sgf file") try: board, plays = sgf_moves.get_setup_and_moves(sgf_game) except ValueError as e: raise Exception(str(e)) if move_number is not None: move_number = max(0, move_number-1) plays = plays[:move_number] for colour, move in plays: if move is None: continue row, col = move try: board.play(row, col, colour) except ValueError: raise Exception("illegal move in sgf file") mat = np.full((19, 19), 0) for colour, pos in board.list_occupied_points(): if (colour == 'b'): mat[pos] = 1 if (colour == 'w'): mat[pos] = 2 # internal representation starts coordinates in upper left: mat = np.flipud(mat) return mat
def __init__(self, pathname): self.pathname = pathname num_of_threads = 100 with open(self.pathname, "rb") as f: sgf_src = f.read() try: self.sgf_game = sgf.Sgf_game.from_bytes(sgf_src) except: raise Exception("SGF file format error") try: _, self.play_seq = sgf_moves.get_setup_and_moves(self.sgf_game) except: raise Exception("") self.initial_board = [] for i in range(19): self.initial_board.append([0, i]) self.initial_board.append([18, i]) self.initial_board.append([i, 0]) self.initial_board.append([i, 18])
def find_patterns_in_game_str(self, sgf_src, game_id, fail_if_no_date=False): """ Similar to find_patterns_in_game but takes the game record directly as a string. sgf_src: SGF as a sting """ sgf_game = None try: sgf_game = sgf.Sgf_game.from_bytes(sgf_src) root = sgf_game.get_root() if root.has_property('SZ'): size = root.get_raw('SZ').decode(root.get_encoding()) if size != '19': logging.warning("Skipping game with size: %s", size) return ([], None) except Exception as e: logging.warning("Warning: cannot open game", sgf_src, ", reason:", e) return ([], None) try: board, plays = sgf_moves.get_setup_and_moves(sgf_game) except Exception as e: logging.warning("Warning: cannot setup game", sgf_game, ", reason:", e) return ([], None) patterns_found = [] num_moves = 0 num_found = 0 date = None try: date = get_game_date_from_sgf(sgf_game, game_id) except (Exception, e): logging.warning( "Could not find date in game id: %s sgf: %s. Reason: %s", game_id, sgf_game, e) pass if fail_if_no_date and date is None: return ([], None) for colour, move in plays: if self.max_moves_ is not None and num_moves > self.max_moves_: break if move is None: continue row, col = move num_moves += 1 try: board.play(row, col, colour) for pattern in self.extract_board_patterns_after_move_( game_id, num_moves, board, row, col): # TODO also add info about who played last move to create this pattern, B or W (colour) patterns_found.append(pattern) except ValueError as e: logging.warning("Error processing game", game_id, "sgf:", sgf_src, "at move:", num_moves, ":", e) break return (patterns_found, date)
def extract_board_table(sgf_file, move_number): sgf_src = sgf_file.read() sgf_file.close() try: sgf_game = sgf.Sgf_game.from_bytes(sgf_src) except ValueError: raise Exception("bad sgf file") board_size = sgf_game.get_size() # extract annotations/markings eg. A, B, square try: node = sgf_game.get_main_sequence()[move_number - 1] except ValueError as e: raise Exception(str(e)) try: board, plays = sgf_moves.get_setup_and_moves(sgf_game) except ValueError as e: raise Exception(str(e)) if move_number is not None: move_number = max(0, move_number - 1) plays = plays[:move_number] for colour, move in plays: if move is None: continue row, col = move try: board.play(row, col, colour) except ValueError: raise Exception("illegal move in sgf file") board_list = [[col + 1, row + 1, board.get(row, col)] for col in range(board_size) for row in range(board_size)] board_table = pd.DataFrame(board_list, columns=['x', 'y', 'stone']) # properties_with_a_value = ['LB'] p = 'LB' text_list = list() if p in node.properties(): text_list = [[i[0][1] + 1, i[0][0] + 1, 'text', i[1]] for i in node.get(p)] text_table = pd.DataFrame(text_list, columns=['x', 'y', 'annotation_type', 'value']) properties_without_a_value = ['SQ', 'MA'] symbol_list = list() for p in properties_without_a_value: if p in node.properties(): for i in node.get(p): row = i[0] col = i[1] symbol_list = symbol_list + [[col + 1, row + 1, 'symbol', p]] symbol_table = pd.DataFrame(symbol_list, columns=['x', 'y', 'annotation_type', 'value']) symbol_table # combine stones and annotations into a single table annotation_table = pd.concat([text_table, symbol_table]) board_table = board_table.merge(annotation_table, on=['x', 'y'], how='outer') # set the color of the annotations board_table['annotation_color'] = np.where( (board_table['stone'].isnull()) | (board_table['stone'] == 'w'), 'b', 'w') return board_table, board_size