7 from sgflib
import SGFParser
11 parser
= argparse
.ArgumentParser( formatter_class
=argparse
.RawDescriptionHelpFormatter
,
13 This script converts SGF files to GTP format so that you can feed them
14 to Pachi, insert genmove at the right places etc. Might not work on
17 When called with FILENAMES argument, it will create according output
18 files with .gtp extension instead of .sgf, unless --no-gtp option is
21 Otherwise the games are read from standard input. Note that the stdin
22 in this case is read in at once, so for very large collections, it is
23 better to run this script separately for each sgf file.
26 cat *.sgf | %s -g -n 5
29 parser
.add_argument('FILENAMES', help='List of sgf games to process.', nargs
='*', default
=[])
30 parser
.add_argument('-g', help='Automatically append genmove command for the other color.', action
='store_true')
31 parser
.add_argument('-n', help='Output at most first MOVENUM moves.', metavar
='MOVENUM', type=int, default
=10**10)
32 parser
.add_argument('--stdout-only', help='Do not create the .gtp files from FILENAMES, print everything to stdout.', action
='store_true')
33 args
= vars(parser
.parse_args())
35 class UnknownNode(Exception):
38 def get_atr(node
, atr
):
40 return node
.data
[atr
].data
[0]
44 def col2num(column
, board_size
):
45 a
, o
, z
= map(ord, ['a', column
, 'z'])
47 return a
+ board_size
- o
48 raise Exception( "Wrong column character: '%s'"%(column
,) )
50 def is_pass_move(coord
, board_size
):
51 # the pass move is represented either by [] ( = empty coord )
52 # OR by [tt] (for boards <= 19 only)
53 return len(coord
) == 0 or ( board_size
<= 19 and coord
== 'tt' )
55 def process_gametree(gametree
, fout
):
56 # cursor for tree traversal
58 # first node is the header
61 handicap
= get_atr(header
, 'HA')
62 board_size
= int(get_atr(header
, 'SZ'))
63 komi
= get_atr(header
, 'KM')
64 player_next
, player_other
= "B", "W"
66 print >>fout
, "boardsize", board_size
67 print >>fout
, "clear_board"
69 print >>fout
, "komi", komi
70 if handicap
and handicap
!= '0':
71 print >>fout
, "fixed_handicap", handicap
72 player_next
, player_other
= player_other
, player_next
74 def print_game_step(coord
):
75 if is_pass_move(coord
, board_size
):
76 print >>fout
, "play", player_next
, "pass"
79 # The reason for this incredibly weird thing is that
80 # the GTP protocol excludes `i` in the coordinates
81 # (do you see any purpose in this??)
84 y
= str(col2num(y
, board_size
))
85 print >>fout
, "play", player_next
, x
+y
88 # walk the game tree forward
90 # sgf2gtp.pl ignores n = 0
91 if c
.atEnd
or (args
['n'] and movenum
>= args
['n']):
96 coord
= get_atr(c
.node
, player_next
)
98 print_game_step(coord
)
100 # MAYBE white started?
101 # or one of the players plays two time in a row
102 player_next
, player_other
= player_other
, player_next
103 coord
= get_atr(c
.node
, player_next
)
105 print_game_step(coord
)
107 # TODO handle weird sgf files better
110 player_next
, player_other
= player_other
, player_next
113 print >>fout
, "genmove", player_next
115 def process_sgf_file(fin
, fout
):
117 col
= SGFParser(sgfdata
).parse()
121 process_gametree(gametree
, fout
)
123 # Try next game tree in this file
125 print >>sys
.stderr
, "Unknown Node"
128 if __name__
== "__main__":
129 if not len(args
['FILENAMES']):
130 process_sgf_file(sys
.stdin
, sys
.stdout
)
132 for in_filename
in args
['FILENAMES']:
133 if args
['stdout_only']:
136 if re
.search('sgf$', in_filename
):
137 filename_base
= in_filename
[:-3]
139 filename_base
= in_filename
141 out_filename
= filename_base
+ 'gtp'
143 fout
= open(out_filename
, 'w')
145 fin
= open(in_filename
, 'r')
147 process_sgf_file(fin
, fout
)
150 if not args
['stdout_only']: