diff --git a/default.css b/default.css
index b2a3cfc..30111d7 100644
--- a/default.css
+++ b/default.css
@@ -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;
diff --git a/deletegame.py b/deletegame.py
index c991e51..e1402c5 100644
--- a/deletegame.py
+++ b/deletegame.py
@@ -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"]+"
")
+ helper.debug(req,form,"
"+str(form.keys())+" sessionid in form:"+form["sessionid"]+"
")
try:
gamename = form["game"]
except:
diff --git a/documentation/development/INSTALL b/documentation/development/INSTALL
index 12543d2..5308a4e 100644
--- a/documentation/development/INSTALL
+++ b/documentation/development/INSTALL
@@ -1,3 +1,5 @@
+-------------------- installing GnuGo ----------------------
+apt-get install gnugo
----------------- creating the database --------------------
#installing PostgreSQL the Debian way
apt-get install postgresql
diff --git a/documentation/development/README_DEVEL b/documentation/development/README_DEVEL
index 965b644..6b80047 100644
--- a/documentation/development/README_DEVEL
+++ b/documentation/development/README_DEVEL
@@ -12,22 +12,30 @@ imgsource/ with the desired ones. then run generate_goban_images.py and
the new images get written to img/.
------------------------------------------
overview of the files:
-main.py - the main script. Essentially a wrapper that prints the
+main.py -the main script. Essentially a wrapper that prints the
traceback if something went wrong.
-login.py - this file contains functions for login and game
+login.py -this file contains functions for login and game
selection/modification.
-goban.py - code for displaying a goban as a html page.
-psql.py - all functions directly accessing the database.
-init_webgo.py - re-initialize the whole game. deletes everything and
+goban.py -code for displaying a goban as a html page.
+psql.py -all functions directly accessing the database.
+init_webgo.py -re-initialize the whole game. deletes everything and
sets some defaults.
-helper.py - small functions for string manipulation etc.
+helper.py -small functions for string manipulation etc.
generate_goban_images.py
- - recreate the goban images. just run from console.
+ -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"
diff --git a/documentation/development/ROADMAP b/documentation/development/ROADMAP
index ae4848b..88004e4 100644
--- a/documentation/development/ROADMAP
+++ b/documentation/development/ROADMAP
@@ -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.
diff --git a/documentation/development/TODO b/documentation/development/TODO
index 1e74532..d4944a3 100644
--- a/documentation/development/TODO
+++ b/documentation/development/TODO
@@ -1 +1,6 @@
-- hoshi Bilder fuer weisse und schwarze Steine erstellen
\ No newline at end of file
+- 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.
\ No newline at end of file
diff --git a/filehandling.py b/filehandling.py
new file mode 100644
index 0000000..a2a1350
--- /dev/null
+++ b/filehandling.py
@@ -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]
\ No newline at end of file
diff --git a/gnugo.py b/gnugo.py
new file mode 100644
index 0000000..ae81730
--- /dev/null
+++ b/gnugo.py
@@ -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"
+
diff --git a/goban.py b/goban.py
index 65ccb8b..dcb9506 100755
--- a/goban.py
+++ b/goban.py
@@ -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 += '