diff --git a/pyfpdb/RushNotesAux.py b/pyfpdb/RushNotesAux.py index 3a445a0f..312de6d5 100644 --- a/pyfpdb/RushNotesAux.py +++ b/pyfpdb/RushNotesAux.py @@ -26,16 +26,14 @@ The existing notes file will be altered by this function ######################################################################## -##########for each hand processed, attempts to update hero.xml player notes for FullTilt +##########for each hand processed, attempts to create update for player notes in FullTilt ##########based upon the AW howto notes written by Ray E. Barker (nutomatic) at fpdb.sourceforge.net +##########Huge thanks to Ray for his guidance and encouragement to create this !! -#to do -### think about seeding -### multiple huds firing at the same xml -### same player / two levels / only one xml -### http://www.faqs.org/docs/diveintopython/kgp_search.html - +# #debugmode will write logfiles for the __init__ and update_data methods +# writes into ./pyfpdb/~Rushdebug.* +# debugmode = False # Standard Library modules @@ -50,9 +48,10 @@ from Mucked import Aux_Window from Mucked import Seat_Window from Mucked import Aux_Seats import Stats +import Card # -# overload minidom methods to fix bug where \n is parsed as " ". +# overload minidom methods to fix bug where \n is parsed as " ". # described here: http://bugs.python.org/issue7139 # @@ -110,7 +109,8 @@ class RushNotes(Aux_Window): notepath = site_params_dict['site_path'] # this is a temporary hijack of site-path self.heroid = self.hud.db_connection.get_player_id(self.config, sitename, heroname) self.notefile = notepath + "/" + heroname + ".xml" - + self.rushtables = ("Mach 10", "Lightning", "Celerity", "Flash", "Zoom") + if not os.path.isfile(self.notefile): self.active = False return @@ -129,28 +129,27 @@ class RushNotes(Aux_Window): outputfile.close() xmlnotefile.unlink + # # Create a fresh queue file with skeleton XML - # + # self.queuefile = self.notefile + ".queue" - queuedom = minidom.Document() - # Create the minidom document + queuedom = minidom.Document() -# Create the base element pld=queuedom.createElement("PLAYERDATA") queuedom.appendChild(pld) nts=queuedom.createElement("NOTES") pld.appendChild(nts) - + nte = queuedom.createElement("NOTE") nte = queuedom.createTextNode("\n") - nts.insertBefore(nte,None) - + nts.insertBefore(nte,None) + outputfile = open(self.queuefile, 'w') queuedom.writexml(outputfile) outputfile.close() queuedom.unlink - + if (debugmode): #initialise logfiles debugfile=open("~Rushdebug.init", "w") @@ -159,19 +158,19 @@ class RushNotes(Aux_Window): debugfile.write("para="+str(params)+"\n") debugfile.write("hero="+heroname+" "+str(self.heroid)+"\n") debugfile.write("back="+notefilebackup+"\n") - debugfile.write("queu="+self.queuefile+"\n") + debugfile.write("queu="+self.queuefile+"\n") debugfile.close() - + open("~Rushdebug.data", "w").close() - + def update_data(self, new_hand_id, db_connection): #this method called once for every hand processed # self.hud.stat_dict contains the stats information for this hand - + if not self.active: return - + if (debugmode): debugfile=open("~Rushdebug.data", "a") debugfile.write(new_hand_id+"\n") @@ -179,10 +178,11 @@ class RushNotes(Aux_Window): debugfile.write(now.strftime("%Y%m%d%H%M%S")+ " update_data begins"+ "\n") debugfile.write("hero="+str(self.heroid)+"\n") #debugfile.write(str(self.hud.stat_dict)+"\n") - debugfile.write(self.hud.table.name+"\n") - debugfile.write(str(self.hud.stat_dict.keys())+"\n") + debugfile.write("table="+self.hud.table.name+"\n") + debugfile.write("players="+str(self.hud.stat_dict.keys())+"\n") + debugfile.write("db="+str(db_connection)+"\n") - if self.hud.table.name not in ("Mach 10", "Lightning", "Celerity", "Flash", "Zoom"): + if self.hud.table.name not in self.rushtables: return # # Grab a list of player id's @@ -212,18 +212,74 @@ class RushNotes(Aux_Window): agg_freq=str(Stats.do_stat(self.hud.stat_dict, player = playerid, stat = 'agg_freq')[3] + " ") BBper100=str(Stats.do_stat(self.hud.stat_dict, player = playerid, stat = 'BBper100')[3]) if BBper100[6] == "-": BBper100=BBper100[0:6] + "(" + BBper100[7:] + ")" - - xmlqueuedict[playername] = ("~fpdb~" + "\n" + - n + vpip + pfr + three_B + fbbsteal + "\n" + - steal + cbet + ffreq1 + "\n" + - agg_freq + BBper100 + "\n" + + + + # + # grab villain known starting hands + # only those where they VPIP'd, so limp in the BB will not be shown + # sort by hand strength. Output will show position too, + # so KK.1 is KK from late posn etc. + # ignore non-rush hands (check against known rushtablenames) + # cards decoding is hard-coded for holdem, so that's tuff atm + # three categories of known hands are shown: + # agression preflop hands + # non-aggression preflop hands + # bigblind called to defend hands + # + # This isn't perfect, but it isn't too bad a starting point + # + + PFcall="PFcall" + PFaggr="PFaggr" + PFdefend="PFdefend" + + c = db_connection.get_cursor() + c.execute(("SELECT handId, position, startCards, street0Aggr, tableName " + + "FROM hands, handsPlayers " + + "WHERE handsplayers.handId = hands.id " + + "AND street0VPI = 1 " + + "AND startCards > 0 " + + "AND playerId = %d " + + "ORDER BY startCards DESC " + + ";") + % int(playerid)) + + for (qid, qposition, qstartcards, qstreet0Aggr, qtablename) in c.fetchall(): + if (debugmode): + debugfile.write("pid, hid, pos, cards, aggr, table player"+ + str(playerid)+"/"+str(qid)+"/"+str(qposition)+"/"+ + str(qstartcards)+"/"+str(qstreet0Aggr)+"/"+ + str(qtablename)+"/"+str(playername)+ + "\n") + + humancards = Card.decodeStartHandValue("holdem", qstartcards) + + if qtablename not in self.rushtables: + pass + elif qposition == "B" and qstreet0Aggr == False: + PFdefend=PFdefend+"/"+humancards + elif qstreet0Aggr == True: + PFaggr=PFaggr+"/"+humancards+"."+qposition + else: + PFcall=PFcall+"/"+humancards+"."+qposition + c.close + + # + # build up final text package (top/tail with ~fpdb~ ~ends~ + # for later search/replace by Merge module + # + xmlqueuedict[playername] = ("~fpdb~" + "\n" + + n + vpip + pfr + three_B + fbbsteal + "\n" + + steal + cbet + ffreq1 + "\n" + + agg_freq + BBper100 + "\n" + + PFcall+"\n"+PFaggr+"\n"+PFdefend +"\n" "~ends~") if (debugmode): now = datetime.now() debugfile.write(now.strftime("%Y%m%d%H%M%S")+" villain data has been processed" + "\n") debugfile.write(str(xmlqueuedict)+"\n") - + # # delaying processing of xml until now. Grab current queuefile contents and # read each existing NOTE element in turn, if matched to a player in xmlqueuedict @@ -244,26 +300,26 @@ class RushNotes(Aux_Window): if len(xmlqueuedict) > 0: playerdata=xmlnotefile.lastChild #move to the PLAYERDATA node (assume last one in the list) notesnode=playerdata.childNodes[0] #Find NOTES node - + for newplayer in xmlqueuedict: newentry = xmlnotefile.createElement("NOTE") newentry.setAttribute("PlayerId", newplayer) - newentry.setAttribute("Text", xmlqueuedict[newplayer]) + newentry.setAttribute("Text", xmlqueuedict[newplayer]) notesnode.insertBefore(newentry,None) newentry = xmlnotefile.createTextNode("\n") notesnode.insertBefore(newentry,None) - + if (debugmode): now = datetime.now() debugfile.write(now.strftime("%Y%m%d%H%M%S")+" xml pre-processing complete"+ "\n") - + # # OverWrite existing xml file with updated DOM and cleanup # updatednotes = open(self.queuefile, 'w') xmlnotefile.writexml(updatednotes) updatednotes.close() - + xmlnotefile.unlink if (debugmode): diff --git a/pyfpdb/RushNotesMerge.py b/pyfpdb/RushNotesMerge.py index f22b67ab..7bfec3df 100755 --- a/pyfpdb/RushNotesMerge.py +++ b/pyfpdb/RushNotesMerge.py @@ -7,7 +7,7 @@ Merge .queue file with hero's note to generate fresh .merge file normal usage -$> ./pyfpdb/RushNotesMerge.py "/home/steve/.wine/drive_c/Program Files/Full Tilt Poker/heroname.xml" +$> ./pyfpdb/RushNotesMerge.py "/home/foo/.wine/drive_c/Program Files/Full Tilt Poker/heroname.xml" The generated file can then replace heroname.xml (if all is well). @@ -37,7 +37,7 @@ import sys from xml.dom import minidom # -# overload minidom methods to fix bug where \n is parsed as " ". +# overload minidom methods to fix bug where \n is parsed as " ". # described here: http://bugs.python.org/issue7139 # @@ -92,14 +92,20 @@ try: sys.argv[1] <> "" except: print "A parameter is required, quitting now" + print "normal usage is something like:" + print '$> ./pyfpdb/RushNotesMerge.py "/home/foo/.wine/drive_c/Program Files/Full Tilt Poker/myhero.xml"' quit() if not os.path.isfile(sys.argv[1]): print "Hero notes file not found, quitting" + print "normal usage is something like:" + print '$> ./pyfpdb/RushNotesMerge.py "/home/foo/.wine/drive_c/Program Files/Full Tilt Poker/myhero.xml"' quit() if not os.path.isfile((sys.argv[1]+".queue")): - print "Nothing queued, quitting" + print "Nothing found to merge, quitting" + print "Did the HUD not get started during the last session?" + print "Has the HUD been stopped and started without merging?" quit() print "***************************************************************" diff --git a/pyfpdb/RushNotesReadMe.txt b/pyfpdb/RushNotesReadMe.txt index 595b5adb..43475536 100644 --- a/pyfpdb/RushNotesReadMe.txt +++ b/pyfpdb/RushNotesReadMe.txt @@ -12,24 +12,40 @@ RushNotesMerge - stand alone process to merge the existing ftp notes, together w the output file can then be renamed to become the new ftp notes file Important info: -The Merge process can only be run when ftp client is shutdown - otherwise ftp overwrites the xml on exit. +The Merge process can only be run when ftp client is shutdown + - otherwise ftp overwrites the xml on exit. -Restarting the autoimport will empty the notes"queue" so avoid restarting autoimport until the previous -notes "queue" has been merged. +Restarting the autoimport will empty the notes"queue" so avoid restarting + autoimport until the previous notes "queue" has been merged. You will + lose all the queued notes, but these will be regenerated the next time + the villian is at your table, so it isn't the end of the world. -Existing ftp notes _SHOULD_ be preserved, but this isn't guaranteed, you have been warned -Existing colour codings should be preserved, this process should not change colourcodings. +Existing ftp notes _SHOULD_ be preserved, but this isn't guaranteed, + you have been warned! + +Existing colour codings should be preserved, + this process does not change or set colourcodings. -Copies of the live ftp notes file are preserved everytime RushNotesAux is started, just in case. +Copies of the live ftp notes file should be preserved everytime + RushNotesAux (i.e. the HUD is started) -The AW is hard-coded with just the table names of Micro Rush Poker, and should ignore all other hands. +The AW is hard-coded with just the table names of Micro Rush Poker, + and should ignore all other hands. +What might not work? +-------------------- + +This isn't tested with Windows, and probably won't work, feedback welcome. +Hasn't been tested for co-existance with other sites, feedback welcome. +Whenever FTP change their notes file format, this will all break rather spectacularly, + you have been warned! + Getting started: --------------- 1. Set the Hero aggregation to alltime. hero_stat_range="A" - This overcomes a sqlite "bug" which has nothing to do with auxillary windows - not doing this - will slow processing down to about 1 hand per minute. + This overcomes a sqlite "bug" which has nothing to do with auxillary windows + not doing this will slow processing down to about 1 hand per minute. 2. Set the site_path to be the folder containing the FTP notes xml file (on wine this is normally site_path="/home/blah/.wine/Program Files/Full Tilt Poker/") @@ -43,12 +59,17 @@ Wire-up the aux process: or whatever works for you. -Start Autoimport, and rearrange the on-screen stats out of the way - (killing the HUD kills the AW updates) Play some poker +--------------- + +Start Autoimport, and rearrange the on-screen stats out of the way + (the full HUD must run, killing the HUD kills the AW updates) + +Play whatever you want Stop the autoimport + Exit the Full tilt poker client (ensure it has fully stopped with ps -A) execute the following: @@ -59,14 +80,20 @@ A revised notes file (blah.merge) should automagically appear in the full tilt r If you are happy with it, replace the existing (myname.xml file) +Since the updates aren't real time, it would be ok to play the rush + session with fpdb inactive, but before quitting any of the tables, + start the HUD and wait for it to catch-up processing all the hands played. + + Summary ------- +------- This is very rough and ready, but it does what I set-out to achieve. -All feedback welcome, and if this is useful as a basis for general notes processing, then thats great. +All feedback welcome, and if this is useful as a basis for general notes + processing in future, then thats great. -As I find bugs and make improvements, I will push to the git branch. +As I find bugs and make improvements, I will push to git. Much more information below: @@ -136,12 +163,13 @@ It is hoped that due to the relatively large hand volume and relatively small although there will obviously be a number of players with no fpdb note. The aggregation parameters used for the notes are based upon the HUD parameters. + (with the exception of the hand-ranges, which uses its' own criteria (see source) -Stopping and starting the HUD will erase the previously created notes holding file. +Stopping and starting the HUD will erase the previously created notes queue file. The HUD must run, so the individual player popups need to be manually relocated. -Although hard-coded for micro RUSH tablenames, the auxilliary window will +Although hard-coded for micro RUSH tablenames, the auxilliary window could probably happily update notes of all cash and tournament players. Process overview