From 333cbdbf6d5eae77a690b94f14eddda9f1858882 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 25 Feb 2009 23:35:15 -0500 Subject: [PATCH 1/6] Speed and reliability changes (+cleanup) to aux window interface. --- pyfpdb/Database.py | 34 +++++++++++++++---------------- pyfpdb/HUD_main.py | 18 ++++++++++------- pyfpdb/Hud.py | 25 +++++++++++------------ pyfpdb/Mucked.py | 50 ++++++++++++++++++---------------------------- 4 files changed, 59 insertions(+), 68 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index edf99cf0..7b376944 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -116,31 +116,30 @@ class Database: row = c.fetchone() return row[0] -# def get_cards(self, hand): -# this version is for the PTrackSv2 db -# c = self.connection.cursor() -# c.execute(self.sql.query['get_cards'], hand) -# colnames = [desc[0] for desc in c.description] -# cards = {} -# for row in c.fetchall(): -# s_dict = {} -# for name, val in zip(colnames, row): -# s_dict[name] = val -# cards[s_dict['seat_number']] = s_dict -# return (cards) - def get_cards(self, hand): -# this version is for the fpdb db + """Get and return the cards for each player in the hand.""" + cards = {} # dict of cards, the key is the seat number example: {1: 'AcQd9hTs5d'} c = self.connection.cursor() c.execute(self.sql.query['get_cards'], hand) colnames = [desc[0] for desc in c.description] - cards = {} for row in c.fetchall(): s_dict = {} for name, val in zip(colnames, row): s_dict[name] = val - cards[s_dict['seat_number']] = s_dict - return (cards) + cards[s_dict['seat_number']] = (self.convert_cards(s_dict)) + return cards + + def convert_cards(self, d): + ranks = ('', '', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A') + cards = "" + for i in range(1, 8): + if d['card' + str(i) + 'Value'] == None: + break + elif d['card' + str(i) + 'Value'] == 0: + cards += "xx" + else: + cards += ranks[d['card' + str(i) + 'Value']] + d['card' +str(i) + 'Suit'] + return cards def get_action_from_hand(self, hand_no): action = [ [], [], [], [], [] ] @@ -214,6 +213,7 @@ if __name__=="__main__": for p in stat_dict.keys(): print p, " ", stat_dict[p] + print "cards =", db_connection.get_cards(73525) db_connection.close_connection print "press enter to continue" diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index a8b800d1..6c31b0e8 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -72,7 +72,7 @@ class HUD_main(object): def destroy(*args): # call back for terminating the main eventloop gtk.main_quit() - def create_HUD(self, new_hand_id, table, table_name, max, poker_game, is_tournament, stat_dict): + def create_HUD(self, new_hand_id, table, table_name, max, poker_game, is_tournament, stat_dict, cards): def idle_func(): @@ -84,18 +84,18 @@ class HUD_main(object): self.hud_dict[table_name] = Hud.Hud(self, table, max, poker_game, self.config, self.db_connection) self.hud_dict[table_name].tablehudlabel = newlabel - self.hud_dict[table_name].create(new_hand_id, self.config, stat_dict) + self.hud_dict[table_name].create(new_hand_id, self.config, stat_dict, cards) for m in self.hud_dict[table_name].aux_windows: m.update_data(new_hand_id, self.db_connection) m.update_gui(new_hand_id) - self.hud_dict[table_name].update(new_hand_id, self.config, stat_dict) + self.hud_dict[table_name].update(new_hand_id, self.config) self.hud_dict[table_name].reposition_windows() return False finally: gtk.gdk.threads_leave() gobject.idle_add(idle_func) - def update_HUD(self, new_hand_id, table_name, config, stat_dict): + def update_HUD(self, new_hand_id, table_name, config): """Update a HUD gui from inside the non-gui read_stdin thread.""" # This is written so that only 1 thread can touch the gui--mainly # for compatibility with Windows. This method dispatches the @@ -103,7 +103,7 @@ class HUD_main(object): def idle_func(): gtk.gdk.threads_enter() try: - self.hud_dict[table_name].update(new_hand_id, config, stat_dict) + self.hud_dict[table_name].update(new_hand_id, config) for m in self.hud_dict[table_name].aux_windows: m.update_gui(new_hand_id) return False @@ -145,6 +145,7 @@ class HUD_main(object): try: (table_name, max, poker_game) = self.db_connection.get_table_name(new_hand_id) stat_dict = self.db_connection.get_stats_from_hand(new_hand_id) + cards = self.db_connection.get_cards(new_hand_id) except: print "skipping ", new_hand_id sys.stderr.write("Database error in hand %d. Skipping.\n" % int(new_hand_id)) @@ -163,9 +164,11 @@ class HUD_main(object): # Update an existing HUD if temp_key in self.hud_dict: + self.hud_dict[temp_key].stat_dict = stat_dict + self.hud_dict[temp_key].cards = cards for aw in self.hud_dict[temp_key].aux_windows: aw.update_data(new_hand_id, self.db_connection) - self.update_HUD(new_hand_id, temp_key, self.config, stat_dict) + self.update_HUD(new_hand_id, temp_key, self.config) # Or create a new HUD else: @@ -175,11 +178,12 @@ class HUD_main(object): tablewindow = Tables.discover_table_by_name(self.config, table_name) if tablewindow == None: +# If no client window is found on the screen, complain and continue if is_tournament: table_name = tour_number + " " + tab_number sys.stderr.write("table name "+table_name+" not found, skipping.\n") else: - self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, is_tournament, stat_dict) + self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, is_tournament, stat_dict, cards) if __name__== "__main__": sys.stderr.write("HUD_main starting\n") diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 17497d90..12df03af 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -228,13 +228,14 @@ class Hud: return self.stat_dict[key]['seat'] sys.stderr.write("Error finding actual seat.\n") - def create(self, hand, config, stat_dict): + def create(self, hand, config, stat_dict, cards): # update this hud, to the stats and players as of "hand" # hand is the hand id of the most recent hand played at this table # # this method also manages the creating and destruction of stat # windows via calls to the Stat_Window class self.stat_dict = stat_dict + self.cards = cards sys.stderr.write("------------------------------------------------------------\nCreating hud from hand %s\n" % hand) adj = self.adj_seats(hand, config) sys.stderr.write("adj = %s\n" % adj) @@ -274,37 +275,35 @@ class Hud: if os.name == "nt": gobject.timeout_add(500, self.update_table_position) - def update(self, hand, config, stat_dict): + def update(self, hand, config): self.hand = hand # this is the last hand, so it is available later - self.stat_dict = stat_dict # so this is available for popups, etc self.update_table_position() - self.stat_dict = stat_dict - for s in stat_dict: + for s in self.stat_dict: try: - self.stat_windows[stat_dict[s]['seat']].player_id = stat_dict[s]['player_id'] + self.stat_windows[self.stat_dict[s]['seat']].player_id = self.stat_dict[s]['player_id'] except: # omg, we have more seats than stat windows .. damn poker sites with incorrect max seating info .. let's force 10 here self.max = 10 - self.create(hand, config) - self.stat_windows[stat_dict[s]['seat']].player_id = stat_dict[s]['player_id'] + self.create(hand, config, self.stat_dict, self.cards) + self.stat_windows[self.stat_dict[s]['seat']].player_id = self.stat_dict[s]['player_id'] for r in range(0, config.supported_games[self.poker_game].rows): for c in range(0, config.supported_games[self.poker_game].cols): this_stat = config.supported_games[self.poker_game].stats[self.stats[r][c]] - number = Stats.do_stat(stat_dict, player = stat_dict[s]['player_id'], stat = self.stats[r][c]) + number = Stats.do_stat(self.stat_dict, player = self.stat_dict[s]['player_id'], stat = self.stats[r][c]) statstring = this_stat.hudprefix + str(number[1]) + this_stat.hudsuffix if this_stat.hudcolor != "": self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor'])) self.stat_windows[stat_dict[s]['seat']].label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(this_stat.hudcolor)) - self.stat_windows[stat_dict[s]['seat']].label[r][c].set_text(statstring) + self.stat_windows[self.stat_dict[s]['seat']].label[r][c].set_text(statstring) if statstring != "xxx": # is there a way to tell if this particular stat window is visible already, or no? - self.stat_windows[stat_dict[s]['seat']].window.show_all() + self.stat_windows[self.stat_dict[s]['seat']].window.show_all() # self.reposition_windows() - tip = stat_dict[s]['screen_name'] + "\n" + number[5] + "\n" + \ + tip = self.stat_dict[s]['screen_name'] + "\n" + number[5] + "\n" + \ number[3] + ", " + number[4] - Stats.do_tip(self.stat_windows[stat_dict[s]['seat']].e_box[r][c], tip) + Stats.do_tip(self.stat_windows[self.stat_dict[s]['seat']].e_box[r][c], tip) def topify_window(self, window): """Set the specified gtk window to stayontop in MS Windows.""" diff --git a/pyfpdb/Mucked.py b/pyfpdb/Mucked.py index 07021c7e..1e550edc 100755 --- a/pyfpdb/Mucked.py +++ b/pyfpdb/Mucked.py @@ -154,7 +154,7 @@ class Stud_list: winners = winners + player pot_dec = "%.2f" % (float(pot)/100) - hero_cards = self.get_hero_cards(self.parent.hero, self.parent.mucked_cards.cards) + hero_cards = self.get_hero_cards(self.parent.hero, self.parent.hud.cards) self.info_row = ((new_hand_id, hero_cards, pot_dec, winners), ) def get_hero_cards(self, hero, cards): @@ -163,11 +163,10 @@ class Stud_list: if hero == '': return "xxxxxx" else: - for k in cards.keys(): - if cards[k]['screen_name'] == hero: - return trans[cards[k]['card1Value']] + cards[k]['card1Suit'] \ - + trans[cards[k]['card2Value']] + cards[k]['card2Suit'] \ - + trans[cards[k]['card3Value']] + cards[k]['card3Suit'] +# find the hero's seat from the stat_dict + for stat in self.parent.hud.stat_dict.itervalues(): + if stat['screen_name'] == hero: + return self.parent.hud.cards[stat['seat']][0:6] return "xxxxxx" def update_gui(self, new_hand_id): @@ -225,25 +224,7 @@ class Stud_cards: self.container.add(self.grid) - def translate_cards(self, old_cards): - ranks = ('', '', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A') - - for c in old_cards.keys(): - for i in range(1, 8): - rank = 'card' + str(i) + 'Value' - suit = 'card' + str(i) + 'Suit' - key = 'hole_card_' + str(i) - if old_cards[c][rank] == 0: - old_cards[c][key] = 'xx' - else: - old_cards[c][key] = ranks[old_cards[c][rank]] + old_cards[c][suit] - return old_cards - def update_data(self, new_hand_id, db_connection): -# db_connection = Database.Database(self.config, 'fpdb', '') - cards = db_connection.get_cards(new_hand_id) - self.cards = self.translate_cards(cards) - self.tips = [] action = db_connection.get_action_from_hand(new_hand_id) for street in action: @@ -261,13 +242,13 @@ class Stud_cards: def update_gui(self, new_hand_id): self.clear() - for c in self.cards.keys(): - self.grid_contents[(1, self.cards[c]['seat_number'] - 1)].set_text(self.cards[c]['screen_name']) - for i in ((0, 'hole_card_1'), (1, 'hole_card_2'), (2, 'hole_card_3'), (3, 'hole_card_4'), - (4, 'hole_card_5'), (5, 'hole_card_6'), (6, 'hole_card_7')): - if not self.cards[c][i[1]] == "xx": - self.seen_cards[(i[0], self.cards[c]['seat_number'] - 1)]. \ - set_from_pixbuf(self.card_images[self.split_cards(self.cards[c][i[1]])]) + for c, cards in self.parent.hud.cards.iteritems(): + self.grid_contents[(1, c - 1)].set_text(self.get_screen_name(c)) + for i in ((0, cards[0:2]), (1, cards[2:4]), (2, cards[4:6]), (3, cards[6:8]), + (4, cards[8:10]), (5, cards[10:12]), (6, cards[12:14])): + if not i[1] == "xx": + self.seen_cards[(i[0], c - 1)]. \ + set_from_pixbuf(self.card_images[self.split_cards(i[1])]) ## action in tool tips for 3rd street cards for c in (0, 1, 2): for r in range(0, self.rows): @@ -279,6 +260,13 @@ class Stud_cards: for r in range(0, self.rows): self.eb[(round_to_col[round], r)].set_tooltip_text(self.tips[round]) + def get_screen_name(self, seat_no): + """Gets and returns the screen name from stat_dict, given seat number.""" + for k in self.parent.hud.stat_dict.keys(): + if self.parent.hud.stat_dict[k]['seat'] == seat_no: + return self.parent.hud.stat_dict[k]['screen_name'] + return "No Name" + def split_cards(self, card): return (card[0], card[1].upper()) From ca57a5a5ff159fa6bb239700df4e95e71ef16258 Mon Sep 17 00:00:00 2001 From: Matt Turnbull Date: Thu, 26 Feb 2009 16:04:08 +0000 Subject: [PATCH 2/6] set -> list --- pyfpdb/EverleafToFpdb.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pyfpdb/EverleafToFpdb.py b/pyfpdb/EverleafToFpdb.py index 4c565d44..fb6ff54d 100755 --- a/pyfpdb/EverleafToFpdb.py +++ b/pyfpdb/EverleafToFpdb.py @@ -177,7 +177,7 @@ class Everleaf(HandHistoryConverter): # "2c, qh" -> set(["2c","qc"]) # Also works with Omaha hands. cards = m.group('CARDS') - cards = set(cards.split(', ')) + cards = cards.split(', ') hand.addHoleCards(cards, m.group('PNAME')) def readAction(self, hand, street): @@ -198,9 +198,10 @@ class Everleaf(HandHistoryConverter): def readShowdownActions(self, hand): + """Reads lines where holecards are reported in a showdown""" for shows in self.re_ShowdownAction.finditer(hand.string): cards = shows.group('CARDS') - cards = set(cards.split(', ')) + cards = cards.split(', ') hand.addShownCards(cards, shows.group('PNAME')) def readCollectPot(self,hand): @@ -208,10 +209,11 @@ class Everleaf(HandHistoryConverter): hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT')) def readShownCards(self,hand): + """Reads lines where hole & board cards are mixed to form a hand (summary lines)""" for m in self.re_CollectPot.finditer(hand.string): if m.group('CARDS') is not None: cards = m.group('CARDS') - cards = set(cards.split(', ')) + cards = cards.split(', ') hand.addShownCards(cards=None, player=m.group('PNAME'), holeandboard=cards) From baefbb5a074d5fa4e8de63859f579def69c7fc0e Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 26 Feb 2009 11:53:31 -0500 Subject: [PATCH 3/6] Cleanup in GuiBulkImport, trivial change to Tables. --- pyfpdb/GuiBulkImport.py | 17 ++++++++++++----- pyfpdb/Tables.py | 6 +++--- 2 files changed, 15 insertions(+), 8 deletions(-) mode change 100644 => 100755 pyfpdb/GuiBulkImport.py diff --git a/pyfpdb/GuiBulkImport.py b/pyfpdb/GuiBulkImport.py old mode 100644 new mode 100755 index 6f06f232..4a6acb8a --- a/pyfpdb/GuiBulkImport.py +++ b/pyfpdb/GuiBulkImport.py @@ -40,9 +40,12 @@ class GuiBulkImport(): self.importer.addImportDirectory(self.path) self.importer.setCallHud(False) starttime = time() - (stored, dups, partial, errs, ttime) = self.importer.runImport() - print 'GuiBulkImport.import_dir done: Stored: %d Duplicates: %d Partial: %d Errors: %d in %s seconds - %d/sec'\ - % (stored, dups, partial, errs, ttime, stored / ttime) + if not self.importer.settings['threads'] > 1: + (stored, dups, partial, errs, ttime) = self.importer.runImport() + print 'GuiBulkImport.import_dir done: Stored: %d Duplicates: %d Partial: %d Errors: %d in %s seconds - %d/sec'\ + % (stored, dups, partial, errs, ttime, stored / ttime) + else: + self.importer.RunImportThreaded() def load_clicked(self, widget, data=None): # get the dir to import from the chooser @@ -73,6 +76,10 @@ class GuiBulkImport(): self.lab_info.set_text("Import finished") + def get_vbox(self): + """returns the vbox of this thread""" + return self.vbox + def __init__(self, db, settings, config): self.db = db # this is an instance of fpdb_db self.settings = settings @@ -115,7 +122,7 @@ class GuiBulkImport(): self.lab_threads = gtk.Label("Number of threads:") self.table.attach(self.lab_threads, 3, 4, 0, 1, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK) self.lab_threads.show() - self.lab_threads.set_sensitive(False) + self.lab_threads.set_sensitive(True) self.lab_threads.set_justify(gtk.JUSTIFY_RIGHT) # spin button - threads @@ -123,7 +130,7 @@ class GuiBulkImport(): self.spin_threads = gtk.SpinButton(adjustment=threads_adj, climb_rate=0.0, digits=0) self.table.attach(self.spin_threads, 4, 5, 0, 1, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK) self.spin_threads.show() - self.spin_threads.set_sensitive(False) + self.spin_threads.set_sensitive(True) # checkbox - fail on error? self.chk_fail = gtk.CheckButton('Fail on error') diff --git a/pyfpdb/Tables.py b/pyfpdb/Tables.py index 6655b7a6..3373a1cb 100755 --- a/pyfpdb/Tables.py +++ b/pyfpdb/Tables.py @@ -390,9 +390,9 @@ if __name__=="__main__": print discover_table_by_name(c, "Ringe") # print discover_tournament_table(c, "118942908", "3") -# tables = discover(c) -# for t in tables.keys(): -# print tables[t] + tables = discover(c) + for t in tables.keys(): + print tables[t] print "press enter to continue" sys.stdin.readline() From af906352fc7cec60270525d466b523c43366a122 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 26 Feb 2009 11:55:51 -0500 Subject: [PATCH 4/6] Minor changes. --- pyfpdb/GuiBulkImport.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfpdb/GuiBulkImport.py b/pyfpdb/GuiBulkImport.py index 4a6acb8a..4a217343 100755 --- a/pyfpdb/GuiBulkImport.py +++ b/pyfpdb/GuiBulkImport.py @@ -122,7 +122,7 @@ class GuiBulkImport(): self.lab_threads = gtk.Label("Number of threads:") self.table.attach(self.lab_threads, 3, 4, 0, 1, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK) self.lab_threads.show() - self.lab_threads.set_sensitive(True) + self.lab_threads.set_sensitive(False) self.lab_threads.set_justify(gtk.JUSTIFY_RIGHT) # spin button - threads @@ -130,7 +130,7 @@ class GuiBulkImport(): self.spin_threads = gtk.SpinButton(adjustment=threads_adj, climb_rate=0.0, digits=0) self.table.attach(self.spin_threads, 4, 5, 0, 1, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK) self.spin_threads.show() - self.spin_threads.set_sensitive(True) + self.spin_threads.set_sensitive(False) # checkbox - fail on error? self.chk_fail = gtk.CheckButton('Fail on error') From e45c42b172aaa185bb84a2063a3eef5b05dde0f2 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 27 Feb 2009 10:36:45 -0500 Subject: [PATCH 5/6] Correct mistaken removal of stderr redirect. --- pyfpdb/HUD_main.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index 6c31b0e8..9d79aafb 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -29,6 +29,11 @@ Main for FreePokerTools HUD. # Standard Library modules import sys + +# redirect the stderr +errorfile = open('HUD-error.txt', 'w', 0) +sys.stderr = errorfile + import os import thread import time From 167ea98b8b0247c3527b360708309ca3bf001b28 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 27 Feb 2009 12:42:49 -0500 Subject: [PATCH 6/6] Eliminate erronious multi huds on same table in some cases. --- pyfpdb/HUD_main.py | 3 ++- pyfpdb/Hud.py | 22 +++++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index 9d79aafb..2084850b 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -87,7 +87,6 @@ class HUD_main(object): self.vb.add(newlabel) newlabel.show() - self.hud_dict[table_name] = Hud.Hud(self, table, max, poker_game, self.config, self.db_connection) self.hud_dict[table_name].tablehudlabel = newlabel self.hud_dict[table_name].create(new_hand_id, self.config, stat_dict, cards) for m in self.hud_dict[table_name].aux_windows: @@ -98,6 +97,8 @@ class HUD_main(object): return False finally: gtk.gdk.threads_leave() + + self.hud_dict[table_name] = Hud.Hud(self, table, max, poker_game, self.config, self.db_connection) gobject.idle_add(idle_func) def update_HUD(self, new_hand_id, table_name, config): diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 0e4b05d6..12f66175 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -48,6 +48,8 @@ import HUD_main class Hud: def __init__(self, parent, table, max, poker_game, config, db_connection): +# __init__ is (now) intended to be called from the stdin thread, so it +# cannot touch the gui self.parent = parent self.table = table self.config = config @@ -57,26 +59,28 @@ class Hud: self.deleted = False self.stacked = True self.site = table.site - self.colors = config.get_default_colors(self.table.site) + self.mw_created = False - self.stat_windows = {} + self.stat_windows = {} self.popup_windows = {} - self.aux_windows = [] + self.aux_windows = [] (font, font_size) = config.get_default_font(self.table.site) + self.colors = config.get_default_colors(self.table.site) + if font == None: font = "Sans" if font_size == None: font_size = "8" - - self.font = pango.FontDescription(font + " " + font_size) - + self.font = pango.FontDescription(font + " " + font_size) # do we need to add some sort of condition here for dealing with a request for a font that doesn't exist? + def create_mw(self): + # Set up a main window for this this instance of the HUD self.main_window = gtk.Window() self.main_window.set_gravity(gtk.gdk.GRAVITY_STATIC) - self.main_window.set_title(table.name + " FPDBHUD") + self.main_window.set_title(self.table.name + " FPDBHUD") self.main_window.destroyhandler = self.main_window.connect("destroy", self.kill_hud) self.main_window.set_decorated(False) self.main_window.set_opacity(self.colors["hudopacity"]) @@ -123,6 +127,7 @@ class Hud: self.ebox.connect_object("button-press-event", self.on_button_press, self.menu) self.main_window.show_all() + self.mw_created = True # TODO: fold all uses of this type of 'topify' code into a single function, if the differences between the versions don't # create adverse effects? @@ -234,6 +239,9 @@ class Hud: # # this method also manages the creating and destruction of stat # windows via calls to the Stat_Window class + if not self.mw_created: + self.create_mw() + self.stat_dict = stat_dict self.cards = cards sys.stderr.write("------------------------------------------------------------\nCreating hud from hand %s\n" % hand)