commit a5eb556ebb859ee07caf12095327810b28057548 Author: phear Date: Tue Sep 6 17:52:46 2005 +0000 init diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..86e11db --- /dev/null +++ b/INSTALL @@ -0,0 +1,18 @@ +----------------- creating the database -------------------- +#installing PostgreSQL the Debian way +apt-get install postgresql +su postgres +#in template1 +psql template1 +#at the prompt write: +CREATE DATABASE webgo ; +#now create user who is allowed to administrate this database +#user and password should be changed;> +CREATE USER name PASSWORD 'password'; +#now make a super user out of this user: +#TODO:tighter rights for user, this should be unsecure +ALTER USER name CREATEUSER; +#now change the user and password variables in the script + +webgouser +webgopassword \ No newline at end of file diff --git a/README b/README new file mode 100644 index 0000000..0f9b905 --- /dev/null +++ b/README @@ -0,0 +1,39 @@ +------------------------------------------- +WebGo Development: + +Steps to do to get a runnable version: +1. create /etc/apache2/conf.d/webgo.conf with content: + +Alias /webgo /home/mtsrc/daten/projekte/webgo/stderr.py + + + Options ExecCGI + AddHandler cgi-script .py + AllowOverride None + order allow,deny + allow from all + + +You should replace the directory settings for optimal results ;> + +2. set ownership of webgo directory to ownership of the web server + +this should be all. Errors get written to ./cgi_errors.log. + +------------------------------------------- + +How to make the goban clickable: + data += '
' + data += '' + #insert rest of goban here + data += '
' + print data + +How to extract the data from this POST: + import cgi + #get instance of fieldstorage + form = cgi.FieldStorage() + #if form == empty (which means if page is displayed for the first time): + if form.keys() != []: + #cut out the name of the clicked button + print string.split(form.keys()[0],".x")[0] \ No newline at end of file diff --git a/ROADMAP b/ROADMAP new file mode 100644 index 0000000..ecb51a6 --- /dev/null +++ b/ROADMAP @@ -0,0 +1,55 @@ + +M0: debug messages as html + Create a script that prints the python stderr of thea main script as html, + so debugging the cgi becomes more easy. + +M1: user interaction thorugh images + Completed, when a user can click on an image, and the image gets replaced + as a result. + +m2: autogenerate images + There are partly transparent images of black and white stones, center, + border and hoshi squares, all available in png format. The Milestone is + considered complete when the program can automatically generate combined + images of all squares with all stones. The stones have to be on top ;> + +m3: display working 9x9 goban + Completed, when the cgi script has an internal representation of a goban + that can handle stones, and this goban is displayed on a html page. + +m4: handle player turns + The program knows wether it is the turn of black or white, and prints the + current turn color on the html page displaying the goban. If player white + clicks on an empty square, a white stone will be layed onto that square. + Same for Player black. + +m5: goban inside database + Manage the goban inside a postgresql database, so all user input changes a + table in the database. Includes a 'size' item that contains the length of + on side of the board, so that gobans of size 9x9, 13x13 and 19x19 can be + displayed. + + . <--- YOU ARE HERE. + +m6: manage users and game sessions inside database + manage user accounts and the game(s) they currently play inside the data- + base. each game has its own table, which contains players, current turn, + size, the goban inside the database. users are managed in a different + table. For each user the following data is stored: password, current games + (up to 8 or so). So if the user calls the cgi script, she has to send + username and password and is then given the choice of game to play. If + there is only one active game, directly present the goban. + +m7: implement Go rules + Do not accept player moves which violate go rules. Remove beaten stones. + Count and display the score for each player. + +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. + -- python profiler + -- http://peter.mapledesign.co.uk/weblog/archives/python_is_slow.html + create a set of images smaller than 50 pixels (for the 19x19 goban) + +m9: make it standards compliant + w3c validation \ No newline at end of file diff --git a/TODO b/TODO new file mode 100644 index 0000000..1e74532 --- /dev/null +++ b/TODO @@ -0,0 +1 @@ +- hoshi Bilder fuer weisse und schwarze Steine erstellen \ No newline at end of file diff --git a/generate_goban_images.py b/generate_goban_images.py new file mode 100755 index 0000000..2993d12 --- /dev/null +++ b/generate_goban_images.py @@ -0,0 +1,25 @@ +#!/usr/bin/python +""" +a simple script using pil to generate the goban from background, grid and stone images. +""" +import Image +gridlist = ["bottomleftline","bottomline","bottomrightline", + "centerline","hoshi","leftline","rightline", + "topleftline", "topline","toprightline"] + +whitestone = Image.open("imgsource/whitestone.png").convert("RGBA") +blackstone = Image.open("imgsource/blackstone.png").convert("RGBA") + +for item in gridlist: + #creating empty goban + bg = Image.open("imgsource/background.png").convert("RGBA") + img = Image.open("imgsource/"+item+".png").convert("RGBA") + bg.paste(img,None,img) + bg.save("img/"+item+".png") + tmp = bg #for the black stones + #filling with white stones + bg.paste(whitestone,None,whitestone) + bg.save("img/"+item+"_white.png") + #filling with black stones + tmp.paste(blackstone,None,blackstone) + tmp.save("img/"+item+"_black.png") diff --git a/goban.py b/goban.py new file mode 100755 index 0000000..06c4176 --- /dev/null +++ b/goban.py @@ -0,0 +1,174 @@ +#!/usr/bin/python + +""" +the main file for WebGo. +""" +import sys,string +import cgi +import pickle +import psql,helper + +picklefile = "goban.pickledump" + +############################################################################### + + + +def display_goban(goban): + """ + gets: dictionary containing the layout of the used goban. + returns: string containing the HTML code for a clickable goban. + """ + data = "" + + hoshis19x19 = [(4,4),(4,10),(4,16),(10,4),(10,10),(10,16),(16,4),(16,10),(16,16)] + hoshis13x13 = [(4,4),(4,10),(7,7),(10,4),(10,10)] + hoshis9x9 = [(3,3),(3,7),(5,5),(7,3),(7,7)] + + + data += '
' + try: + size = goban["size"] + except: + #TODO: proper error management + raise "[EE] display_goban: got broken goban dictionary." + sys.exit(1) + for x in range(1,size+1): + for y in range(1,size+1): + # check for white or black stone + if goban[(x,y)] == 1: + stone = "_white" + elif goban[(x,y)] == 2: + stone = "_black" + else: + stone = "" + sx = str(x) + sy = str(y) + # check position: + if (x == 1) and (y == 1): # upper left + data += '' + elif (x == 1) and (y == size): # upper right + data += '
' + elif (x == size) and (y == size): # lower right + data += '
' + elif (x == size) and (y == 1): # lower left + data += '' + elif (y == 1): #left line + data += '' + elif (x == 1): # top line + data += '' + elif (y == size): # right line + data += '
' + elif (x == size): #bottom line + data += '' + else: # hoshi or empty inner field + defaultfield = '' + #too lazy to make special images for hoshi fields with stones: + if goban[(x,y)] == 1: + hoshifield = '' + elif goban[(x,y)] == 2: + hoshifield = '' + else: #empty hoshi + hoshifield = '' + if size == 19: # 9 hoshis + if (x,y) in hoshis19x19: + data += hoshifield + else: + data += defaultfield + elif size == 13: + if (x,y) in hoshis13x13: + data += hoshifield + else: + data += defaultfield + elif size == 9: + if (x,y) in hoshis9x9: + data += hoshifield + else: + data += defaultfield + data += '
' + return data + + + + + +def string_to_tuple(str): + """ + gets a string. If the string contains '(',')' and ',', then return + a tuple processed from the string. If the partial string is empty, then + -1 will be returned for that value. + """ + if (str[0] =='(') and (str[-1] ==')') and (string.find(str,',')): + splitlist = string.split(str[1:-1],",") + returnlist = [] + for item in splitlist: + try: + returnlist.append(int(item)) + except: #empty string + returnlist.append(-1) + return tuple(returnlist) + + +def process_form(goban): + """ + gets a goban dictionary. + + reads out the returned CGI form. + if the goban has been clicked, return a (x,y) tuple of the position. + + """ + #get instance of fieldstorage + form = cgi.FieldStorage() + #if form == empty (which means if page is displayed for the first time): + if form.keys() != []: + #cut out the name of the clicked button + namestring = string.split(form.keys()[0],".x")[0] + position = 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 + + +def set_stone(goban, position): + """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 tone (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 + else: + return "Could not make move: Field not empty." + +############################################################################### + +def main(): + # Print the required header that tells the browser how to render the text. + #(currently done by error logger) + #print "Content-Type: text/plain\n\n" + + #do stuff + data = helper.header() + + #read goban table from database + tmplist = psql.read_table("test") + #make a dictionary out of the list + goban = psql.fetchall_list_to_goban_dict(tmplist) + #print goban + + (goban,str) = process_form(goban) + data += "

Turn number: %s, %s Player's Move.

" % (goban["turn_number"],("White","Black")[goban["turn_number"] % 2]) #eleet ;> + data += display_goban(goban) + if str != "": + data +="\n

"+str+"

\n" + + + data += helper.footer() + print data + + \ No newline at end of file diff --git a/helper.py b/helper.py new file mode 100644 index 0000000..cdb4d3e --- /dev/null +++ b/helper.py @@ -0,0 +1,38 @@ +def header(): + """return html header""" + data = """ + + + + """ + return data + +def footer(): + """return html footer""" + data = """ + + """ + return data + +# create a unique session id +def generate_session_id(): + import md5, time, base64, random, string + m = md5.new() + m.update(str(time.time())) + m.update(str(random.random())) + return string.replace(base64.encodestring(m.digest())[:-3], '/', '$') + + +def check_for_int(data): + """ + gets a string. if string is an integer: return integer. + else return given string. + """ + #check if value is int + num = [n for n in data if n.isdigit()] + tmp = "".join(num) + if tmp == data: + ret = int(data) + else: + ret = data + return ret \ No newline at end of file diff --git a/img/bottomleftline.png b/img/bottomleftline.png new file mode 100644 index 0000000..9be1f27 Binary files /dev/null and b/img/bottomleftline.png differ diff --git a/img/bottomleftline_black.png b/img/bottomleftline_black.png new file mode 100644 index 0000000..a045992 Binary files /dev/null and b/img/bottomleftline_black.png differ diff --git a/img/bottomleftline_white.png b/img/bottomleftline_white.png new file mode 100644 index 0000000..c052c28 Binary files /dev/null and b/img/bottomleftline_white.png differ diff --git a/img/bottomline.png b/img/bottomline.png new file mode 100644 index 0000000..2fe367d Binary files /dev/null and b/img/bottomline.png differ diff --git a/img/bottomline_black.png b/img/bottomline_black.png new file mode 100644 index 0000000..85f86d5 Binary files /dev/null and b/img/bottomline_black.png differ diff --git a/img/bottomline_white.png b/img/bottomline_white.png new file mode 100644 index 0000000..edadbfd Binary files /dev/null and b/img/bottomline_white.png differ diff --git a/img/bottomrightline.png b/img/bottomrightline.png new file mode 100644 index 0000000..bd53949 Binary files /dev/null and b/img/bottomrightline.png differ diff --git a/img/bottomrightline_black.png b/img/bottomrightline_black.png new file mode 100644 index 0000000..a30627d Binary files /dev/null and b/img/bottomrightline_black.png differ diff --git a/img/bottomrightline_white.png b/img/bottomrightline_white.png new file mode 100644 index 0000000..2259f54 Binary files /dev/null and b/img/bottomrightline_white.png differ diff --git a/img/centerline.png b/img/centerline.png new file mode 100644 index 0000000..dea30d3 Binary files /dev/null and b/img/centerline.png differ diff --git a/img/centerline_black.png b/img/centerline_black.png new file mode 100644 index 0000000..a3aa587 Binary files /dev/null and b/img/centerline_black.png differ diff --git a/img/centerline_white.png b/img/centerline_white.png new file mode 100644 index 0000000..3eb550a Binary files /dev/null and b/img/centerline_white.png differ diff --git a/img/centerwhite.png b/img/centerwhite.png new file mode 100644 index 0000000..0f0aaba Binary files /dev/null and b/img/centerwhite.png differ diff --git a/img/hoshi.png b/img/hoshi.png new file mode 100644 index 0000000..707317e Binary files /dev/null and b/img/hoshi.png differ diff --git a/img/hoshi_black.png b/img/hoshi_black.png new file mode 100644 index 0000000..a3aa587 Binary files /dev/null and b/img/hoshi_black.png differ diff --git a/img/hoshi_white.png b/img/hoshi_white.png new file mode 100644 index 0000000..3eb550a Binary files /dev/null and b/img/hoshi_white.png differ diff --git a/img/leftline.png b/img/leftline.png new file mode 100644 index 0000000..691cd26 Binary files /dev/null and b/img/leftline.png differ diff --git a/img/leftline_black.png b/img/leftline_black.png new file mode 100644 index 0000000..0f924ed Binary files /dev/null and b/img/leftline_black.png differ diff --git a/img/leftline_white.png b/img/leftline_white.png new file mode 100644 index 0000000..514e7a5 Binary files /dev/null and b/img/leftline_white.png differ diff --git a/img/rightline.png b/img/rightline.png new file mode 100644 index 0000000..13f413f Binary files /dev/null and b/img/rightline.png differ diff --git a/img/rightline_black.png b/img/rightline_black.png new file mode 100644 index 0000000..db9ec99 Binary files /dev/null and b/img/rightline_black.png differ diff --git a/img/rightline_white.png b/img/rightline_white.png new file mode 100644 index 0000000..70f1e6e Binary files /dev/null and b/img/rightline_white.png differ diff --git a/img/topleftline.png b/img/topleftline.png new file mode 100644 index 0000000..5dd7dda Binary files /dev/null and b/img/topleftline.png differ diff --git a/img/topleftline_black.png b/img/topleftline_black.png new file mode 100644 index 0000000..4ef0fe7 Binary files /dev/null and b/img/topleftline_black.png differ diff --git a/img/topleftline_white.png b/img/topleftline_white.png new file mode 100644 index 0000000..f52577d Binary files /dev/null and b/img/topleftline_white.png differ diff --git a/img/topline.png b/img/topline.png new file mode 100644 index 0000000..98a9691 Binary files /dev/null and b/img/topline.png differ diff --git a/img/topline_black.png b/img/topline_black.png new file mode 100644 index 0000000..4f2d4c8 Binary files /dev/null and b/img/topline_black.png differ diff --git a/img/topline_white.png b/img/topline_white.png new file mode 100644 index 0000000..b24c02b Binary files /dev/null and b/img/topline_white.png differ diff --git a/img/toprightline.png b/img/toprightline.png new file mode 100644 index 0000000..3f20c7a Binary files /dev/null and b/img/toprightline.png differ diff --git a/img/toprightline_black.png b/img/toprightline_black.png new file mode 100644 index 0000000..eafa497 Binary files /dev/null and b/img/toprightline_black.png differ diff --git a/img/toprightline_white.png b/img/toprightline_white.png new file mode 100644 index 0000000..1f2df2a Binary files /dev/null and b/img/toprightline_white.png differ diff --git a/imgsource/background.png b/imgsource/background.png new file mode 100644 index 0000000..cd5e42c Binary files /dev/null and b/imgsource/background.png differ diff --git a/imgsource/blackstone.png b/imgsource/blackstone.png new file mode 100644 index 0000000..209f381 Binary files /dev/null and b/imgsource/blackstone.png differ diff --git a/imgsource/bottomleftline.png b/imgsource/bottomleftline.png new file mode 100644 index 0000000..8eaacef Binary files /dev/null and b/imgsource/bottomleftline.png differ diff --git a/imgsource/bottomline.png b/imgsource/bottomline.png new file mode 100644 index 0000000..76fa4a0 Binary files /dev/null and b/imgsource/bottomline.png differ diff --git a/imgsource/bottomrightline.png b/imgsource/bottomrightline.png new file mode 100644 index 0000000..f70c027 Binary files /dev/null and b/imgsource/bottomrightline.png differ diff --git a/imgsource/centerline.png b/imgsource/centerline.png new file mode 100644 index 0000000..fd339fb Binary files /dev/null and b/imgsource/centerline.png differ diff --git a/imgsource/hoshi.png b/imgsource/hoshi.png new file mode 100644 index 0000000..5a21b35 Binary files /dev/null and b/imgsource/hoshi.png differ diff --git a/imgsource/leftline.png b/imgsource/leftline.png new file mode 100644 index 0000000..cd2c37b Binary files /dev/null and b/imgsource/leftline.png differ diff --git a/imgsource/rightline.png b/imgsource/rightline.png new file mode 100644 index 0000000..82e0a5c Binary files /dev/null and b/imgsource/rightline.png differ diff --git a/imgsource/topleftline.png b/imgsource/topleftline.png new file mode 100644 index 0000000..f39e53b Binary files /dev/null and b/imgsource/topleftline.png differ diff --git a/imgsource/topline.png b/imgsource/topline.png new file mode 100644 index 0000000..dfeee45 Binary files /dev/null and b/imgsource/topline.png differ diff --git a/imgsource/toprightline.png b/imgsource/toprightline.png new file mode 100644 index 0000000..dc5f147 Binary files /dev/null and b/imgsource/toprightline.png differ diff --git a/imgsource/whitestone.png b/imgsource/whitestone.png new file mode 100644 index 0000000..aaa5d3d Binary files /dev/null and b/imgsource/whitestone.png differ diff --git a/init_webgo.py b/init_webgo.py new file mode 100755 index 0000000..ed2e628 --- /dev/null +++ b/init_webgo.py @@ -0,0 +1,23 @@ +import psql + + +def clear(): + try: + psql.drop_table("test") + psql.drop_table("users") + except: + pass + +def create(): + psql.create_goban_table(9) + psql.create_user_table() + psql.add_webgo_user("gast","gast") + psql.add_webgo_user("gast2","gast2") + + +def main(): + clear() + create() + + + \ No newline at end of file diff --git a/login.py b/login.py new file mode 100755 index 0000000..dee3a1a --- /dev/null +++ b/login.py @@ -0,0 +1,130 @@ +import psql,init_webgo,helper +import time +from mod_python import * + +def process_form(req,form): + """ + reads username and passsword from form + """ + #if form == empty (which means if page is displayed for the first time): + req.write(str(form.keys())) + #req.write("
"+"name="+form['name']+", password="+form['password']+"
") + if form.keys() != []: + + if ("name" in form.keys()) and ("password" in form.keys()): + #extract name and password + name = form["name"] + password = form["password"] + sessionid = form["sessionid"] + origpassword = psql.get_user_info(name,"password") + #check if user exists (else we would get an error string) + if origpassword != "no such user": #no error message, now check password + req.write("hier bin ich in der Schleife.
") + req.write(str(origpassword)+"
") + if password == origpassword: + #login accepted + psql.set_user_sessionid(name,sessionid) + psql.set_user_timeout(name) + #now display list of games. + game_overview_form(req,name,sessionid) + else: + req.write("Login incorrect. Please try again.
") + req.write(login_form()) + else: #no such user + req.write("Login incorrect. Please try again.
") + req.write(login_form()) + else: #one of (name,password) is missing: + req.write("Please enter your name and password.") + req.write(login_form()) + + +def game_overview_form(req,user,sessionid): + """ + gets the name of a user and the queue of games. + prints a form with the option to select,create and delete games. + """ + data = helper.header()+ """ +

Current Games:

+
+ """ + gamelist = psql.get_user_game_list(user) + req.write(str(gamelist)+"
\n") + #display list of current games + counter = 10 + tmp = "" + for item in gamelist: + if (item != None) and (item != "None"): + tmp += ' name="game" value="%s"> %s\n' % (item,item) + tmp += '\n' % sessionid + tmp += '\n' % user + #later write partners name and whether its our turn or not + #data += "Your partner: %s." + tmp +="
" + counter -= 1 + if tmp == "": #no current games + data += "You don't have any running games.\n" + else: + data += tmp + data += '\n\n
' + #now comes the option for creating new games. + data += "

Start a new Game

\n" + if counter > 0: + data+= "You have %s free game slots.
" % counter + data += """ +
+ + + + +
+ """ % (sessionid, user) + else: + data+= "Sorry, all your game slots are in use." + #display "You have ... free game slots" + Button "create game" + #bei "create game neue funktion zum Erstellen + Mitspieler aus Liste auswählen. + data+=helper.footer() + #check for timeout: + if (psql.get_user_info(user,'timeout') >= int(time.time())) and (sessionid == psql.get_user_info(user,'sessionid')): + req.write(data) + else: + req.write(helper.header()+ 'your session timed out'+helper.footer()) + +def login_form(): + """ + print welcome message and html form. + """ + data = helper.header() + """ + +
+

Name:
+

+

Pasword:
+

+ +

+
+ """ % helper.generate_session_id() + data += helper.footer() + + + return data + + +def create_new_game(req,user): + """ + create a new game for user. + gets: request object, username. + """ + + + +def main(req): + #get instance of fieldstorage + form = util.FieldStorage(req) + if "sessionid" not in form.keys(): + req.write(login_form()) + elif ("create" in form.keys()) and ("username" in form.keys()): + #user wants to create a new game + create_new_game(req,form["username"]) + else: + process_form(req,form) diff --git a/main.py b/main.py new file mode 100755 index 0000000..5ca513b --- /dev/null +++ b/main.py @@ -0,0 +1,73 @@ +#!/usr/bin/python +""" +simple cgi wrapper for a cgi script, prints the error of the script as html +taken from http://gnosis.cx/publish/programming/feature_5min_python.html +modified a little +""" + +from mod_python import apache + +import sys, traceback +import init_webgo + +DEBUG = 1 + + +def handler(req): + # "Content-type: text/html\n\n" + req.content_type = "text/html" + try: # use explicit exception handling + #reinitialize database + init_webgo.main() + + login = apache.import_module("login") + login.main(req) + return apache.OK + except: + import time + errtime = '----- '+ time.ctime(time.time()) +' -----\n' + errlog = open('/tmp/cgi_errors.log', 'a') + errlog.write(errtime) + errlog.write(ErrorMsg()) + data = """CGI Error Encountered! +

Sorry, a problem was encountered running WebGo.

+

Please check the error log on the server for details.

+
"""
+		data += ErrorMsg()
+		data+="
\n" + req.write(data) + return apache.OK + + + + +def ErrorMsg(escape=0): + """ + returns: string + + simualtes the traceback output and if argemument + set to 1 (true) the string will be + converted to fit into html documents without problems. + from Dirk Holtwick + """ + import traceback, sys, string + + type=None + value=None + tb=None + limit=None + type, value, tb = sys.exc_info() + body = "Traceback (innermost last):\n" + list = traceback.format_tb(tb, limit) + traceback.format_exception_only(type, value) + body = body + "%-20s %s" % ( + string.join(list[:-1], ""), + list[-1], + ) + if escape: + import cgi + body = cgi.escape(body) + return body + + + +#start(req) \ No newline at end of file diff --git a/mptest.py b/mptest.py new file mode 100755 index 0000000..d91cae8 --- /dev/null +++ b/mptest.py @@ -0,0 +1,7 @@ +from mod_python import apache + +def handler(req): + req.write("Hello World!") + return apache.OK + + diff --git a/old_functions.py b/old_functions.py new file mode 100755 index 0000000..fdd3415 --- /dev/null +++ b/old_functions.py @@ -0,0 +1,51 @@ +def init_goban(size=9): + """ + Returns an empty goban in the form of a dictionary where the keys are + x,y-tuples: (1,1) is the upper left corner, (9,9) the lower right one + for a 9x9 goban. + The additional key named size contains the length of a side of the goban. + Content of a field: + 0 == empty field + 1 == white stone on field + 2 == black stone on field + Field turn_number: Current turn to be played. Even: white, uneven: black. + Optional argument size: define length of a side of the goban (one of + 9, 12 or 19). Defaults to 9. + Returns dictionary. + """ + goban = {} + for x in range(1,size+1): + for y in range(1,size+1): + goban[(x,y)] = 0 + if (size == 9) or (size == 13) or (size == 19): + goban["size"] = size + else: + goban["size"] = 9 + goban["turn_number"] = 1 + + #some stones for testing purposes + goban[(1,2)] = 1; goban[(2,1)] = 1; goban[(2,3)] = 1; goban[(3,3)] = 1; goban[(6,7)] = 1; goban[(6,9)] = 1 + goban[(2,2)] = 2; goban[(1,3)] = 2; goban[(4,7)] = 2; goban[(4,9)] = 2; goban[(5,8)] = 2; goban[(7,9)] = 2 + + return goban + + +def save_goban(goban): + """gets a goban dictionary and pickles it to a file. + """ + try: + f = open(picklefile,"w") + pickle.dump(goban,f) + f.close() + except: + print "error: could not write to file "+picklefile+"!" + +def load_goban(): + """trys to load and return a pickled goban. If this does not work return + a newly initialized goban.""" + try: + f = open(picklefile,"r") + return pickle.load(f) + f.close() #datei ist jetzt genullt + except: + return init_goban() \ No newline at end of file diff --git a/psql.py b/psql.py new file mode 100755 index 0000000..f0b1df3 --- /dev/null +++ b/psql.py @@ -0,0 +1,274 @@ +import helper +import pgdb,sys + +dbusername="webgouser" +dbpassword="webgopassword" +dbname="webgo" + + + +#pgdb.connect(connect_string) -> connection +#connect_string = 'host:database:user:password:opt:tty' +connect_string='localhost:'+dbname+':'+dbusername+':'+dbpassword +db=pgdb.connect(connect_string) + + +def create_table(name,layout=""): + """ + create_table(name:string, layout:string) + returns name if successfull, None if not. + + + simple function to create a table. the function itself would just + create an empty table with the command 'CREATE TABLE ();'. + The real layout is given to the function as an argument of type + string. This string contains all column declarations in SQL syntax: + "var1 real, var2 int" + name is the name of the table + + """ + executestring = "CREATE TABLE %s ( %s );" % (name,layout) + sql_one_liner(executestring) + + + +def insert_into_table(table, content): + """ + gets the name of a table and a content string. + executes INSERT INTO name VALUES content; + """ + executestring = "INSERT INTO %s VALUES %s" % (table,content) + sql_one_liner(executestring) + + + +def drop_table(name): + """ + gets: name of table. + executes DROP TABLE + """ + executestring = "DROP TABLE %s;" % (name) + sql_one_liner(executestring) + + +def sql_one_liner(data): + """ + gets:SQL statement + creates a cursor, executes , closes cursor. + """ + cursor=db.cursor() + cursor.execute(data) + # Commit the changes + db.commit() + cursor.close() + + +def create_goban_table(size): + """ + gets:size of goban. + creates postgresql table containing goban data. + returns: name of created table. + """ + tablename="test" + data="line varchar(15)" + for i in range(1,size+1): + if data != "": + data += ", " + data += "x"+str(i) + ' varchar(15)' + create_table(tablename,data) + #table created, now fill the table + for i in range(1,size+1): + tmplist=[] + tmplist.append("y"+str(i)) + for k in range(1,size+1): + tmplist.append(0) + insert_into_table(tablename,str(tuple(tmplist))) + #ok, goban itself has been created and filled, + #now insert additional variables + tmplist=[] + tmplist.append("turn_number") + tmplist.append("1") + insert_into_table(tablename,str(tuple(tmplist))) + #size of goban + tmplist=[] + tmplist.append("size") + tmplist.append(size) + insert_into_table(tablename,str(tuple(tmplist))) + #name of goban (=name of table in database) + tmplist=[] + tmplist.append("name") + tmplist.append(tablename) + insert_into_table(tablename,str(tuple(tmplist))) + return tablename + +def create_user_table(): + """ + creates a table named users with following columns: + name - name of user + password - passsword of user + game1 - the 10 game slots of this user contain names + ... of goban tables + game10 + sessionid - id of current session + timeout - when does session time out? + """ + data = "username varchar(15)" + data += ", password varchar(15)" + for i in range(1,11): + data += ", game"+str(i)+" varchar(15)" + data += ", sessionid text" + data += ", timeout int" + create_table("users",data) + + +def read_table(table): + """ + gets the name of a table, does a + SELECT * FROM table; + returns output. + """ + cursor=db.cursor() + data="SELECT * FROM %s;" % (table) + cursor.execute(data) + # Commit the changes + db.commit() + ret = cursor.fetchall() + cursor.close() + return ret + +def get_user_game_list(name): + """ + gets a username, returns the list of games for user. + """ + cursor=db.cursor() + ret = [] + for x in range(1,11): + data="SELECT game%s FROM users WHERE username = '%s'" % (x,name) + try: + cursor.execute(data) + # Commit the changes + db.commit() + ret.append(cursor.fetchone()[0]) #[0], because return is a list + except: + ret = "could not get info of all games -- table corrupt?" + return ret + cursor.close() + return ret + +def get_user_info(name,infotype): + """ + gets the name of a user and the type of requested info. + returns info from database. + """ + cursor=db.cursor() + if infotype in ("password","sessionid","timeout"): + + data="SELECT %s FROM users WHERE username = '%s'" % (infotype,name) + try: + cursor.execute(data) + # Commit the changes + db.commit() + ret = cursor.fetchone()[0] #[0], because return is a list + except: + ret = "no such user" + cursor.close() + else: + ret = "Are your sure about the infotype?" + return ret + +def set_user_sessionid(username,sessionid): + """ + gets username and sessionid, writes sessid into database + """ + executestring ="UPDATE users SET sessionid = '%s' WHERE username = '%s'" %(sessionid, username) + sql_one_liner(executestring) + +def set_user_timeout(username): + """ + gets username, sets timeout to time.time + 30min + """ + import time + timeout = int(time.time()) + 1800 #current time in seconds + seconds for session + executestring ="UPDATE users SET timeout = '%s' WHERE username = '%s'" %(timeout, username) + sql_one_liner(executestring) + + +def update_database_field(table,column,line,data): + """ + gets: table name, column name, line name, new content for field. + executes an SQL UPDATE statement for line. + """ + #TODO:schreiben + executestring ="UPDATE %s SET %s = '%s' WHERE line = '%s'" %(table,column,data,line) + sql_one_liner(executestring) + +def update_goban_field(table,x,y,content): + """ + gets: goban dictionary, x,y coordinates, new content for field. + modifies goban in database. + """ + update_database_field(table,"x"+str(x),"y"+str(y),content) + +def update_turn_number(table,new_number): + """ + gets: name of table,new turn number + modifies 'turn_number' in table + """ + update_database_field(table,"x1","turn_number",new_number) + +def add_webgo_user(name,password): + """ + adds a database entry for a user. + gets: username and password + """ + #size of goban + tmplist=[] + tmplist.append(name) + tmplist.append(password) + insert_into_table("users",str(tuple(tmplist))) + +def fetchall_list_to_goban_dict(list): + """ + gets the output from read_table (a list), + returns a goban dictionary. + """ + #create dictionary + ret = {} + #get size of goban + for item in list: + if item[0] == "size": + size=int(item[1]) + ret["size"] = size + #populate dictionary with goban field + for item in list: + if item[0][0] == "y": #goban fields + #get current y coordinate + y = int(item[0][1:]) + #fill dictionary for current y coordinate + for x in range(1,size+1): + ret[(x,y)]=helper.check_for_int(item[x]) + else: #other variables + ret[item[0]]=helper.check_for_int(item[1]) + + return ret + + + +def test(): + #create_table("test") + drop_table("test") + create_goban_table(9) + update_database_field("test","x1","turn_number",4) + list = read_table("test") + print list + dict = fetchall_list_to_goban_dict(list) + print dict + print dict["turn_number"] + print dict["name"] + print type(dict["turn_number"]) + + + +#test() + + diff --git a/test.py b/test.py new file mode 100644 index 0000000..e2a1d50 --- /dev/null +++ b/test.py @@ -0,0 +1,3 @@ +def hello(req): + x = "Hello, world!" + return x