Attached is a patch that I believe will close sr #2208 when applied to
trunk, which I hope to do tomorrow morning (US/Eastern).

There's more I want to do in pokerservice.py.  I've talked to Loic about
storing the payouts as they went down in the database, since we can't be
sure that a change in the algorithm/table hasn't occured since the
tourney ran.

However, that should be a separate patch.  If there are no objections
tomorrow morning when I get online, I'll merge this from r5187 on
/branches/poker-prizes into trunk.

This patch is copyrighted by me and licensed GPLv3-or-later.

diff --git a/poker-engine/ChangeLog b/poker-engine/ChangeLog
index 5a149ea..d327add 100644
--- a/poker-engine/ChangeLog
+++ b/poker-engine/ChangeLog
@@ -1,3 +1,61 @@
+2008-12-07  Bradley M. Kuhn  <[EMAIL PROTECTED]>
+
+	* pokerengine/Makefile.am (pokerengine_PYTHON): Added
+	pokerprizes.py
+
+	* tests/tournament.py.in (TestPrizes.test1): Adapted test.
+
+	* tests/Makefile.am (EXTRA_DIST): added testmessages.py
+
+	* tests/test-pokertournament.py.in
+	(PokerTournamentTestCase.testPrizes): Adjusted test.
+	(PokerTournamentTestCase.testPrizesAlgorithm): Adjusted test.
+	(PokerTournamentTestCase.testPrizesTable): Adjusted test.
+
+	* tests/test-pokerprizes.py.in
+	(PokerPrizesTestCase.test01_algorithmPrizeInterface): Added test
+	to cover removePlayer().
+	(PokerPrizesTestCase.test02_tablePrizeInterface): Added test to
+	cover removePlayer().
+
+	* pokerengine/pokerprizes.py (PokerPrizes.removePlayer): Wrote method.
+
+	* pokerengine/pokertournament.py (PokerTournament.prizes): Adapted
+	to use self.perize_object.prizes()
+	(PokerTournament.register): Added called to prizes_object.addPlayer()
+	(PokerTournament.unregister): Added called to prizes_object.removePlayer()
+
+	* pokerengine/pokerprizes.py (PokerPrizes.__init__): Added
+	dummy configDirs argument to simplify code in pokertournament.loadPayouts()
+
+	* pokerengine/pokertournament.py
+	(PokerTournament.prizesAlgorithm, PokerTournament.prizesTable):
+	Removed methods.
+	(PokerTournament.loadPayouts): Switched to use PokerPrizesFactory()
+
+	* tests/test-pokerprizes.py.in (PokerPrizesTestCase.tearDown):
+	Added method.
+	(PokerPrizesTestCase.setUp): Added method.
+	(PokerPrizesTestCase.test00_factory): Wrote test.
+
+	* configure.ac (AC_CONFIG_FILES): Added tests/test-pokerprizes.py.
+
+2008-12-06  Bradley M. Kuhn  <[EMAIL PROTECTED]>
+
+	* pokerengine/pokerprizes.py (PokerPrizesFactory): Created class.
+	(PokerPrizes): Created class.
+	(PokerPrizesAlgorithm): Created class, using
+	pokertournament.prizesAlgorithm() as getPrizes()
+	(PokerPrizesTable): Created class, using
+	pokertournament.prizesTable() as getPrizes()
+
+	* tests/test-pokerprizes.py.in (PokerPrizesTestCase): Created
+	class.
+	(PokerPrizesTestCase.test01_algorithmPrizeInterface): Adapted from
+	PokerTournamentTestCase.testPrizesAlgorithm
+	(PokerPrizesTestCase.test02_tablePrizeInterface): Adapted from
+	PokerTournamentTestCase.testPrizesTable
+
 2008-11-28  Loic Dachary <[EMAIL PROTECTED]>
 
 	* Release 1.3.1
diff --git a/poker-engine/configure.ac b/poker-engine/configure.ac
index 8e7e8d3..d12ff81 100644
--- a/poker-engine/configure.ac
+++ b/poker-engine/configure.ac
@@ -96,6 +96,7 @@ AC_CONFIG_FILES([Makefile
                  tests/test-pokercards.py
                  tests/test-pokerengineconfig.py
                  tests/test-pokertournament.py
+                 tests/test-pokerprizes.py
                  tests/test-game.py
                  tests/test-pokerchips.py
                  tests/test-pokerrake.py
diff --git a/poker-engine/pokerengine/Makefile.am b/poker-engine/pokerengine/Makefile.am
index 666cf95..7f3f8de 100644
--- a/poker-engine/pokerengine/Makefile.am
+++ b/poker-engine/pokerengine/Makefile.am
@@ -34,5 +34,6 @@ pokerengine_PYTHON = \
 	pokerengineconfig.py \
 	pokergame.py \
 	pokerrake.py \
+	pokerprizes.py \
 	pokertournament.py \
 	version.py
diff --git a/poker-engine/pokerengine/pokerprizes.py b/poker-engine/pokerengine/pokerprizes.py
new file mode 100644
index 0000000..9e849dd
--- /dev/null
+++ b/poker-engine/pokerengine/pokerprizes.py
@@ -0,0 +1,147 @@
+#
+# Copyright (C)             2008 Bradley M. Kuhn <[EMAIL PROTECTED]>
+# Copyright (C) 2006, 2007, 2008 Loic Dachary <[EMAIL PROTECTED]>
+# Copyright (C) 2004, 2005, 2006 Mekensleep <[EMAIL PROTECTED]>
+#                                24 rue vieille du temple, 75004 Paris
+#
+# 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:
+#  Bradley M. Kuhn <[EMAIL PROTECTED]>
+#  Loic Dachary <[EMAIL PROTECTED]>
+#
+from pokerengine.pokerengineconfig import Config
+############################################################################
+class PokerPrizesFactory:
+    """PokerPrizes is designed to handle payout strcutres for poker
+    tournaments.  The Factory is used to generate different types of
+    payout structure builds.
+
+    The public interface usage looks something like this:
+    
+        prizes = pokerprizes.PokerPrizeFactory("Type")(buyInAmount = 100, playerCount = 5)
+        prizes.addPlayer()
+        prizeArray = prizes.getPrizes() 
+        # returns an list where index+1 st place gets the price, prizeArray[index]"""
+
+    def __init__(self, moduleStr = 'pokerprizes', classPrefix = "PokerPrizes", defaultClass = "PokerPrizesAlgorithm"):
+        self.moduleStr = moduleStr
+        self.classPrefix = classPrefix
+        self.defaultClass = defaultClass
+    # ----------------------------------------------------------------------
+    def error(self, string):
+        self.message("ERROR " + string)
+    # ----------------------------------------------------------------------
+    def message(self, string):
+        print string
+    # ----------------------------------------------------------------------
+    def getClass(self, classname):
+        classname = self.classPrefix + classname
+        try:
+            return getattr(__import__(self.moduleStr, globals(), locals(), [classname]), classname)
+        except AttributeError, ae:
+            self.error(ae.__str__())
+        classname = self.defaultClass
+        return getattr(__import__(self.moduleStr, globals(), locals(), [classname]), classname)
+############################################################################
+class PokerPrizes:
+    """PokerPrizesVirtual base class for PokerPrizes"""
+    def __init__(self, buyInAmount, playerCount = 0, guaranteeAmount = 0, configDirs = None):
+        self.buy_in = buyInAmount
+        self.player_count = playerCount
+        self.guarantee_amount = guaranteeAmount
+    # ----------------------------------------------------------------------
+    def error(self, string):
+        self.message("ERROR " + string)
+    # ----------------------------------------------------------------------
+    def message(self, string):
+        print "[PokerPrizes] " + string
+    # ----------------------------------------------------------------------
+    def addPlayer(self):
+        self.player_count += 1
+    # ----------------------------------------------------------------------
+    def removePlayer(self):
+        self.player_count -= 1
+    # ----------------------------------------------------------------------
+    def getPrizes(self):
+        errStr = "getPrizes NOT IMPLEMENTED IN ABSTRACT BASE CLASS"
+        self.error(errStr)
+        raise NotImplementedError(errStr)
+############################################################################
+class PokerPrizesAlgorithm(PokerPrizes):
+    def getPrizes(self):
+        buy_in = self.buy_in
+        candidates_count = self.player_count 
+        if candidates_count < 5:
+            winners = 1
+        elif candidates_count < 10:
+            winners = 2
+        elif candidates_count < 20:
+            winners = 3
+        elif candidates_count < 30:
+            winners = 4
+        elif candidates_count < 40:
+            winners = 6
+        elif candidates_count < 50:
+            winners = int(candidates_count * 0.2)
+        elif candidates_count < 200:
+            winners = int(candidates_count * 0.15)
+        else:
+            winners = int(candidates_count * 0.1)
+
+        prizes = []
+        prize_pool = max(self.guarantee_amount, buy_in * candidates_count)
+        money_left = prize_pool
+        while winners > 0:
+            if money_left / winners < max(1, prize_pool / 100, int(buy_in * 2.5)):
+                prizes.extend([ money_left / winners ] * winners)
+                winners = 0
+            else:
+                money_left /= 2
+                winners -= 1
+                prizes.append(money_left)
+        rest = prize_pool - sum(prizes)
+        prizes[0] += rest
+        return prizes
+############################################################################
+class PokerPrizesTable(PokerPrizes):
+    def __init__(self, buyInAmount, playerCount = 0, guaranteeAmount = 0, configDirs = ['.'],
+                 configFileName = "poker.payouts.xml"):
+        self._loadPayouts(configDirs)
+
+        PokerPrizes.__init__(self, buyInAmount = buyInAmount, playerCount = playerCount,
+                             guaranteeAmount = guaranteeAmount)
+    # ----------------------------------------------------------------------
+    def _loadPayouts(self, dirs):
+        config = Config(dirs)
+        config.load("poker.payouts.xml")
+        self.payouts = []
+        for node in config.header.xpathEval("/payouts/payout"):
+            properties = config.headerNodeProperties(node)
+            self.payouts.append(( int(properties['max']), map(lambda percent: float(percent) / 100, node.content.split())))
+    # ----------------------------------------------------------------------
+    def getPrizes(self):
+        buy_in = self.buy_in
+        for ( maximum, payouts ) in self.payouts:
+            if self.player_count <= maximum:
+                break
+
+        total = max(self.guarantee_amount, self.player_count * buy_in)
+        prizes = map(lambda percent: int(total * percent), payouts)
+        #
+        # What's left because of rounding errors goes to the tournament winner
+        #
+        prizes[0] += total - sum(prizes)
+        return prizes
diff --git a/poker-engine/pokerengine/pokertournament.py b/poker-engine/pokerengine/pokertournament.py
index 2e00640..de2fef9 100644
--- a/poker-engine/pokerengine/pokertournament.py
+++ b/poker-engine/pokerengine/pokertournament.py
@@ -1,11 +1,8 @@
 #
 # Copyright (C) 2006, 2007, 2008 Loic Dachary <[EMAIL PROTECTED]>
-# Copyright (C) 2004, 2005, 2006 Mekensleep
-#
-# Mekensleep
-# 24 rue vieille du temple
-# 75004 Paris
-#       [EMAIL PROTECTED]
+# Copyright (C)             2008 Bradley M. Kuhn <[EMAIL PROTECTED]>
+# Copyright (C) 2004, 2005, 2006 Mekensleep <[EMAIL PROTECTED]>
+#                                24 rue vieille du temple, 75004 Paris
 #
 # 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
@@ -35,7 +32,7 @@ def tournament_seconds():
 shuffler = random
 
 from pokerengine.pokergame import PokerGameServer
-from pokerengine.pokerengineconfig import Config
+from pokerengine.pokerprizes import PokerPrizesFactory
 
 TOURNAMENT_STATE_ANNOUNCED = "announced"
 TOURNAMENT_STATE_REGISTERING = "registering"
@@ -226,12 +223,7 @@ class PokerTournament:
         self.updateRegistering()
 
     def loadPayouts(self):
-        config = Config(self.dirs)
-        config.load("poker.payouts.xml")
-        self.payouts = []
-        for node in config.header.xpathEval("/payouts/payout"):
-            properties = config.headerNodeProperties(node)
-            self.payouts.append(( int(properties['max']), map(lambda percent: float(percent) / 100, node.content.split())))
+        self.prizes_object =  PokerPrizesFactory().getClass(self.prizes_specs.capitalize())(buyInAmount = self.buy_in, playerCount = self.registered, configDirs = self.dirs)
 
     def message(self, message):
         print self.prefix + "[PokerTournament %s] " % self.name + message
@@ -366,6 +358,7 @@ class PokerTournament:
         if self.can_register:
             self.players.append(serial)
             self.registered += 1
+            self.prizes_object.addPlayer()
             if self.state == TOURNAMENT_STATE_REGISTERING:
                 self.updateRunning()
             elif self.state == TOURNAMENT_STATE_RUNNING:
@@ -378,6 +371,7 @@ class PokerTournament:
         if self.state == TOURNAMENT_STATE_REGISTERING:
             self.players.remove(serial)
             self.registered -= 1
+            self.prizes_object.removePlayer()
             return True
         else:
             return False
@@ -511,60 +505,12 @@ class PokerTournament:
         return len(to_equalize) > 0
 
     def prizes(self):
+        # FIXME?: I left this test for self.can_register because it was
+        # here before PokerPrizes() class existed, but it is not clear to
+        # me that it should still be here.  I have made the tests cover it
+        # though.  -- bkuhn, 2008-12-07
         if self.can_register:
             return None
         if not self.rank2prize:
-            if self.prizes_specs == "algorithm":
-                self.rank2prize = self.prizesAlgorithm()
-            elif self.prizes_specs == "table":
-                self.rank2prize = self.prizesTable()
+            self.rank2prize = self.prizes_object.getPrizes()
         return self.rank2prize
-
-    def prizesAlgorithm(self):
-        buy_in = self.buy_in
-        candidates_count = self.registered
-        if candidates_count < 5:
-            winners = 1
-        elif candidates_count < 10:
-            winners = 2
-        elif candidates_count < 20:
-            winners = 3
-        elif candidates_count < 30:
-            winners = 4
-        elif candidates_count < 40:
-            winners = 6
-        elif candidates_count < 50:
-            winners = int(candidates_count * 0.2)
-        elif candidates_count < 200:
-            winners = int(candidates_count * 0.15)
-        else:
-            winners = int(candidates_count * 0.1)
-
-        prizes = []
-        prize_pool = max(self.prize_min, buy_in * candidates_count)
-        money_left = prize_pool
-        while winners > 0:
-            if money_left / winners < max(1, prize_pool / 100, int(buy_in * 2.5)):
-                prizes.extend([ money_left / winners ] * winners)
-                winners = 0
-            else:
-                money_left /= 2
-                winners -= 1
-                prizes.append(money_left)
-        rest = prize_pool - sum(prizes)
-        prizes[0] += rest
-        return prizes
-                
-    def prizesTable(self):
-        buy_in = self.buy_in
-        for ( maximum, payouts ) in self.payouts:
-            if self.registered <= maximum:
-                break
-
-        total = max(self.prize_min, self.registered * buy_in)
-        prizes = map(lambda percent: int(total * percent), payouts)
-        #
-        # What's left because of rounding errors goes to the tournament winner
-        #
-        prizes[0] += total - sum(prizes)
-        return prizes
diff --git a/poker-engine/tests/Makefile.am b/poker-engine/tests/Makefile.am
index 3dd412b..fc5af18 100644
--- a/poker-engine/tests/Makefile.am
+++ b/poker-engine/tests/Makefile.am
@@ -30,6 +30,7 @@ export PYTHON
 
 EXTRA_DIST = \
 	coverage.py \
+	testmessages.py \
 	test-data/pokerrake.py \
 	bugs.py \
 	$(wildcard conf/*.xml) \
diff --git a/poker-engine/tests/test-pokerprizes.py.in b/poker-engine/tests/test-pokerprizes.py.in
new file mode 100644
index 0000000..9f6902d
--- /dev/null
+++ b/poker-engine/tests/test-pokerprizes.py.in
@@ -0,0 +1,203 @@
+# -*- mode: python -*-
+# Copyright (C)             2008 Bradley M. Kuhn <[EMAIL PROTECTED]>
+# Copyright (C) 2006, 2007, 2008 Loic Dachary <[EMAIL PROTECTED]>
+# Copyright (C) 2006             Mekensleep <[EMAIL PROTECTED]>
+#                                24 rue vieille du temple, 75004 Paris
+#
+# 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:
+#  Bradley M. Kuhn <[EMAIL PROTECTED]>
+#  Pierre-Andre (05/2006)
+#  Loic Dachary <[EMAIL PROTECTED]>
+#
+
+import sys, os
+sys.path.insert(0, "@top_srcdir@")
+
+import unittest
+import os.path
+import types
+import time
+
+from testmessages import restore_all_messages, silence_all_messages, search_output, clear_all_messages, get_messages
+from pokerengine import pokerprizes
+
+class PokerPrizesTestCase(unittest.TestCase):
+    TestConfDirectory = '@top_srcdir@/conf'
+        
+    # ---------------------------------------------------------
+    def setUp(self):
+        silence_all_messages()
+        self.dirs = ['.', PokerPrizesTestCase.TestConfDirectory, '~/conf']
+    
+    # -------------------------------------------------------
+    def tearDown(self):
+        pass
+    # -------------------------------------------------------------------------
+    def test00_factory(self):
+        """test00_factory
+        basic factory interface tests."""
+        f = pokerprizes.PokerPrizesFactory()
+        clear_all_messages()
+        f.error("test")
+        self.assertEquals(get_messages(), ['ERROR test'])
+
+        self.failUnless(f.getClass(""), pokerprizes.PokerPrizesAlgorithm)
+
+        clear_all_messages()
+        self.assertEquals(f.getClass("DOESNOTEXIST"), pokerprizes.PokerPrizesAlgorithm)
+        self.assertEquals(get_messages(), ["ERROR 'module' object has no attribute 'PokerPrizesDOESNOTEXIST'"])
+    # -------------------------------------------------------
+    def test01_algorithmPrizeInterface(self):
+        """test01_algorithmPrizeInterface
+        Test the payout structure of the Algorithm prize interface"""
+        pa = pokerprizes.PokerPrizesFactory().getClass("Algorithm")(buyInAmount = 100, playerCount = 4)
+        self.assertEquals(pa.buy_in, 100)
+        self.assertEquals(pa.player_count, 4)
+
+        self.failUnlessEqual(pa.getPrizes(), [400])
+        
+        for cnt in range(5, 9):
+            pa.addPlayer()
+            self.failUnlessEqual(pa.player_count, cnt)
+            if cnt == 5:
+                pa.removePlayer()
+                self.assertEquals(pa.player_count, 4)
+                self.failUnlessEqual(pa.getPrizes(), [400])
+                pa.addPlayer()
+                self.assertEquals(pa.player_count, cnt) 
+                self.failUnlessEqual(pa.getPrizes(), [375, 125])
+
+        self.failUnlessEqual(pa.getPrizes(), [600, 200])
+
+        for cnt in range(9, 19):
+            pa.addPlayer()
+            self.failUnlessEqual(pa.player_count, cnt)
+        self.failUnlessEqual(pa.getPrizes(), [1125, 450, 225])
+        
+        for cnt in range(19, 29):
+            pa.addPlayer()
+            self.failUnlessEqual(pa.player_count, cnt)
+
+        self.failUnlessEqual(pa.getPrizes(), [1575, 700, 350, 175])
+        
+        for cnt in range(29, 39):
+            pa.addPlayer()
+            self.failUnlessEqual(pa.player_count, cnt)
+
+        self.failUnlessEqual(pa.getPrizes(), [1902, 950, 237, 237, 237, 237])
+        
+        for cnt in range(39, 49):
+            pa.addPlayer()
+            self.failUnlessEqual(pa.player_count, cnt)
+
+        self.failUnlessEqual(len(pa.getPrizes()), int(48 * 0.20))
+        
+        for cnt in range(49, 199):
+            pa.addPlayer()
+            self.failUnlessEqual(pa.player_count, cnt)
+
+        self.failUnlessEqual(len(pa.getPrizes()), int(198 * 0.15))
+        
+        for cnt in range(199, 299):
+            pa.addPlayer()
+            self.failUnlessEqual(pa.player_count, cnt)
+
+        self.failUnlessEqual(len(pa.getPrizes()), int(298 * 0.10))
+    # -------------------------------------------------------
+    def test02_tablePrizeInterface(self):
+        """test02_tablePrizeInterface
+        Test the payout structure of the table prize interface"""
+        pt = pokerprizes.PokerPrizesFactory().getClass("Table")(buyInAmount = 100, playerCount = 2, configDirs = self.dirs)
+        self.assertEquals(pt.buy_in, 100)
+        self.assertEquals(pt.player_count, 2)
+
+        self.failUnlessEqual(pt.getPrizes(), [200])
+        
+        for player in range(4, 7):
+            pt.addPlayer()
+            if player == 4:
+                pt.removePlayer()
+                self.assertEquals(pt.player_count, 2)
+                self.failUnlessEqual(pt.getPrizes(), [200])
+                pt.addPlayer()
+                self.assertEquals(pt.player_count, 3)
+                self.failUnlessEqual(pt.getPrizes(), [300])
+
+        self.failUnlessEqual(pt.getPrizes(), [350, 150])
+        
+        for player in range(7, 28):
+            pt.addPlayer()
+        self.failUnlessEqual(pt.getPrizes(), [1300, 780, 520])
+        
+        for player in range(28, 48):
+            pt.addPlayer()
+        self.failUnlessEqual(pt.getPrizes(), [1840, 1104, 736, 552, 368])
+        
+        for player in range(48, 198):
+            pt.addPlayer()
+        self.failUnlessEqual(pt.getPrizes(), [5880, 3920, 2450, 1764, 1568, 1274, 980, 784, 588, 392])
+        
+        for player in range(198, 298):
+            pt.addPlayer()
+        self.failUnlessEqual(len(pt.getPrizes()), 20)
+    # -------------------------------------------------------
+    def test03_virtualBaseClass(self):
+        """test03_virtualBaseClass
+        Test minor things not elsewhere covered for the base class"""
+        v = pokerprizes.PokerPrizes(5, playerCount = 3, guaranteeAmount = 100)
+        self.assertEquals(v.buy_in, 5)
+        self.assertEquals(v.player_count, 3)
+        self.assertEquals(v.guarantee_amount, 100)
+
+        clear_all_messages()
+        v.error("test")
+        self.assertEquals(get_messages(), ['ERROR test'])
+
+        clear_all_messages()
+        exceptCaught = False
+        try:
+            v.getPrizes()
+            self.failIf(True) # should not reach here
+        except NotImplementedError, nie:
+            exceptCaught = True
+            self.assertEquals(nie.__str__(), 'getPrizes NOT IMPLEMENTED IN ABSTRACT BASE CLASS')
+        self.failUnless(exceptCaught)
+        self.assertEquals(get_messages(), ['ERROR getPrizes NOT IMPLEMENTED IN ABSTRACT BASE CLASS'])
+# ---------------------------------------------------------
+def GetTestSuite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(PokerPrizesTestCase))
+    # Comment out above and use line below this when you wish to run just
+    # one test by itself (changing prefix as needed).
+#    suite.addTest(unittest.makeSuite(Breaks, prefix = "test2"))
+    return suite
+    
+# ---------------------------------------------------------
+def Run(verbose):
+    return unittest.TextTestRunner(verbosity=verbose).run(GetTestSuite())
+    
+# ---------------------------------------------------------
+if __name__ == '__main__':
+    if Run(int(os.environ.get('VERBOSE_T', 2))).wasSuccessful():
+        sys.exit(0)
+    else:
+        sys.exit(1)
+
+# Interpreted by emacs
+# Local Variables:
+# compile-command: "( cd .. ; ./config.status tests/test-pokerprizes.py ) ; ( cd ../tests ; make COVERAGE_FILES='../pokerengine/pokerprizes.py' TESTS='coverage-reset test-pokerprizes.py coverage-report' check )"
+# End:
diff --git a/poker-engine/tests/test-pokertournament.py.in b/poker-engine/tests/test-pokertournament.py.in
index e9703fc..caed381 100644
--- a/poker-engine/tests/test-pokertournament.py.in
+++ b/poker-engine/tests/test-pokertournament.py.in
@@ -38,7 +38,10 @@ class ConstantPlayerShuffler:
     def shuffle(self, what):
         what.sort()
 
+from testmessages import restore_all_messages, silence_all_messages, search_output, clear_all_messages, get_messages
+
 from pokerengine import pokertournament
+from pokerengine.pokerprizes import PokerPrizesTable, PokerPrizesAlgorithm
 pokertournament.shuffler = ConstantPlayerShuffler()
 
 class PokerTournamentTestCase(unittest.TestCase):
@@ -113,7 +116,7 @@ class PokerTournamentTestCase(unittest.TestCase):
                             'rebuy_delay' : 30, \
                             'add_on' : 10, \
                             'add_on_delay' : 120, \
-                            'prizes_specs' : 'prizes', \
+                            'prizes_specs' : 'table', \
                             }                                
             
         tournament = pokertournament.PokerTournament(**arguments)
@@ -354,43 +357,77 @@ class PokerTournamentTestCase(unittest.TestCase):
                             'buy_in' : 100, \
                             'players_quota' :  300, \
                             'seats_per_game' : 2, \
-                            'verbose' : int(os.environ.get('VERBOSE_T', 3))
+                            'verbose' : int(os.environ.get('VERBOSE_T', 3)), \
+                            'prizes_specs' : 'algorithm'
                             }
-                            
         tournament = pokertournament.PokerTournament(**arguments)
+
+        self.assertEquals(tournament.prizes(), None)
+        tournament.can_register = True
         
         for player in range(4):
             self.failUnless(tournament.register(player))
-        self.failUnlessEqual(tournament.prizesAlgorithm(), [400])
+        self.assertEquals(tournament.prizes(), None)
+        tournament.can_register = False
+        tournament.rank2prize = None
+        self.failUnlessEqual(tournament.prizes(), [400])
+        tournament.can_register = True
         
         for player in range(4, 8):
             self.failUnless(tournament.register(player))
-        self.failUnlessEqual(tournament.prizesAlgorithm(), [600, 200])
+        self.assertEquals(tournament.prizes(), None)
+        tournament.can_register = False
+        tournament.rank2prize = None
+        self.failUnlessEqual(tournament.prizes(), [600, 200])
+        tournament.can_register = True
         
         for player in range(8, 18):
             self.failUnless(tournament.register(player))
-        self.failUnlessEqual(tournament.prizesAlgorithm(), [1125, 450, 225])
+        self.assertEquals(tournament.prizes(), None)
+        tournament.can_register = False
+        tournament.rank2prize = None
+        self.failUnlessEqual(tournament.prizes(), [1125, 450, 225])
+        tournament.can_register = True
         
         for player in range(18, 28):
             self.failUnless(tournament.register(player))
-        self.failUnlessEqual(tournament.prizesAlgorithm(), [1575, 700, 350, 175])
+        self.assertEquals(tournament.prizes(), None)
+        tournament.can_register = False
+        tournament.rank2prize = None
+        self.failUnlessEqual(tournament.prizes(), [1575, 700, 350, 175])
+        tournament.can_register = True
         
         for player in range(28, 38):
             self.failUnless(tournament.register(player))
-        self.failUnlessEqual(tournament.prizesAlgorithm(), [1902, 950, 237, 237, 237, 237])
+        self.assertEquals(tournament.prizes(), None)
+        tournament.can_register = False
+        tournament.rank2prize = None
+        self.failUnlessEqual(tournament.prizes(), [1902, 950, 237, 237, 237, 237])
+        tournament.can_register = True
         
         for player in range(38, 48):
             self.failUnless(tournament.register(player))
-        self.failUnlessEqual(len(tournament.prizesAlgorithm()), int(48 * 0.20))
+        self.assertEquals(tournament.prizes(), None)
+        tournament.can_register = False
+        tournament.rank2prize = None
+        self.failUnlessEqual(len(tournament.prizes()), int(48 * 0.20))
+        tournament.can_register = True
         
         for player in range(48, 198):
             self.failUnless(tournament.register(player))
-        self.failUnlessEqual(len(tournament.prizesAlgorithm()), int(198 * 0.15))
+        self.assertEquals(tournament.prizes(), None)
+        tournament.can_register = False
+        tournament.rank2prize = None
+        self.failUnlessEqual(len(tournament.prizes()), int(198 * 0.15))
+        tournament.can_register = True
         
         for player in range(198, 298):
             self.failUnless(tournament.register(player))
-        self.failUnlessEqual(len(tournament.prizesAlgorithm()), int(298 * 0.10))
-        
+        self.assertEquals(tournament.prizes(), None)
+        tournament.can_register = False
+        tournament.rank2prize = None
+        self.failUnlessEqual(len(tournament.prizes()), int(298 * 0.10))
+        tournament.can_register = True
     # -------------------------------------------------------
     def testPrizesTable(self):
         """Test Poker Tournament : Prizes table"""
@@ -400,35 +437,58 @@ class PokerTournamentTestCase(unittest.TestCase):
                             'buy_in' : 100, \
                             'players_quota' :  300, \
                             'seats_per_game' : 2, \
+                            'prizes_specs' : 'table', \
                             'verbose' : int(os.environ.get('VERBOSE_T', 3))
                             }
-                            
         tournament = pokertournament.PokerTournament(**arguments)
-        
+
         for player in range(2):
             self.failUnless(tournament.register(player))
-        self.failUnlessEqual(tournament.prizesTable(), [200])
+        self.assertEquals(tournament.prizes(), None)
+        tournament.can_register = False
+        tournament.rank2prize = None
+        self.failUnlessEqual(tournament.prizes(), [200])
+        tournament.can_register = True
         
         for player in range(4, 7):
             self.failUnless(tournament.register(player))
-        self.failUnlessEqual(tournament.prizesTable(), [350, 150])
+        self.assertEquals(tournament.prizes(), None)
+        tournament.can_register = False
+        tournament.rank2prize = None
+        self.failUnlessEqual(tournament.prizes(), [350, 150])
+        tournament.can_register = True
         
         for player in range(7, 28):
             self.failUnless(tournament.register(player))
-        self.failUnlessEqual(tournament.prizesTable(), [1300, 780, 520])
+        self.assertEquals(tournament.prizes(), None)
+        tournament.can_register = False
+        tournament.rank2prize = None
+        self.failUnlessEqual(tournament.prizes(), [1300, 780, 520])
+        tournament.can_register = True
         
         for player in range(28, 48):
             self.failUnless(tournament.register(player))
-        self.failUnlessEqual(tournament.prizesTable(), [1840, 1104, 736, 552, 368])
-        
+        self.assertEquals(tournament.prizes(), None)
+        tournament.can_register = False
+        tournament.rank2prize = None
+        self.failUnlessEqual(tournament.prizes(), [1840, 1104, 736, 552, 368])
+        tournament.can_register = True
+
         for player in range(48, 198):
             self.failUnless(tournament.register(player))
-        self.failUnlessEqual(tournament.prizesTable(), [5880, 3920, 2450, 1764, 1568, 1274, 980, 784, 588, 392])
+        self.assertEquals(tournament.prizes(), None)
+        tournament.rank2prize = None
+        tournament.can_register = False
+        self.failUnlessEqual(tournament.prizes(), [5880, 3920, 2450, 1764, 1568, 1274, 980, 784, 588, 392])
+        tournament.can_register = True
         
         for player in range(198, 298):
             self.failUnless(tournament.register(player))
-        self.failUnlessEqual(len(tournament.prizesTable()), 20)
-        
+        self.assertEquals(tournament.prizes(), None)
+        tournament.can_register = False
+        tournament.rank2prize = None
+        self.failUnlessEqual(len(tournament.prizes()), 20)
+        tournament.can_register = True
     # -------------------------------------------------------
     def testPrizes(self):
         """Test Poker Tournament : Prizes"""
@@ -444,24 +504,55 @@ class PokerTournamentTestCase(unittest.TestCase):
                             }
                             
         tournament = pokertournament.PokerTournament(**arguments)
-        
         self.failUnlessEqual(tournament.prizes(), None)
-        
         for player in range(20):
             self.failUnless(tournament.register(player))
         
         tournament.prizes_specs = 'table'
         tournament.rank2prize = None
-        self.failUnlessEqual(tournament.prizesTable(), tournament.prizes())
-        
-        tournament.prizes_specs = 'algorithm'
+        p = PokerPrizesTable(buyInAmount = 100, playerCount = 20, configDirs = self.dirs)
+        self.failUnlessEqual(tournament.prizes_object.player_count, p.player_count)
+        self.failUnlessEqual(tournament.prizes_object.buy_in, p.buy_in)
+        self.failUnlessEqual(tournament.prizes(), p.getPrizes())
+
+        arguments['prizes_specs'] = 'algorithm'
+        tournament = pokertournament.PokerTournament(**arguments)
+        self.failUnlessEqual(tournament.prizes(), None)
+        for player in range(20):
+            self.failUnless(tournament.register(player))
         tournament.rank2prize = None
-        self.failUnlessEqual(tournament.prizesAlgorithm(), tournament.prizes())
+        p = PokerPrizesAlgorithm(buyInAmount = 100, playerCount = 20)
+        self.failUnlessEqual(tournament.prizes_object.player_count, p.player_count)
+        self.failUnlessEqual(tournament.prizes_object.buy_in, p.buy_in)
+        self.failUnlessEqual(tournament.prizes(), p.getPrizes())
         
-        tournament.prizes_specs = 'invalid'
-        tournament.rank2prize = None
+
+        silence_all_messages()
+
+        arguments['prizes_specs'] = 'invalid'
+        tournament = pokertournament.PokerTournament(**arguments)
         self.failUnlessEqual(tournament.prizes(), None)
-        
+        for player in range(20):
+            self.failUnless(tournament.register(player))
+        tournament.rank2prize = None
+
+        # Behavior before pokerprizes existed when prizes_specs was
+        # invalid in some way, it simply had nothing returned from
+        # tournament.prizes().  The test case, therefore, was as below:
+
+#        self.failUnlessEqual(tournament.prizes(), None) However, it makes
+
+        # However, it more sense to simply default to something if a prize
+        # spec is invalid, and print an error message.  That is what now
+        # happens, and that's what this test code does:
+
+        msgs = get_messages()
+        self.assertEquals(msgs[0], "ERROR 'module' object has no attribute 'PokerPrizesInvalid'")
+        p = PokerPrizesAlgorithm(buyInAmount = 100, playerCount = 20)
+        self.failUnlessEqual(tournament.prizes_object.player_count, p.player_count)
+        self.failUnlessEqual(tournament.prizes_object.buy_in, p.buy_in)
+        self.failUnlessEqual(tournament.prizes(), p.getPrizes())
+        restore_all_messages()
     # -------------------------------------------------------
     def testMovePlayer(self):
         """Test Poker Tournament : Move player"""
diff --git a/poker-engine/tests/testmessages.py b/poker-engine/tests/testmessages.py
new file mode 100644
index 0000000..dd9b65c
--- /dev/null
+++ b/poker-engine/tests/testmessages.py
@@ -0,0 +1,115 @@
+#
+# Copyright (C) 2006, 2007, 2008 Loic Dachary <[EMAIL PROTECTED]>
+# Copyright (C) 2006 Mekensleep <[EMAIL PROTECTED]>
+#                    24 rue vieille du temple, 75004 Paris
+#
+# This software's license gives you freedom; you can copy, convey,
+# propagate, redistribute and/or modify this program under the terms of
+# the GNU General Public License (GPL) as published by the Free Software
+# Foundation (FSF), either version 3 of the License, or (at your option)
+# any later version of the GPL published by the FSF.
+#
+# 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 in a file in the toplevel directory called
+# "GPLv3".  If not, see <http://www.gnu.org/licenses/>.
+#
+# Authors:
+#  Loic Dachary <[EMAIL PROTECTED]>
+#
+import sys, os
+
+classes = []
+
+from pokerengine import pokergame
+classes.append(pokergame.PokerGame)
+
+from pokerengine import pokerprizes
+classes.append(pokerprizes.PokerPrizesFactory)
+classes.append(pokerprizes.PokerPrizes)
+
+from twisted.internet import defer
+
+verbose = int(os.environ.get('VERBOSE_T', '-1'))
+
+#
+# for coverage purpose, make sure all message functions
+# are called at least once
+#
+def call_messages():
+    import StringIO
+    for a_class in classes:
+        stdout = sys.stdout
+        sys.stdout = StringIO.StringIO()
+        class F(a_class):
+            def __init__(self, *args, **kwargs):
+                self._prefix = 'P'
+                self.prefix = 'P'
+                self.id = 1
+                self.name = 'name'
+        F().message('')
+        sys.stdout = stdout
+call_messages()
+
+messages_needle = ''
+messages_grep_hit = None
+def grep_output(needle):
+    messages_grep_hit = defer.Deferred()
+    messages_needle = needle
+    return messages_grep_hit
+
+def messages_grep(haystack):
+    if haystack.find(messages_needle):
+        hit = messages_grep_hit
+        messages_grep_hit = None
+        hit.callback(haystack)
+        
+def messages_append(string):
+    if verbose > 3:
+        print "OUTPUT: " + string
+    if not hasattr(string, '__str__'):
+        raise Exception, "Message comes in as non-stringifiable object" 
+    string = string.__str__()
+    messages_out.append(string)
+    messages_grep(string)
+
+class2message = {
+    pokergame.PokerGame: lambda self, string: messages_append(self.prefix + "[PokerGame " + str(self.id) + "] " + string)
+    }
+messages_out = []
+
+def redirect_messages(a_class):
+    if not hasattr(a_class, 'orig_message'):
+        a_class.orig_message = [ ]
+    a_class.orig_message.append(a_class.message)
+    a_class.message = class2message.get(a_class, lambda self, string: messages_append(string))
+    
+def silence_all_messages():
+    messages_out = []
+    for a_class in classes:
+        redirect_messages(a_class)
+
+def restore_all_messages():
+    for a_class in classes:
+        a_class.message = a_class.orig_message.pop()
+
+def search_output(what):
+    if verbose > 1:
+        print "search_output: " + what
+    for message in messages_out:
+        if message.find(what) >= 0:
+            return True
+        if verbose > 1:
+            print "\tnot in " + message
+    return False
+
+def clear_all_messages():
+    global messages_out
+    messages_out = []
+
+def get_messages():
+    return messages_out
diff --git a/poker-engine/tests/tournament.py.in b/poker-engine/tests/tournament.py.in
index b2d6ac6..0fd6587 100644
--- a/poker-engine/tests/tournament.py.in
+++ b/poker-engine/tests/tournament.py.in
@@ -439,68 +439,102 @@ class TestCreate(unittest.TestCase):
 class TestPrizes(unittest.TestCase):
 
     def test1(self):
-        tourney = PokerTournament(dirs = [ '../conf', '@top_srcdir@/conf' ])
-        tourney.can_register = False
+        tourney = PokerTournament(dirs = [ '../conf', '@top_srcdir@/conf' ],
+                                  prizes_specs = 'algorithm', buy_in = 5, players_quota = 100)
+        for ii in range(1, 11): tourney.register(ii)
 
-        tourney.prizes_specs = "algorithm"
-        tourney.buy_in = 5
-        
-        tourney.registered = 10
-        tourney.rank2prize = None
+        tourney.can_register = False
         self.assertEqual(tourney.prizes(), [32, 12, 6])
 
-        tourney.registered = 20
-        tourney.rank2prize = None
+        tourney = PokerTournament(dirs = [ '../conf', '@top_srcdir@/conf' ],
+                                  prizes_specs = 'algorithm', buy_in = 5, players_quota = 100)
+        for ii in range(1, 21): tourney.register(ii)
+
+        tourney.can_register = False
         self.assertEqual(tourney.prizes(), [57, 25, 12, 6])
 
-        tourney.registered = 50
-        tourney.rank2prize = None
+        tourney = PokerTournament(dirs = [ '../conf', '@top_srcdir@/conf' ],
+                                  prizes_specs = 'algorithm', buy_in = 5, players_quota = 1000)
+        for ii in range(1, 51): tourney.register(ii)
+
+        tourney.can_register = False
         self.assertEqual(tourney.prizes(), [129, 62, 31, 7, 7, 7, 7])
                         
-        tourney.registered = 200
-        tourney.rank2prize = None
+        tourney = PokerTournament(dirs = [ '../conf', '@top_srcdir@/conf' ],
+                                  prizes_specs = 'algorithm', buy_in = 5, players_quota = 1000)
+        for ii in range(200): tourney.register(ii)
+
+        tourney.can_register = False
         self.assertEqual(tourney.prizes(), [506, 250, 125, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7])
 
-        tourney.prizes_specs = "table"
-        
-        tourney.registered = 3
-        tourney.rank2prize = None
+        tourney = PokerTournament(dirs = [ '../conf', '@top_srcdir@/conf' ],
+                                  prizes_specs = 'table', buy_in = 5, players_quota = 1000)
+        for ii in range(3): tourney.register(ii)
+
+        tourney.can_register = False
         self.assertEqual(tourney.prizes(), [15])
 
-        tourney.registered = 6
-        tourney.rank2prize = None
+        tourney = PokerTournament(dirs = [ '../conf', '@top_srcdir@/conf' ],
+                                  prizes_specs = 'table', buy_in = 5, players_quota = 1000)
+        for ii in range(6): tourney.register(ii)
+
+        tourney.can_register = False
         self.assertEqual(tourney.prizes(), [21, 9])
 
-        tourney.registered = 30
-        tourney.rank2prize = None
+        tourney = PokerTournament(dirs = [ '../conf', '@top_srcdir@/conf' ],
+                                  prizes_specs = 'table', buy_in = 5, players_quota = 1000)
+        for ii in range(30): tourney.register(ii)
+
+        tourney.can_register = False
         self.assertEqual(tourney.prizes(), [75, 45, 30])
 
-        tourney.registered = 50
-        tourney.rank2prize = None
+        tourney = PokerTournament(dirs = [ '../conf', '@top_srcdir@/conf' ],
+                                  prizes_specs = 'table', buy_in = 5, players_quota = 1000)
+        for ii in range(50): tourney.register(ii)
+
+        tourney.can_register = False
         self.assertEqual(tourney.prizes(), [100, 60, 40, 30, 20])
 
-        tourney.registered = 200
-        tourney.rank2prize = None
+        tourney = PokerTournament(dirs = [ '../conf', '@top_srcdir@/conf' ],
+                                  prizes_specs = 'table', buy_in = 5, players_quota = 1000)
+        for ii in range(200): tourney.register(ii)
+
+        tourney.can_register = False
         self.assertEqual(tourney.prizes(), [300, 200, 125, 90, 80, 65, 50, 40, 30, 20])
                         
-        tourney.registered = 300
-        tourney.rank2prize = None
+        tourney = PokerTournament(dirs = [ '../conf', '@top_srcdir@/conf' ],
+                                  prizes_specs = 'table', buy_in = 5, players_quota = 1000)
+        for ii in range(300): tourney.register(ii)
+
+        tourney.can_register = False
         self.assertEqual(tourney.prizes(), [453, 292, 180, 120, 97, 75, 52, 37, 26, 18, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15])
 
-        tourney.registered = 500
-        tourney.rank2prize = None
+        tourney = PokerTournament(dirs = [ '../conf', '@top_srcdir@/conf' ],
+                                  prizes_specs = 'table', buy_in = 5, players_quota = 1000)
+        for ii in range(500): tourney.register(ii)
+
+        tourney.can_register = False
         self.assertEqual(tourney.prizes(), [641, 375, 250, 200, 125, 100, 75, 50, 43, 31, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18])
 
-        tourney.registered = 700
-        tourney.rank2prize = None
+        tourney = PokerTournament(dirs = [ '../conf', '@top_srcdir@/conf' ],
+                                  prizes_specs = 'table', buy_in = 5, players_quota = 1000)
+        for ii in range(700): tourney.register(ii)
+
+        tourney.can_register = False
         self.assertEqual(tourney.prizes(), [717, 437, 315, 245, 175, 140, 105, 61, 52, 43, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17])
 
-        tourney.registered = 1000
-        tourney.rank2prize = None
+        tourney = PokerTournament(dirs = [ '../conf', '@top_srcdir@/conf' ],
+                                  prizes_specs = 'table', buy_in = 5, players_quota = 5000)
+        for ii in range(1000): tourney.register(ii)
+
+        tourney.can_register = False
         self.assertEqual(tourney.prizes(), [1026, 600, 450, 350, 250, 200, 150, 87, 75, 62, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10])
 
-        tourney.registered = 5000
-        tourney.rank2prize = None
+        tourney = PokerTournament(dirs = [ '../conf', '@top_srcdir@/conf' ],
+                                  prizes_specs = 'table', buy_in = 5, players_quota = 5000)
+        for ii in range(5000): tourney.register(ii)
+
+        tourney.can_register = False
         self.assertEqual(tourney.prizes(), [5036, 3000, 2000, 1500, 1250, 1000, 625, 437, 312, 250, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37])
 
                         
-- 

   -- bkuhn
_______________________________________________
Pokersource-users mailing list
[email protected]
https://mail.gna.org/listinfo/pokersource-users

Reply via email to