Skip to content

Commit

Permalink
Easier to programmatically generate deals from Python. (#7)
Browse files Browse the repository at this point in the history
* Easier to programmatically generate deals from Python.

* Indentation typo fixed.

* Fixes based on code review.

- Use functools.partial
- Deal.prepare now has a default argument (passing an empty dict isn't needed)
- Key and value pairs in predeal arg to Deal.prepare will be converted from
  strings to Seat / Hand.
  • Loading branch information
Kungsgeten authored and anntzer committed Dec 7, 2017
1 parent e714dea commit 70d2fda
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 26 deletions.
34 changes: 34 additions & 0 deletions README.rst
Expand Up @@ -337,4 +337,38 @@ hands. See ``examples/deal_gambling.py`` for a complete example.
Finally, please note that smartstacking is only available for scripts in their
own files, not at the command line nor in the GUI.

Generating deals using Python
=============================

Deals can also be generated programmatically from Python, instead of using the
``redeal`` program. Here's an example:

.. code:: python
from redeal import *
def accept(deal):
return deal.north.hcp >= 18
dealer = Deal.prepare()
# A random deal is generated
deal1 = dealer()
# Generate another one, using our accept function above
deal2 = dealer(accept)
You may also use predealing and SmartStacking, as an argument to
``Deal.prepare``:

.. code:: python
from redeal import *
def accept(deal):
return deal.north.hcp >= 15
dealer = Deal.prepare({'S': 'K83 AK83 - QJT972'})
deal = dealer(accept)
.. vim: set fileencoding=utf-8:
65 changes: 39 additions & 26 deletions redeal/redeal.py
Expand Up @@ -6,6 +6,7 @@
from itertools import groupby, permutations, product
from math import sqrt
from operator import itemgetter
import functools
import random
import sys
if sys.version_info < (3,):
Expand Down Expand Up @@ -226,17 +227,23 @@ class Deal(tuple, object):
"""

@classmethod
def prepare(cls, predeal):
def prepare(cls, predeal=None):
"""Contruct a dealer from a ``Seat -> [Hand | SmartStack]`` dict.
Seat and/or Hand may be given as strings.
There can be at most one ``SmartStack`` entry.
"""
predeal = predeal.copy() or {}
predeal = {} if predeal is None else predeal.copy() or {}
dealer = {}
seat_smartstack = None
for seat in Seat:
pre = predeal.pop(seat, Hand(()))
if isinstance(pre, SmartStack):
try:
pre = predeal.pop(str(seat)[0])
except:
pre = predeal.pop(seat, Hand(()))
if isinstance(pre, str):
dealer[seat] = H(pre).cards
elif isinstance(pre, SmartStack):
if seat_smartstack:
raise Exception("Only one Smartstack allowed.")
seat_smartstack = seat, pre
Expand All @@ -256,31 +263,37 @@ def prepare(cls, predeal):
dealer["_smartstack"] = seat
dealer["_remaining"] = [card for card in FULL_DECK
if card not in predealt_set]
return lambda: cls(dealer)
return functools.partial(cls, dealer)

def __new__(cls, dealer):
def __new__(cls, dealer, accept_func=None, tries=1000):
"""Randomly deal a hand from a prepared dealer.
``accept_func`` can be a function similar to ``Simulation.accept``
Reshuffles until ``accept_func`` returns true, but at most set number of ``tries``.
"""
hands = [None] * len(Seat)
cards = dealer["_remaining"]
try:
seat = dealer["_smartstack"]
except KeyError:
pass
else:
hands[seat] = hand = Hand(dealer[seat]())
cards = list(set(cards).difference(hand.cards()))
random.shuffle(cards)
for seat in Seat:
if hands[seat]:
continue
pre = dealer[seat]()
to_deal = len(Rank) - len(pre)
hand, cards = pre + cards[:to_deal], cards[to_deal:]
hands[seat] = Hand(hand)
self = tuple.__new__(cls, hands)
self._dd_cache = {}
return self
for i in range(tries):
hands = [None] * len(Seat)
cards = dealer["_remaining"]
try:
seat = dealer["_smartstack"]
except KeyError:
pass
else:
hands[seat] = hand = Hand(dealer[seat]())
cards = list(set(cards).difference(hand.cards()))
random.shuffle(cards)
for seat in Seat:
if hands[seat]:
continue
pre = dealer[seat]()
to_deal = len(Rank) - len(pre)
hand, cards = pre + cards[:to_deal], cards[to_deal:]
hands[seat] = Hand(hand)
self = tuple.__new__(cls, hands)
self._dd_cache = {}
if accept_func is None or accept_func(self):
return self
raise Exception("Could not generate any deal matching accept_func")

def _short_str(self):
"""Return a one-line version of the deal.
Expand Down

0 comments on commit 70d2fda

Please sign in to comment.