webgo now utilizes gnugo to evaluate moves. The game is now playable (though I dont know what happens if someone wins/finishes a game :))

This commit is contained in:
phear 2005-09-23 14:37:07 +00:00
parent 2630332479
commit cc76ec975b
12 changed files with 504 additions and 83 deletions

View file

@ -45,7 +45,6 @@ body {
height: 120px;
margin: 0;
padding: 0;
background-image: url(cryptobox-img/vault_pingu.png);
background-position: top right;
background-attachment: scroll;
background-repeat: no-repeat;
@ -247,13 +246,13 @@ input#submit:hover {
cursor: pointer;
}
/* the submit buttons have to have id="goban" for the following style, for use in goban display ------------- */
/*input#goban {
input {
padding: 0px;
border: 0px;
margin: 0px;
}
*/
/*input#goban:hover {
padding: 0px;
border: 0px;

View file

@ -1,4 +1,6 @@
import psql,login
import psql,login,helper
#helper = apache.import_module("helper")
def get_game_slot_of_game(player, gamename):
"""
@ -18,7 +20,7 @@ def main(req,form):
manage the removal of game from game slots of players and
delete game from database.
"""
helper.debug(req,form,str(form.keys())+" sessionid in form:"+form["sessionid"]+"<hr>")
helper.debug(req,form,"<br>"+str(form.keys())+" sessionid in form:"+form["sessionid"]+"<br>")
try:
gamename = form["game"]
except:

View file

@ -1,3 +1,5 @@
-------------------- installing GnuGo ----------------------
apt-get install gnugo
----------------- creating the database --------------------
#installing PostgreSQL the Debian way
apt-get install postgresql

View file

@ -23,11 +23,19 @@ init_webgo.py - re-initialize the whole game. deletes everything and
helper.py -small functions for string manipulation etc.
generate_goban_images.py
-recreate the goban images. just run from console.
gnugo.py -contains functions using gnugo in gtp mode. used for
evaluating wether or not a move is legal.
filehandling.py -contains functions for, well, file handling ;>
------------------------------------------
coding guidelines
tab == 4 whitespaces.
function names are lowercase with _ as a seperator.
function names are all lowercase with _ as a seperator.
------------------------------------------
how is the data saved internally:
for each go game a table is generated. this table has a 'sgf' field containing the current board in sgf file format (needed for gnugo move validation). It also has fields for each goban field. The 'sgf' entry is the SPOT for the current state of the board.
If the board gets changed, this means the 'sgf' file gets changed and then the changed fields in the table get
updated accordingly. This is a bit unclean, but it means I do not have to write a sgf parser ;>
------------------------------------------
known bugs:
"DatabaseError: error 'ERROR: current transaction is aborted, commands ignored until end of transaction block"

View file

@ -38,12 +38,12 @@ m6: manage users and game sessions inside database
username and password and is then given the choice of game to play. If
there is only one active game, directly present the goban.
. <--- YOU ARE HERE.
m7: implement Go rules
Do not accept player moves which violate go rules. Remove beaten stones.
Count and display the score for each player.
. <--- YOU ARE HERE.
m8: make it pretty, make it fast.
Create nicer images replacing the old ones which were just for testing
Find bottlenecks and optimize them for speed.

View file

@ -1 +1,6 @@
- hoshi Bilder fuer weisse und schwarze Steine erstellen
- remove temporarily created files ;>
- what happens if a game is finished?
- add a description field for a goban table
- add a date-of-creation-creation field and a last-changed-field to goban table
- display game list more nicely with players and last change.

85
filehandling.py Normal file
View file

@ -0,0 +1,85 @@
import os,tempfile,dircache,string,commands
def gen_temp_dir(prefix=None):
"""generate a secure temporary directory. returns name of dir."""
dirname=tempfile.mkdtemp("",prefix)
dirname+="/"
return dirname
def read_file(filename):
"""
read from the file whose name is given
@param filename String : name of file to read from
@return String: content of given file or None
"""
try:
f = open(filename,"r")
filecontent = f.read()
f.close()
except:
#TODO:if debug >=1:
print "(EE)[%s]: \"%s\" is not readable!"%(__name__, filename)
return ""
return filecontent
def is_dir_readable(path):
"""
Gets the name of a directory.
returns True if dir is readable, else False.
"""
return os.access(path,os.R_OK)
def write_file(filename,content):
"""
Write content to the given filename.
gets: filename,content.
"""
try:
f = open(filename,"w")#oeffnen und schliessen =>
f.close() #datei ist jetzt genullt
f = open(filename,"a") #anhaengend oeffnen
f.write(content)
f.close()
return ""
except:
#TODO: debug
#if self.debug >=1:
print "(EE)[%s]: \"%s\" is not writeable!"%(__name__, filename)
return filename
def basename(filename):
return os.path.basename(filename)
def make_all_dirs_absolute(prefix,dirlist):
"""
this function gets an absolute pathname and a list of pathnames
relative to the first. It returns this list, but with absolute
entries.
"""
ret=[]
for element in dirlist:
ret.append(os.path.normpath(prefix+"/"+element))
return ret
def gen_temp_dir(prefix='pk'):
'''returns the name of a secure temporary directory
with optional prefix as parameter'''
dirname=tempfile.mkdtemp("",prefix)
dirname+="/"
return dirname
def gen_temp_file(suffix="--gnugo"):
"""
returns the name of a generated temporay file.
optionally gets a suffix for the filename.
"""
return tempfile.mkstemp(suffix)[1]

247
gnugo.py Normal file
View file

@ -0,0 +1,247 @@
import string,sys,popen2
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,req,form):
"""
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
#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(req,form,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]
helper.debug(req,form,"color: %s -- turn: %s " % (color,turn))
#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
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"

View file

@ -4,8 +4,7 @@ DEBUG = 1
import sys,string
import cgi
import pickle
import psql,helper
import psql,helper,gnugo
picklefile = "goban.pickledump"
@ -25,7 +24,7 @@ def display_goban(goban,req,form):
hoshis9x9 = [(3,3),(3,7),(5,5),(7,3),(7,7)]
data += '<p><form method="post">'
data += '\n<p>\n<form method="post">\n'
data += """<input type="hidden" name="sessionid" value="%s">
<input type="hidden" name="username" value="%s">
<input type="hidden" name="game" value="%s">
@ -50,30 +49,30 @@ def display_goban(goban,req,form):
sy = str(y)
# check position:
if (x == 1) and (y == 1): # upper left
data += '<input type=image id="goban" src="img/topleftline'+stone+'.png" name="('+sx+','+sy+')">'
data += '<input type=image id="goban" src="img/topleftline'+stone+'.png" name="('+sx+','+sy+')"\n>'
elif (x == 1) and (y == size): # upper right
data += '<input type=image id="goban" src="img/toprightline'+stone+'.png" name="('+sx+','+sy+')"><br>'
data += '<input type=image id="goban" src="img/toprightline'+stone+'.png" name="('+sx+','+sy+')"\n><br\n>'
elif (x == size) and (y == size): # lower right
data += '<input type=image id="goban" src="img/bottomrightline'+stone+'.png" name="('+sx+','+sy+')"><br>'
data += '<input type=image id="goban" src="img/bottomrightline'+stone+'.png" name="('+sx+','+sy+')"\n><br>\n'
elif (x == size) and (y == 1): # lower left
data += '<input type=image id="goban" src="img/bottomleftline'+stone+'.png" name="('+sx+','+sy+')">'
data += '<input type=image id="goban" src="img/bottomleftline'+stone+'.png" name="('+sx+','+sy+')"\n>'
elif (y == 1): #left line
data += '<input type=image id="goban" src="img/leftline'+stone+'.png" name="('+sx+','+sy+')">'
data += '<input type=image id="goban" src="img/leftline'+stone+'.png" name="('+sx+','+sy+')"\n>'
elif (x == 1): # top line
data += '<input type=image id="goban" src="img/topline'+stone+'.png" name="('+sx+','+sy+')">'
data += '<input type=image id="goban" src="img/topline'+stone+'.png" name="('+sx+','+sy+')"\n>'
elif (y == size): # right line
data += '<input type=image id="goban" src="img/rightline'+stone+'.png" name="('+sx+','+sy+')"><br>'
data += '<input type=image id="goban" src="img/rightline'+stone+'.png" name="('+sx+','+sy+')"\n><br\n>'
elif (x == size): #bottom line
data += '<input type=image id="goban" src="img/bottomline'+stone+'.png" name="('+sx+','+sy+')">'
data += '<input type=image id="goban" src="img/bottomline'+stone+'.png" name="('+sx+','+sy+')"\n>'
else: # hoshi or empty inner field
defaultfield = '<input type=image id="goban" src="img/centerline'+stone+'.png" name="('+sx+','+sy+')">'
defaultfield = '<input type=image id="goban" src="img/centerline'+stone+'.png" name="('+sx+','+sy+')"\n>'
#too lazy to make special images for hoshi fields with stones:
if goban[(x,y)] == 1:
hoshifield = '<input type=image id="goban" src="img/centerline_white.png" name="('+sx+','+sy+')">'
hoshifield = '<input type=image id="goban" src="img/centerline_white.png" name="('+sx+','+sy+')"\n>'
elif goban[(x,y)] == 2:
hoshifield = '<input type=image id="goban" src="img/centerline_black.png" name="('+sx+','+sy+')">'
hoshifield = '<input type=image id="goban" src="img/centerline_black.png" name="('+sx+','+sy+')"\n>'
else: #empty hoshi
hoshifield = '<input type=image id="goban" src="img/hoshi.png" name="('+sx+','+sy+')">'
hoshifield = '<input type=image id="goban" src="img/hoshi.png" name="('+sx+','+sy+')"\n>'
if size == 19: # 9 hoshis
if (x,y) in hoshis19x19:
data += hoshifield
@ -100,7 +99,7 @@ def display_goban(goban,req,form):
def process_form(req,form,goban):
def process_form(req,form,gobandict):
"""
gets a goban dictionary.
@ -108,35 +107,66 @@ def process_form(req,form,goban):
if the goban has been clicked, return a (x,y) tuple of the position.
"""
ret = ""
#if form == empty (which means if page is displayed for the first time):
if form.keys() != []:
#cut out the name of the clicked button
for item in form.keys():
if string.find(item,").x")>0:
namestring = string.split(item,".x")[0]
position = helper.string_to_tuple(namestring)
ret = set_stone(goban, position)
if (type(ret) == type("")):
return (goban,ret) #return old goban and error string
else:
goban = ret
return (goban,"") # return new goban and empty string
coordstring = string.split(item,".x")[0]
position = helper.string_to_tuple(coordstring)
ret = set_stone(gobandict, position,req,form)
return ret
def set_stone(goban, position):
def set_stone(gobandict, position,req,form):
"""gets a goban dictionary and a (x,y)-tuple. Returns a modified goban."""
turn = goban["turn_number"]
if (goban[position] == 0): #empty field
goban[position] = (turn % 2) + 1 #even turn: white stone (1), else black stone(2)
goban["turn_number"] += 1
#now write changed values to database
psql.update_goban_field(goban["name"],position[0],position[1],(turn % 2) + 1)
psql.update_turn_number(goban["name"],goban["turn_number"])
return goban
size = gobandict["size"]
name = gobandict["name"]
turn = gobandict["turn_number"]
if (gobandict[position] == 0): #empty field
if gnugo.is_legal(gobandict,position,req,form): #gnugo says the move is ok
#let gnugo make the above move, let gnugo write move to file
new_sgf = gnugo.make_move_in_sgf(req,form,gobandict,position)
#write new sgf file into database
psql.update_goban_table_field(name,"x1","sgf",new_sgf)
#...and in current gobandict
gobandict["sgf"] = new_sgf
#now convert sgf to gobandict coordinates.
gobanlite = gnugo.sgf_to_goban_dict(gobandict)
#merge new coordinates with gobandict and update database where necessary
(new_gobandict, something_changed) = update_goban_dict_and_table(gobandict,gobanlite)
#and finally:
if something_changed:
psql.update_turn_number(name,turn+1)
helper.debug(req,form,"updated turn b/c gobandict has changed")
else:
helper.debug(req,form,"gobandict has not been changed, leaving turn_number untouched")
helper.debug(req,form,"set_stone:game name: %s, turn: %s, value at position: %s" % (name,turn,new_gobandict[position]))
return ""
else: #move not ok
return "This is not a legal move (says Gnugo)."
else: #position not empty
return "Could not make move: Field not empty."
def update_goban_dict_and_table(gobandict,gobanlite):
"""
gets a gobandict and a gobdict light (just coordinates and size).
updates the fields in gobandict and database.
returns changed gobandict and True (or False) if something has been changed (or not).
"""
tf = False
for key in gobanlite.keys():
if gobandict[key] != gobanlite[key]:
#found difference in dicts.
#update gobandict
gobandict[key] = gobanlite[key]
#update databse table. the only valid difference can be changed goban field positions.
psql.update_goban_field(gobandict["name"],key[0],key[1],gobandict[key])
tf = True
return gobandict,tf
###############################################################################
def main(gamename):

View file

@ -5,10 +5,7 @@ DEBUG = 1
def header():
"""return html header"""
data = """
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<title>WebGo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
@ -17,8 +14,8 @@ def header():
<meta http-equiv="expires" content="0" />
<link rel="stylesheet" media="screen" href="default.css" type="text/css" />
</head>
<body>
<h1> WebGo </h1>
<body>
"""
return data
@ -30,9 +27,9 @@ def debug(req,form, optstr = ""):
"""
if DEBUG:
if optstr == "":
req.write(str(form.keys()))
req.write("Debug: "+str(form.keys())+"<br>\n")
else:
req.write(optstr)
req.write("Debug: "+optstr+"<br>\n")
def footer():
"""return html footer"""
@ -88,3 +85,25 @@ def string_to_tuple(str):
except: #empty string
returnlist.append(-1)
return tuple(returnlist)
def dict_coords_to_gnugo_coords(coords,size):
"""
gets a (x,y) coordinate tuple and boardsize.
returns a string in gnugo syntax. examples:
gets (1,1), returns "A7".
gets (6,2), returns "B2".
"""
letterlist = [" "]
letterlist.extend(list(string.letters[26:]))
letterlist.remove("I")
letter = letterlist[coords[1]]
digit = size+1-coords[0]
return letter+str(digit)
def test():
print dict_coords_to_gnugo_coords((6,5),7)
if __name__ == "__main__":
test()

View file

@ -9,15 +9,13 @@ def is_my_turn(req,form,gobandict):
check wether or not the current this is the players turn.
return true or false.
"""
#INFO: player1 is black,player2 is white. black starts the game.
me = form["username"]
player1 = gobandict["player1"]
player2 = gobandict["player2"]
#get turn_number.
turn_number = gobandict["turn_number"]
#if turn_number modulo 2 == 0: are we player two?
#if player 2 can play: are we player two?
# yes:return True, else return False
if turn_number % 2 == 0:
if me == player2:
@ -41,42 +39,46 @@ def main(req,form):
"""
display selected goban and manage user input.
"""
helper.debug(req,form,str(form.keys())+"<hr>")
try:
gamename = form["game"]
except:
gamename = ""
if gamename != "":
data = ""
req.write(helper.header())
#helper.debug(req,form,str(form.keys()))
#read goban table from database
tmplist = psql.read_table(gamename)
#make a dictionary out of the list
gobandict = psql.fetchall_list_to_goban_dict(tmplist)
#check if user has already clicked onto a field:
foundx = False
click_on_field = False
for item in form.keys():
if string.find(item,").x") > 0:
foundx = True
if foundx:
click_on_field = True
if click_on_field:
#if yes: is this the user's turn? then process form.
if is_my_turn(req,form,gobandict):
(gobandict,retstring) = goban.process_form(req,form,gobandict)
#do stuff
data = helper.header()
data += "Turn number: "+str(gobandict["turn_number"])+". "
helper.debug(req,form,"its my turn , i am going to process the form: --")
retstring = goban.process_form(req,form,gobandict)
if retstring != "":
helper.debug(req,form,"playgame.main says: "+str(retstring))
else:
#reload gobandict, it has been changed.
gobandict = psql.fetchall_list_to_goban_dict(psql.read_table(gamename))
else:
helper.debug(req,form,"its not my turn.")
data += """<br>Turn number: %s. %s plays.\n
""" % (str(gobandict["turn_number"]), ["White","Black"][int(gobandict["turn_number"] % 2)])
#check whether its our turn
#if yes: print 'your move' and display goban and process move
#if not: print '...s move' and display goban.
if is_my_turn(req,form,gobandict):
data += ("Its your turn.<br>")
data += "<br>Its your turn.<br>\n"
else:
data+= ("This is not your turn. You have to wait for the move of the other player.<br>")
data += "<br>This is not your turn. You have to wait for the move of the other player.<br>\n"
#print goban
data += goban.display_goban(gobandict,req,form)
data += login.navigation_bar(req,form)

28
psql.py
View file

@ -1,4 +1,4 @@
import helper
import helper,gnugo
import pgdb,sys
DEBUG = 1
@ -50,6 +50,7 @@ def create_goban_table(player1,player2,size):
name
player1
player2
sgf
and the meaning of these fields:
(xn,yn) is a field of the goban,
@ -58,8 +59,7 @@ def create_goban_table(player1,player2,size):
(name,x1) is the name of this goban.
(player1,x1) is the name of one player.
(player2,x1) is the name of the other player.
(sgf,x1) contains a sgf file with the current board.
"""
tablename = helper.generate_game_name()
data="line text"
@ -101,6 +101,12 @@ def create_goban_table(player1,player2,size):
tmplist.append("player2")
tmplist.append(player2)
insert_into_table(tablename,str(tuple(tmplist)))
#empty sgf file as string
tmplist=[]
tmplist.append("sgf")
sgf = gnugo.create_sgf_file(size)
tmplist.append(sgf)
insert_into_table(tablename,str(tuple(tmplist)))
return tablename
@ -324,6 +330,9 @@ def set_game_slot(username,gameslot,gamename):
executestring ="UPDATE users SET %s = '%s' WHERE username = '%s'" %(gameslot,gamename, username)
sql_one_liner(executestring)
################# access of goban tables ####################################################################
def get_players_for_game(tablename):
@ -361,6 +370,19 @@ def update_turn_number(table,new_number):
"""
update_goban_table_field(table,"x1","turn_number",new_number)
def get_sgf(table):
"""
gets a table name,
returns content of "sgf" field.
"""
cursor=db.cursor()
data="select x1 from %s where line='sgf';" % (table)
cursor.execute(data)
# Commit the changes
db.commit()
sgf = cursor.fetchone()[0]
cursor.close()
return sgf
def fetchall_list_to_goban_dict(list):