import string,sys,popen2,re import helper,filehandling gnugocommand = "/usr/games/gnugo --mode gtp" showboard = """ = A B C D E F G 7 . . . . . . . 7 6 . . . . . . . 6 5 . . + . + . . 5 4 . . X X . . . 4 3 . . O . + . . 3 2 . . . . . . . 2 WHITE (O) has captured 0 stones 1 . . . . . . . 1 BLACK (X) has captured 0 stones A B C D E F G """ def is_int( str ): """ Is the given string an integer? """ ok = 1 try: num = int(str) except ValueError: ok = 0 return ok def showboard_to_goban_dict(showboard): """ gets a string containing the result of the 'showboard' command from gnugo --mode gtp. returns a goban dictionary . """ gobandict= {} showboardlist = string.split(showboard,'\n') while '' in showboardlist: showboardlist.remove('') #remove '=' if string.find(showboardlist[0],"=")>=0: showboardlist.remove(showboardlist[0]) #get boardsize tmplist = string.split(showboardlist[0]," ") while '' in tmplist: tmplist.remove('') boardsize = len(tmplist) #remove first A B C D ... showboardlist.remove(showboardlist[0]) #remove last A B C D ... showboardlist.remove(showboardlist[-1]) for i in range(0,boardsize): #make string to list linelist = string.split(showboardlist[i],' ') #clean list from '' entries while '' in linelist: linelist.remove('') # remove numbers for p in range(0,boardsize+1): if is_int(linelist[p]): linelist.remove(linelist[p]) #print linelist,'\n' #now fill dictionary: for j in range(0,boardsize): if (linelist[j] == ".") or (linelist[j] == "+"): gobandict[(i+1,j+1)] = 0 #empty if linelist[j] == "O": gobandict[(i+1,j+1)] = 1 #white stone if linelist[j] == "X": gobandict[(i+1,j+1)] = 2 #black stone #check for info of caputered stones: if len(linelist) > boardsize: if 'WHITE' in linelist: whitecapture = "white has captured %s stones." % linelist[-2] #print whitecapture elif 'BLACK' in linelist: blackcapture = "black has captured %s stones." % linelist[-2] gobandict["size"] = boardsize return gobandict def sgf_to_goban_dict(gobandict, filename=""): """ gets a goban dictionary and optionally a temporary filename. saves string to file, loads in gnugo, does showboard, convert showboard to gobandict. return gobandict 'lite' (just coordinates and size) """ sgf = gobandict["sgf"] #generate tmpfile if filename == "": filename = filehandling.gen_temp_file() #write sgf data to file filehandling.write_file(filename,sgf) #open connection to gnugo: conn = GTP_connection(gnugocommand) #load sgf file in gnugo result = conn.exec_cmd("loadsgf "+filename) #make move (looks like 'play black F2' result = conn.exec_cmd("showboard") #convert to goban dict ret = showboard_to_goban_dict(result) result = conn.exec_cmd("quit") return ret ### GTP_connection is based on twogtp.py packaged with gnugo. class GTP_connection: """ gets a program call string, opens an interactive session with program called with 'program'. GTP_connection.exec_cmd(command) returns result of command. # # Class members: # outfile File to write to # infile File to read from """ def __init__(self, command): try: infile, outfile = popen2.popen2(command) except: print "popen2 failed" self.infile = infile self.outfile = outfile def exec_cmd(self, cmd): self.outfile.write(cmd + "\n\n") self.outfile.flush() result = "" line = self.infile.readline() while line != "\n": result = result + line line = self.infile.readline() # Remove trailing newline from the result if result[-1] == "\n": result = result[:-1] if len(result) == 0: return "ERROR: len = 0" if (result[0] == "?"): return "ERROR: GTP Command failed: " + result[2:] if (result[0] == "="): return result[2:] return "ERROR: Unrecognized answer: " + result def is_legal(gobandict,coords): """ gets a goban dict and a (x,y) tuple. tests wether proposed move is legal. returns True or False. """ """size = gobandict["size"] turn = gobandict["turn_number"] #who's turn is it? color = ["white","black"][turn % 2] #even turn: white plays, else black plays """ gamename = gobandict["name"] color = gobandict["play"] size = gobandict["size"] #convert given coordinates gnucoords = " " + helper.dict_coords_to_gnugo_coords(coords,size) #open connection to gnugo: conn = GTP_connection(gnugocommand) result = conn.exec_cmd("is_legal "+ color +gnucoords) if result == "1": return True else: return False result = conn.exec_cmd("quit") def create_sgf_file(size, filename=""): """ gets: board size, optionally a temporary filename to use. returns the content of an empty sgf file. """ conn = GTP_connection(gnugocommand) result = conn.exec_cmd("boardsize "+str(size)) if filename == "": filename = filehandling.gen_temp_file() result = conn.exec_cmd("printsgf "+filename) ret = filehandling.read_file(filename) result = conn.exec_cmd("quit") return ret def make_move_in_sgf(gobandict,coords,filename = ""): """ gets: goban dict, (x,y) tuple for move, optionally a filename for tempfile. writes the string to a file, opens gnugo, makes the move, writes new sgf to temporary file, reads content of temporary file. returns: sgf string of new file. """ size = gobandict["size"] turn = gobandict["turn_number"] sgf = gobandict["sgf"] #convert given coordinates gnucoords = " " + helper.dict_coords_to_gnugo_coords(coords,size) # get current player #even turn: white plays, else its blacks turn """ color = ["white","black"][turn % 2] """ color = gobandict["play"] #generate tmpfile if filename == "": filename = filehandling.gen_temp_file() #write sgf data to file filehandling.write_file(filename,sgf) #open connection to gnugo: conn = GTP_connection(gnugocommand) #load sgf file in gnugo result = conn.exec_cmd("loadsgf "+filename) #make move (looks like 'play black F2' result = conn.exec_cmd("play "+color+gnucoords) #save result to file result = conn.exec_cmd("printsgf "+filename) #read out new file sgf = filehandling.read_file(filename) result = conn.exec_cmd("quit") return sgf def parse_static_gnugo_sgf(s): """ gets a string containing the data saved by the gnugo "printsgf" order. """ #dicitonary to return ret = {} #removing newlines vom given string s = s.replace("\r\n","") #windoze s = s.replace("\n","") #unix #getting the board size # looks like SZ[19] # the pattern finds a number ([0-9]) with length (1-2) between "SZ[" and "]" boardsize = re.search("SZ\[([0-9]{1,2})\]",s).groups()[0] boardsize = int(boardsize) ret["size"] = boardsize #now fill ret with default values (== 0): for i in range (1,boardsize+1): for k in range (1,boardsize+1): ret[(i,k)] = 0 #some regexp patterns: #(?: ...) groups items stones = "%s((?:\[[a-z][a-z]\])*)" #dont forget to set %s! whitestones = stones % "AW" blackstones = stones % "AB" #getting white stones #looks like AW[bb][cb][cc][cd][de][df] try: stonestring = re.search(whitestones,s).groups()[0] except: #we could not find anything stonestring = "" if stonestring != "": ret = set_stones(stonestring,1,ret) #getting black stones try: stonestring = re.search(blackstones,s).groups()[0] except: #we could not find anything stonestring = "" if stonestring != "": ret = set_stones(stonestring,2,ret) #who's turn is it? if string.find(s,"PL[B]")>0: ret["play"] = "black" else: ret["play"] = "white" return ret def set_stones(stonestring,value,ret): """ gets: - string from sgf file with stone postitions in brackets: '[ab][ac]...' - value to set - dictionary to transform does: returns: - dicionary """ #create a list of letters letters = [" "] letters.extend(list(string.letters)[0:26]) #regexp stonestolist = "\[([a-z][a-z])\]" rawlist = re.findall(stonestolist,stonestring) for item in rawlist: #fill in specific values ret[(letters.index(item[1]),letters.index(item[0]))] = value return ret if __name__ == '__main__': #showboard_to_goban_dict(showboard) import popen2 conn = GTP_connection("gnugo --mode gtp") result = conn.exec_cmd("boardsize 7") result = conn.exec_cmd("genmove black") result = conn.exec_cmd("genmove white") result = conn.exec_cmd("printsgf test.sgf") result = conn.exec_cmd("quit") conn = GTP_connection("gnugo --mode gtp") result = conn.exec_cmd("loadsgf test.sgf") result = conn.exec_cmd("showboard") print result,"\n----\n" print showboard_to_goban_dict(result) print create_sgf_file(7) #loadsgf #printsgf #is_legal black F2 #dict_coords_to_gnugo_coords(coords) translates (6,6) to "F2" #sample output s = """(; GM[1] FF[4] SZ[19] GN[GNU Go 3.7.4 load and print] DT[2005-10-09] KM[5.5] RU[Japanese] AP[GNU Go:3.7.4] AW[bb][cb][cc][cd][de][df] [ag][cg][ah][ch][dh][ai][bi][ci] AB[ba][ab][ac][bc][bd][be][ce][af][cf][bg][bh] PL[B] )""" print parse_static_gnugo_sgf(s)