From 46022509de5e5539638e51e784c861b36c03d6cb Mon Sep 17 00:00:00 2001 From: gimick Date: Sun, 5 Dec 2010 16:59:32 +0000 Subject: [PATCH] pypokereval: fixes to allow py2exe to compile. Also, place win32 dependencies in pyfpdb (pyfpdb files can be deleted when there is a site-package on win) This commit allows fpdb+pypokereval to work on win32 machines without having to manually install pypokereval files --- packaging/windows/py2exe_setup.py | 5 +- packaging/windows/pypoker138walkthrough.txt | 368 ++++++++++---------- pyfpdb/_pokereval_2_6.pyd | Bin 0 -> 143360 bytes pyfpdb/pokereval.py | 338 ++++++++++++++++++ 4 files changed, 533 insertions(+), 178 deletions(-) create mode 100644 pyfpdb/_pokereval_2_6.pyd create mode 100644 pyfpdb/pokereval.py diff --git a/packaging/windows/py2exe_setup.py b/packaging/windows/py2exe_setup.py index 0f46f8db..84b75886 100644 --- a/packaging/windows/py2exe_setup.py +++ b/packaging/windows/py2exe_setup.py @@ -68,7 +68,6 @@ import matplotlib import shutil #from datetime import date - def isSystemDLL(pathname): #dwmapi appears to be vista-specific file, not XP if os.path.basename(pathname).lower() in ("dwmapi.dll"): @@ -120,6 +119,7 @@ pydir = rootdir+'pyfpdb/' gfxdir = rootdir+'gfx/' sys.path.append( pydir ) # allows fpdb modules to be found by options/includes below + print "\n" + r"Output will be created in "+distdir print "*** Cleaning working folders ***" @@ -142,6 +142,9 @@ setup( {'script': pydir+'Configuration.py', } ], + console = [ {'script': pydir+'Stove.py', } + ], + options = {'py2exe': { 'packages' : ['encodings', 'matplotlib'], 'includes' : ['gio', 'cairo', 'pango', 'pangocairo', 'atk', 'gobject' diff --git a/packaging/windows/pypoker138walkthrough.txt b/packaging/windows/pypoker138walkthrough.txt index 6a4ab8f7..1c7ee0f4 100644 --- a/packaging/windows/pypoker138walkthrough.txt +++ b/packaging/windows/pypoker138walkthrough.txt @@ -1,177 +1,191 @@ -pypokereval build for windows stepbystep guide ----------------------------------------------- - -Created by Gimick on 3rd December 2010 - -This walkthrough is derived with the assistance of EricBlade and the build notes -supplied by Loic Dachary http://dachary.org/ - -Content is available under the the GNU Affero General Public License version 3 - - -0. Build environ ----------------- - -We are building against the 2008 runtime because Python 2.6 - has the same dependency (msvcr90.dll version 9.0.21022.8) - -Using winXPhome 32 bit - -1 Visual studio ---------------- - -1.1/ Get the ISO CD from here ... http://www.microsoft.com/express/Downloads/#2008-All - -1.2/ Run and install Visual C++ only, don't bother with the additional packages offered - -This package will run 30 days before registration is needed - -2. Python runtime ------------------ - -2.1/ Install python runtime from here ... - -Python 2.6.5 ... http://www.python.org/ftp/python/2.6.5/python-2.6.5.msi - -3. Source install ------------------ - -3.1/ grab sources from here - -pypoker-eval v138 ... http://download.gna.org/pokersource/sources/pypoker-eval-138.0.tar.gz -poker-eval v138 ... http://download.gna.org/pokersource/sources/poker-eval-138.0.tar.gz - -3.2/ unpack and place the pypoker-eval-138 directory in c:\ -3.2.1/ rename to pypoker-eval - -3.3/ unpack and place the poker-eval-138 directory in c:\ -3.3.1/ rename to poker-eval - -Important: the build will fail with bizarre missing header files if the project is placed - in a directory containing a space character - you have been warned! - -4. Update source file ---------------------- - -4.1/ dos> write c:/pypoker-eval/pypokereval.c - -change this: - -#define VERSION_NAME(W) W##2_4 -#define PYTHON_VERSION "2_4" - -to be this: - -#define VERSION_NAME(W) W##2_6 -#define PYTHON_VERSION "2_6" - -4.2/ save and exit - -5. Build pre-preparation ------------------------- - -(Here we are converting the two project definition files to 2008) - -5.1 navigate to directory c:/poker-eval -5.1.1 double click poker-eval.vcproj -5.1.2 Visual studio will launch and make a conversion - accept all defaults -5.1.3 exit and save - -5.2 navigate to directory c:/pypoker-eval -5.2.1 double click pypoker-eval.vcproj -5.2.2 Visual studio will launch and make a conversion - accept all defaults -5.2.3 exit - -6. build preparation --------------------- - -6.2 navigate to directory c:/pypoker-eval -6.2.1 double click pypoker-eval.vcproj - visual studio should launch - -6.2.3 Select Build...configuration manager... - Select "active solution configuration" to "Release" - (The configuration for both projects will change to "Release") - -6.2.3 Close the configuration manager - -6.2.4 In the solution explorer window, hilight pythonpoker-eval / right mouse / properties... - -6.2.5 In the pythonpoker-eval properties dialog, - -change references to "python24" to "python26" in the following: - - = C/C++/Additional Include Directories/ - = linker/general/Additional library directories - = linker/input/Additional Dependencies - -Change the following - - = linker/generate debug info - set to No - = linker/debugging/Generate debug info - set to No - -6.2.6 Apply all changes to the properties dialog and close - -6.3 Exit from visual studio - -7. Build poker eval -------------------- - -7.1 navigate to directory c:/poker-eval -7.1.1 double click poker-eval.vcproj -7.1.2 Visual studio will launch - -7.2 In the solution explorer window, hilight poker-eval / right mouse / build - -7.3 There should be no errors - -7.4 Exit from visual studio - - -8. Build pypoker eval ---------------------- - -8.1 navigate to directory c:/pypoker-eval -8.1.1 double click pypoker-eval.vcproj -8.1.2 Visual studio will launch - -8.2 In the solution explorer window, hilight pythonpoker-eval / right mouse / build - -8.3 There should be no errors (but a few warnings) - -8.4 Exit from visual studio - -9. packaging ------------- - -9.1 Navigate to c:/pypoker-eval/release -9.2 the output file is pypokereval.dll -9.3 rename this file to _pokereval_2_6.pyd - -9.4 create a zip file containing : - -_pokereval_2_6.pyd from releases -test.py from pypoker-eval-138.0 -pokereval.py from pypoker-eval-138.0 -poker-eval.vcproj from c:\poker-eval -pypoker-eval.vcproj from c:\pypoker-eval -pypokereval.c from c:\pypoker-eval - -Remember to include the version (138), python 265 and win32 in the package filename - -10. Installation and Testing ----------------------------- - -Python 2.6.5 must be installed - -10.1 Extract this package to directory -10.2 Change directory to the directory in 10.1 -10.3 execute dos> c:\Python26\python.exe test.py -10.4 hand-output should scroll down the screen -10.5 start the python interpreter -10.6 >>> import pokereval -10.7 No errors should be seen - - - - - +pypokereval build for windows stepbystep guide +---------------------------------------------- + +Created by Gimick on 3rd December 2010 + +This walkthrough is derived with the assistance of EricBlade and the build notes +supplied by Loic Dachary http://dachary.org/ + +Content is available under the the GNU Affero General Public License version 3 + + +0. Build environ +---------------- + +We are building against the 2008 runtime because Python 2.6 + has the same dependency (msvcr90.dll version 9.0.21022.8) + +Using winXPhome 32 bit + +1 Visual studio +--------------- + +1.1/ Get the ISO CD from here ... http://www.microsoft.com/express/Downloads/#2008-All + +1.2/ Run and install Visual C++ only, don't bother with the additional packages offered + +This package will run 30 days before registration is needed + +2. Python runtime +----------------- + +2.1/ Install python runtime from here ... + +Python 2.6.5 ... http://www.python.org/ftp/python/2.6.5/python-2.6.5.msi + +3. Source install +----------------- + +3.1/ grab sources from here + +pypoker-eval v138 ... http://download.gna.org/pokersource/sources/pypoker-eval-138.0.tar.gz +poker-eval v138 ... http://download.gna.org/pokersource/sources/poker-eval-138.0.tar.gz + +3.2/ unpack and place the pypoker-eval-138 directory in c:\ +3.2.1/ rename to pypoker-eval + +3.3/ unpack and place the poker-eval-138 directory in c:\ +3.3.1/ rename to poker-eval + +Important: the build will fail with bizarre missing header files if the project is placed + in a directory containing a space character - you have been warned! + +4. Update source file +--------------------- + +4.1/ dos> write c:/pypoker-eval/pypokereval.c + +change this: + +#define VERSION_NAME(W) W##2_4 +#define PYTHON_VERSION "2_4" + +to be this: + +#define VERSION_NAME(W) W##2_6 +#define PYTHON_VERSION "2_6" + +4.2/ save and exit + +4.3/ dos> write c:/pypoker-eval/pokereval.py + +Comment-out this line: + +_pokereval = __import__('_pokereval_' + sys.version[0] + '_' + sys.version[2]) + +Insert this one in its' place: + +import _pokereval_2_6 as _pokereval + + +4.4/ save and exit + + +5. Build pre-preparation +------------------------ + +(Here we are converting the two project definition files to 2008) + +5.1 navigate to directory c:/poker-eval +5.1.1 double click poker-eval.vcproj +5.1.2 Visual studio will launch and make a conversion - accept all defaults +5.1.3 exit and save + +5.2 navigate to directory c:/pypoker-eval +5.2.1 double click pypoker-eval.vcproj +5.2.2 Visual studio will launch and make a conversion - accept all defaults +5.2.3 exit + +6. build preparation +-------------------- + +6.2 navigate to directory c:/pypoker-eval +6.2.1 double click pypoker-eval.vcproj - visual studio should launch + +6.2.3 Select Build...configuration manager... + Select "active solution configuration" to "Release" + (The configuration for both projects will change to "Release") + +6.2.3 Close the configuration manager + +6.2.4 In the solution explorer window, hilight pythonpoker-eval / right mouse / properties... + +6.2.5 In the pythonpoker-eval properties dialog, + +change references to "python24" to "python26" in the following: + + = C/C++/Additional Include Directories/ + = linker/general/Additional library directories + = linker/input/Additional Dependencies + +Change the following + + = linker/generate debug info - set to No + = linker/debugging/Generate debug info - set to No + +6.2.6 Apply all changes to the properties dialog and close + +6.3 Exit from visual studio + +7. Build poker eval +------------------- + +7.1 navigate to directory c:/poker-eval +7.1.1 double click poker-eval.vcproj +7.1.2 Visual studio will launch + +7.2 In the solution explorer window, hilight poker-eval / right mouse / build + +7.3 There should be no errors + +7.4 Exit from visual studio + + +8. Build pypoker eval +--------------------- + +8.1 navigate to directory c:/pypoker-eval +8.1.1 double click pypoker-eval.vcproj +8.1.2 Visual studio will launch + +8.2 In the solution explorer window, hilight pythonpoker-eval / right mouse / build + +8.3 There should be no errors (but a few warnings) + +8.4 Exit from visual studio + +9. packaging +------------ + +9.1 Navigate to c:/pypoker-eval/release +9.2 the output file is pypokereval.dll +9.3 rename this file to _pokereval_2_6.pyd + +9.4 create a zip file containing : + +_pokereval_2_6.pyd from releases +test.py from pypoker-eval-138.0 +pokereval.py from pypoker-eval-138.0 +poker-eval.vcproj from c:\poker-eval +pypoker-eval.vcproj from c:\pypoker-eval +pypokereval.c from c:\pypoker-eval + +Remember to include the version (138), python 265 and win32 in the package filename + +10. Installation and Testing +---------------------------- + +Python 2.6.5 must be installed + +10.1 Extract this package to directory +10.2 Change directory to the directory in 10.1 +10.3 execute dos> c:\Python26\python.exe test.py +10.4 hand-output should scroll down the screen +10.5 start the python interpreter +10.6 >>> import pokereval +10.7 No errors should be seen + + + + + diff --git a/pyfpdb/_pokereval_2_6.pyd b/pyfpdb/_pokereval_2_6.pyd new file mode 100644 index 0000000000000000000000000000000000000000..f11d3081e396138da2d9b9bc2aadb69ca1388e57 GIT binary patch literal 143360 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 literal 0 HcmV?d00001 diff --git a/pyfpdb/pokereval.py b/pyfpdb/pokereval.py new file mode 100644 index 00000000..08d08786 --- /dev/null +++ b/pyfpdb/pokereval.py @@ -0,0 +1,338 @@ +# +# Copyright (C) 2007, 2008 Loic Dachary +# Copyright (C) 2004, 2005, 2006 Mekensleep +# +# Mekensleep +# 24 rue vieille du temple +# 75004 Paris +# licensing@mekensleep.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +# +# Authors: +# Loic Dachary +# +# +import sys + +# for fpdb alter the following line from __import__ to import...as... . +# fpdb py2exe package build does no recognise __import__ statement, +# and fails at runtime with _pokereval_2_6 not found + +#_pokereval = __import__('_pokereval_' + sys.version[0] + '_' + sys.version[2]) +import _pokereval_2_6 as _pokereval + +from types import * + +class PokerEval: + """\ +Evaluate the strengh of a poker hand for a given poker variant. +In all methods, when a list of cards is to be provided (for instance +with the "hand" argument of the "best" method), each member of the +list may be a number or a string designating a card according to +the following table: + + 2h/00 2d/13 2c/26 2s/39 + 3h/01 3d/14 3c/27 3s/40 + 4h/02 4d/15 4c/28 4s/41 + 5h/03 5d/16 5c/29 5s/42 + 6h/04 6d/17 6c/30 6s/43 + 7h/05 7d/18 7c/31 7s/44 + 8h/06 8d/19 8c/32 8s/45 + 9h/07 9d/20 9c/33 9s/46 + Th/08 Td/21 Tc/34 Ts/47 + Jh/09 Jd/22 Jc/35 Js/48 + Qh/10 Qd/23 Qc/36 Qs/49 + Kh/11 Kd/24 Kc/37 Ks/50 + Ah/12 Ad/25 Ac/38 As/51 + +The string __ (two underscore) or the number 255 are placeholders +meaning that the card is unknown. +""" + + def best(self, side, hand, board = []): + """\ +Return the best five card combination that can be made with the cards +listed in "hand" and, optionally, board. The "side" may be "hi" or +"low". The "board" argument must only be provided for variants where +knowing if a given card is taken from the board or not is significant +(such as Omaha but not Holdem). + +A list is returned. The first element is the numerical value +of the hand (better hands have higher values if "side" is "hi" and +lower values if "side" is "low"). The second element is a list whose +first element is the strength of the hand among the following: + +Nothing (only if "side" equals "low") +NoPair +TwoPair +Trips +Straight +Flush +FlHouse +Quads +StFlush + +The last five elements are numbers describing the best hand properly +sorted (for instance the ace is at the end for no pair if "side" is low or +at the beginning if "side" high). + +Examples: + +[134414336, ['StFlush', 29, 28, 27, 26, 38]] is the wheel five to ace, clubs +[475920, ['NoPair', 45, 29, 41, 39, 51]] is As, 8s, 5c, 4s, 2s +[268435455, ['Nothing']] means there is no qualifying low +""" + if len(hand + board) >= 5: + return _pokereval.eval_hand(side, hand, board) + else: + return False + + def best_hand(self, side, hand, board = []): + """\ +Return the best five card combination that can be made with the cards +listed in "hand" and, optionaly, board. The "side" may be "hi" or +"low". The returned value is the second element of the list returned +by the "best" method. +""" + if len(hand + board) >= 5: + return _pokereval.eval_hand(side, hand, board)[1] + else: + return False + + def best_hand_value(self, side, hand, board = []): + """\ +Return the best five card combination that can be made with the cards +listed in "hand" and, optionaly, board. The "side" may be "hi" or +"low". The returned value is the first element of the list returned +by the "best" method. +""" + if len(hand + board) >= 5: + return _pokereval.eval_hand(side, hand, board)[0] + else: + return False + + def evaln(self, cards): + """\ +Call the poker-eval Hand_EVAL_N function with the "cards" argument. +Return the strength of the "cards" as a number. The higher the +better. +""" + return _pokereval.evaln(cards) + + def winners(self, *args, **kwargs): + """\ +Return a list of the indexes of the best hands, relative to the "pockets" +keyword argument. For instance, if the first pocket and third pocket cards +tie, the list would be [0, 2]. Since there may be more than one way to +win a hand, a hash is returned with the list of the winners for each so +called side. For instace {'hi': [0], 'low': [1]} means pocket cards +at index 0 won the high side of the hand and pocket cards at index 1 +won the low side. + +See the"poker_eval" method for a detailed +explanation of the semantics of the arguments. + +If the keyword argument "fill_pockets" is set, pocket cards +can contain a placeholder (i.e. 255 or __) that will be be +used as specified in the "poker_eval" method documentation. + +If the keyword argument "fill_pockets" is not set, pocket cards +that contain at least one placeholder (i.e. 255 or __) are +ignored completly. For instance if winners is called as follows +o.winners(game = 'holdem', pockets = [ [ '__', 'As' ], [ 'Ks', 'Kd'] ]) +it is strictly equivalent as calling +o.winners(game = 'holdem', pockets = [ [ 'Ks', 'Kd'] ]). +""" + index2index = {} + normalized_pockets = [] + normalized_index = 0 + pockets = kwargs["pockets"][:] + for index in xrange(len(pockets)): + if not kwargs.has_key("fill_pockets"): + if 255 in pockets[index] or "__" in pockets[index]: + pockets[index] = [] + + if pockets[index] != []: + normalized_pockets.append(pockets[index]) + index2index[index] = normalized_index + normalized_index += 1 + kwargs["pockets"] = normalized_pockets + + results = _pokereval.poker_eval(*args, **kwargs) + + (count, haslopot, hashipot) = results.pop(0) + winners = { 'low': [], 'hi': [] } + for index in xrange(len(pockets)): + if index2index.has_key(index): + result = results[index2index[index]] + if result[1] == 1 or result[3] == 1: + winners["hi"].append(index) + if result[4] == 1 or result[6] == 1: + winners["low"].append(index) + + if not haslopot or len(winners["low"]) == 0: + del winners["low"] + if not hashipot: + del winners["hi"] + return winners + + def poker_eval(self, *args, **kwargs): + """\ +Provided with a description of a poker game, return the outcome (if at showdown) or +the expected value of each hand. The poker game description is provided as a set +of keyword arguments with the following meaning: + +game : the variant (holdem, holdem8, omaha, omaha8, 7stud, 7stud8, razz, + 5draw, 5draw8, 5drawnsq, lowball, lowball27). + Mandatory, no default. + +pockets : list of pocket cards for each player still in game. Each member + of the list is a list of cards. The position of the pocket cards + in the list is meaningfull for the value returned will refer to + this position when stating which player wins, tie or loose. + Example: [ ["tc", "ac"], ["3h", "ah"], ["8c", "6h"]] + Cards do not have to be real cards like "tc" or "4s". They may also be a + placeholder, denoted by "__" or 255. When using placeholders, the + keyword argument "iterations" may be specified to use Monte Carlo instead of + exhaustive exploration of all the possible combinations. + Example2: [ ["tc", "__"], [255, "ah"], ["8c", "6h"]] + + Mandatory, no default. + +board : list of community cards, for games where this is meaningfull. If + specified when irrelevant, the return value cannot be predicted. + Default: [] + +dead : list of dead cards. These cards won't be accounted for when exloring + the possible hands. + Default: [] + +iterations: the maximum number of iterations when exploring the + possible outcome of a given hand. Roughly speaking, each + iteration means to distribute cards that are missing (for + which there are place holders in the board or pockets + keywords arguments, i.e. 255 or __). If the number of + iterations is not specified and there are place holders, + the return value cannot be predicted. + Default: +infinite (i.e. exhaustive exploration) + +Example: object.poker_eval(game = "holdem", + pockets = [ ["tc", "ac"], ["3h", "ah"], ["8c", "6h"]], + dead = [], + board = ["7h", "3s", "2c"]) + +The return value is a map of two entries: +'info' contains three integers: + - the number of samples (which must be equal to the number of iterations given + in argument). + - 1 if the game has a low side, 0 otherwise + - 1 if the game has a high side, 0 otherwise +'eval' is a list of as many maps as there are pocket cards, each +made of the following entries: + 'scoop': the number of time these pocket cards scoop + 'winhi': the number of time these pocket cards win the high side + 'losehi': the number of time these pocket cards lose the high side + 'tiehi': the number of time these pocket cards tie for the high side + 'winlo': the number of time these pocket cards win the low side + 'loselo': the number of time these pocket cards lose the low side + 'tielo': the number of time these pocket cards tie for the low side + 'ev': the EV of these pocket cards as an int in the range [0,1000] with + 1000 being the best. + +It should be clear that if there is only one sample (i.e. because all the +cards are known which is the situation that occurs at showdown) the details +provided by the 'eval' entry is mostly irrelevant and the caller might +prefer to call the winners method instead. +""" + result = _pokereval.poker_eval(*args, **kwargs) + return { + 'info': result[0], + 'eval': [ { 'scoop': x[0], + 'winhi': x[1], + 'losehi': x[2], + 'tiehi': x[3], + 'winlo': x[4], + 'loselo': x[5], + 'tielo': x[6], + 'ev': int(x[7] * 1000) } for x in result[1:] ] + } + + def deck(self): + """\ +Return the list of all cards in the deck. +""" + return [ self.string2card(i + j) for i in "23456789TJQKA" for j in "hdcs" ] + + def nocard(self): + """Return 255, the numerical value of a place holder in a list of cards.""" + return 255 + + def string2card(self, cards): + """\ +Convert card names (strings) to card numbers (integers) according to the +following map: + + 2h/00 2d/13 2c/26 2s/39 + 3h/01 3d/14 3c/27 3s/40 + 4h/02 4d/15 4c/28 4s/41 + 5h/03 5d/16 5c/29 5s/42 + 6h/04 6d/17 6c/30 6s/43 + 7h/05 7d/18 7c/31 7s/44 + 8h/06 8d/19 8c/32 8s/45 + 9h/07 9d/20 9c/33 9s/46 + Th/08 Td/21 Tc/34 Ts/47 + Jh/09 Jd/22 Jc/35 Js/48 + Qh/10 Qd/23 Qc/36 Qs/49 + Kh/11 Kd/24 Kc/37 Ks/50 + Ah/12 Ad/25 Ac/38 As/51 + +The "cards" argument may be either a list in which case a converted list +is returned or a string in which case the corresponding number is +returned. +""" + if type(cards) is ListType or type(cards) is TupleType: + return [ _pokereval.string2card(card) for card in cards ] + else: + return _pokereval.string2card(cards) + + def card2string(self, cards): + """\ +Convert card numbers (integers) to card names (strings) according to the +following map: + + 2h/00 2d/13 2c/26 2s/39 + 3h/01 3d/14 3c/27 3s/40 + 4h/02 4d/15 4c/28 4s/41 + 5h/03 5d/16 5c/29 5s/42 + 6h/04 6d/17 6c/30 6s/43 + 7h/05 7d/18 7c/31 7s/44 + 8h/06 8d/19 8c/32 8s/45 + 9h/07 9d/20 9c/33 9s/46 + Th/08 Td/21 Tc/34 Ts/47 + Jh/09 Jd/22 Jc/35 Js/48 + Qh/10 Qd/23 Qc/36 Qs/49 + Kh/11 Kd/24 Kc/37 Ks/50 + Ah/12 Ad/25 Ac/38 As/51 + +The "cards" argument may be either a list in which case a converted list +is returned or an integer in which case the corresponding string is +returned. +""" + if type(cards) is ListType or type(cards) is TupleType: + return [ _pokereval.card2string(card) for card in cards ] + else: + return _pokereval.card2string(cards) +