{"id":17800440,"url":"https://github.com/anntzer/redeal","last_synced_at":"2025-04-23T21:22:11.673Z","repository":{"id":3567244,"uuid":"4629237","full_name":"anntzer/redeal","owner":"anntzer","description":"A reimplementation of Thomas Andrews' Deal in Python.","archived":false,"fork":false,"pushed_at":"2025-04-21T16:46:15.000Z","size":631,"stargazers_count":64,"open_issues_count":1,"forks_count":41,"subscribers_count":12,"default_branch":"main","last_synced_at":"2025-04-21T17:42:50.590Z","etag":null,"topics":["bridge-game"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anntzer.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2012-06-11T19:37:33.000Z","updated_at":"2025-04-21T16:46:19.000Z","dependencies_parsed_at":"2024-01-21T13:28:45.984Z","dependency_job_id":"cfa9be42-0ab7-41bb-b751-c15099c7304b","html_url":"https://github.com/anntzer/redeal","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anntzer%2Fredeal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anntzer%2Fredeal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anntzer%2Fredeal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anntzer%2Fredeal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anntzer","download_url":"https://codeload.github.com/anntzer/redeal/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250515326,"owners_count":21443371,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bridge-game"],"created_at":"2024-10-27T12:21:57.336Z","updated_at":"2025-04-23T21:22:11.666Z","avatar_url":"https://github.com/anntzer.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"======\nRedeal\n======\n\n-----------------------------------------------------\nA reimplementation of Thomas Andrews' Deal in Python.\n-----------------------------------------------------\n\n.. contents:: :local:\n\nThomas Andrew's Deal is a deal generator: it outputs deals satisfying whatever\nconditions you specify -- deals with a double void, deals with a strong 2♣\nopener opposite a yarborough, etc.  Using Bo Haglund's double dummy solver, it\ncan even solve the hands it has generated for you. Unfortunately, I have never\nreally liked the language Deal uses for scripting: Tcl.  Redeal is thus my\nrewrite of Deal using another language: Python.\n\nRedeal runs under Python 3.6 or higher.  See the ``examples/`` directory for\nsome example simulations.\n\nA double-dummy solver function is also available through Bo Haglund's DDS,\nwhich is distributed with Redeal as a git submodule.  Note that this requires\nthe ``libgomp`` package.  You can also download the compiled shared objects\nfrom `Bo Haglund's website`__.  For Windows, the DDS DLLs are distributed\ntogether with Redeal, so everything should work out of the box.  If the DDS\nlibrary is absent, Redeal will work fine but the ``dd_tricks``, ``dd_score``\nand ``dd_all_tricks`` methods will be unavailable.\n\n__ http://privat.bahnhof.se/wb758135/bridge/dll.html\n\nInstallation\n============\n\nOn a Unix system, do **not** download the ``.zip`` or ``.tar.gz`` releases.\nThey do not contain the DDS library.  The recommended way to install the\npackage is directly from GitHub,\n\n.. code:: sh\n\n    $ python -mpip install --user --upgrade git+https://github.com/anntzer/redeal\n\nOn Windows **only**, you can also download the ``.zip`` archive (from main,\nnot from the releases), and run, from the directory containing the archive,\n``python -mpip install --user --upgrade redeal-main.zip`` (or whatever name\nit has).\n\nNow, run ``python -mredeal --help``, or ``python -mredeal`` to get a few hands,\nor ``python -mredeal examples/deal1.py`` for an example simulation.  In the\n``examples`` directory (which you can extract from the zip archive), ``python\n__run_all_examples__.py`` will go through all the examples.\n\n(Depending on the details of your installation, directly using the command\n``redeal`` instead of ``python -mredeal`` may also work, but there are not\nguarantees for that.)\n\nA note on the GUI\n=================\n\nRedeal provides a GUI, ``python -mredeal --gui``, if you are not comfortable\nusing the command line.  Some GUI-specific information is scattered in the\ntutorial so read on!\n\nAn introductory tutorial\n========================\n\nAll these examples come from Deal's documentation.\n\nDealing hands\n-------------\n\nRun ``python -mredeal`` at the command line to deal 10 hands, or ``python\n-mredeal -n N`` to deal ``N`` hands.\n\n.. code:: sh\n\n    $ python -mredeal -n2\n    ♠AQ53♥QJ9♦K963♣T9 ♠K♥AK853♦AQ87♣A42 ♠976♥7642♦T2♣KJ73 ♠JT842♥T♦J54♣Q865\n    ♠T7♥J862♦QT4♣8752 ♠Q93♥T95♦A32♣KQ94 ♠K854♥AK7♦KJ87♣T3 ♠AJ62♥Q43♦965♣AJ6\n    Tries: 2\n\nNote that if your terminal does not support UTF-8, suit symbols will be\nreplaced by letters -- but the rest should work fine.\n\nHere, the number of tries is the same as the number of hands, as any hand is\naccepted.  This may not be the case in more complex cases.\n\nUsing the GUI, just keep click ``Run`` to go!  The number of requested deals\ncan be set at the top of the window.\n\nStacking a hand\n---------------\n\nWould you open 2 or 3♥ with ♠-♥KQJT62♦T9876♣84?  Well, let's deal a couple of\nhands to see how this would fare.\n\n.. code:: sh\n\n    $ python -mredeal -S '- KQJT62 T9876 84'\n    ♠AT982♥854♦J42♣KT ♠KQ7♥A973♦AK5♣AQJ ♠♥KQJT62♦T9876♣84 ♠J6543♥♦Q3♣976532\n    ♠85♥854♦K4♣JT9752 ♠K97643♥A97♦A♣KQ6 ♠♥KQJT62♦T9876♣84 ♠AQJT2♥3♦QJ532♣A3\n    ♠94♥97♦KJ42♣QJ972 ♠KJ852♥A85♦AQ3♣K5 ♠♥KQJT62♦T9876♣84 ♠AQT763♥43♦5♣AT63\n    ♠KJT963♥A954♦K4♣2 ♠AQ82♥7♦5♣AKJT753 ♠♥KQJT62♦T9876♣84 ♠754♥83♦AQJ32♣Q96\n    ♠984♥93♦AJ543♣AK7 ♠AJ52♥A84♦KQ♣JT96 ♠♥KQJT62♦T9876♣84 ♠KQT763♥75♦2♣Q532\n    ♠J974♥53♦QJ43♣T62 ♠AKQ852♥A97♦♣J975 ♠♥KQJT62♦T9876♣84 ♠T63♥84♦AK52♣AKQ3\n    ♠742♥73♦AQ♣AK9763 ♠KJT♥A95♦J542♣J52 ♠♥KQJT62♦T9876♣84 ♠AQ98653♥84♦K3♣QT\n    ♠Q82♥A9♦A42♣AT732 ♠AJ754♥85♦KJ5♣Q95 ♠♥KQJT62♦T9876♣84 ♠KT963♥743♦Q3♣KJ6\n    ♠QJT543♥8♦AJ3♣Q53 ♠K876♥A9743♦K5♣JT ♠♥KQJT62♦T9876♣84 ♠A92♥5♦Q42♣AK9762\n    ♠AQJ8432♥4♦AQ♣KT5 ♠KT96♥A98♦32♣AJ76 ♠♥KQJT62♦T9876♣84 ♠75♥753♦KJ54♣Q932\n    Tries: 10\n\nThere are also ``-N``, ``-E`` and ``-W`` options, with the expected meanings.\nNote that you do not have to indicate 13 cards for a hand, but you always have\nto specify the four suits.  For example, you can select hands where North holds\nthe heart ace with ``python -mredeal -S '- A - -'``.\n\nUsing the GUI, input the hands (using the same format) in the boxes labeled\n\"North\", \"South\", \"East\" and \"West\".\n\nFormatting output\n-----------------\n\nThe default output is compact, but not very friendly.  What about more classic\ndiagrams?  The ``--format=long`` flag (or the GUI's \"long output for diagrams\"\noption) is there for that!\n\n.. code:: sh\n\n    $ python -mredeal --format=long -n1\n\n           ♠\n           ♥632\n           ♦AKT92\n           ♣K7652\n\n    ♠AJ85         ♠T962\n    ♥KJ954        ♥7\n    ♦QJ           ♦8763\n    ♣QJ           ♣AT94\n\n           ♠KQ743\n           ♥AQT8\n           ♦54\n           ♣83\n\n    Tries: 1\n\nOur first script\n----------------\n\nLet's say we want a selection of deals in which north holds a one spade opener.\nFor now, we will use a crude definition for an opening 1♠ call -- we will\nrequire North to have 5 or more spades and 12 or more points.\n\nHere is the script we write, to a file we'll call ``onespade.py``, or in the\n``accept`` box of the GUI:\n\n.. code:: python\n\n    def accept(deal):\n        if len(deal.north.spades) \u003e= 5 and deal.north.hcp \u003e= 12:\n            return True\n\nand run it as follows:\n\n.. code:: sh\n\n    $ python -mredeal examples/onespade.py # put the path to onespade.py\n    ♠AJ854♥J986♦T♣AKJ ♠KQ96♥2♦KJ874♣T52 ♠T732♥AKQT43♦Q2♣3 ♠♥75♦A9653♣Q98764\n    ♠AQ875♥T87♦A♣QJ84 ♠T943♥♦9752♣T9652 ♠J6♥AQJ9432♦J6♣A7 ♠K2♥K65♦KQT843♣K3\n    ♠KQ9874♥J4♦J43♣KQ ♠J65♥A873♦2♣AJT87 ♠A2♥K65♦AT975♣652 ♠T3♥QT92♦KQ86♣943\n    ♠QT6543♥A9♦KT♣K32 ♠72♥KT74♦A9♣QT754 ♠J98♥QJ865♦QJ8♣J8 ♠AK♥32♦765432♣A96\n    ♠AT862♥KQJ♦Q65♣K2 ♠QJ953♥A832♦7♣A53 ♠4♥T765♦KT983♣Q87 ♠K7♥94♦AJ42♣JT964\n    ♠KQ974♥A652♦9♣QJ3 ♠AJ5♥Q7♦KQ8♣A9872 ♠♥K84♦AT76543♣T64 ♠T8632♥JT93♦J2♣K5\n    ♠AJ943♥Q♦AQJT♣JT9 ♠T52♥AJT♦K852♣AQ6 ♠KQ6♥K876532♦97♣2 ♠87♥94♦643♣K87543\n    ♠KQT532♥KQ♦K♣KQ92 ♠8♥T5♦A864♣AT7654 ♠AJ76♥98643♦Q5♣83 ♠94♥AJ72♦JT9732♣J\n    ♠AT9743♥Q7♦J♣AKT2 ♠8♥A932♦AKT7♣J963 ♠K62♥J5♦98653♣874 ♠QJ5♥KT864♦Q42♣Q5\n    ♠KJ842♥K5♦94♣AK74 ♠53♥Q7♦762♣Q98653 ♠AQ96♥943♦JT85♣JT ♠T7♥AJT862♦AKQ3♣2\n    Tries: 120\n\nThe ``accept`` function is called after each deal is dealt.  It can either\nreturn ``True`` (or any Python-truthy object), if the deal satisfies our\nconditions, or ``False`` (or any Python-falsey object) otherwise -- in which\ncase it is not counted towards the goal of 10 deals.  Note that at the end,\nredeal also gives us the total number of hands it had to deal in order to get\n10 accepted hands.\n\nIn our case, ``deal.north`` represents North's hand, ``deal.north.spades`` is a\nlist of North's spade holding, and ``deal.north.hcp`` is North's number of HCP.\nIf the conditions are satisfied, we return ``True``.  This prints the hand and\nincrements the counter of accepted hands.\n\nThere are in total, four functions that can be overridden:\n\n- ``initial`` (taking no argument) is called when the simulation begins\n  (defaults to doing nothing)\n- ``accept`` (taking a ``deal`` argument) should return True or False depending\n  on whether the deal is accepted -- defaults to always True,\n- ``do`` (taking a ``deal`` argument) is called on each accepted deal --\n  defaults to printing the deal,\n- ``final`` (taking a ``n_tries`` argument) is called when the simulation ends\n  (defaults to printing the number of tries).\n\nOne can also give the ``accept`` function, as the body of a function taking a\n``deal`` argument, at the command line:\n\n.. code:: sh\n\n    $ python -mredeal --accept 'return len(deal.north.spades) \u003e= 5 and deal.north.hcp \u003e= 12'\n    ♠AKJT7♥85♦865♣KQ7 ♠852♥A74♦AQT42♣86 ♠963♥KJ3♦J973♣AT4 ♠Q4♥QT962♦K♣J9532\n    ♠AKT86♥AJ76♦64♣42 ♠J954♥T♦KT752♣KT5 ♠3♥KQ853♦A983♣Q76 ♠Q72♥942♦QJ♣AJ983\n    ♠AQ753♥A96♦A♣AT43 ♠KJT6♥KQ83♦Q753♣8 ♠9♥JT75♦KT42♣KQJ7 ♠842♥42♦J986♣9652\n    ♠A98543♥63♦KQ♣AQ9 ♠J2♥AJT2♦J976♣J63 ♠QT6♥K9874♦T43♣K8 ♠K7♥Q5♦A852♣T7542\n    ♠AK9642♥JT♦J9♣A42 ♠75♥A732♦AKQ84♣Q3 ♠T3♥K54♦T653♣KJT6 ♠QJ8♥Q986♦72♣9875\n    ♠AK832♥3♦32♣AKQT2 ♠964♥J6♦AKJ5♣8765 ♠J7♥AK8542♦6♣J943 ♠QT5♥QT97♦QT9874♣\n    ♠AQ432♥♦KJT43♣Q74 ♠J985♥9765♦A862♣T ♠6♥AKQJ82♦Q7♣AJ32 ♠KT7♥T43♦95♣K9865\n    ♠AJT83♥AJ8♦82♣Q75 ♠Q64♥Q975♦J76♣KJ2 ♠75♥KT4♦KT93♣T943 ♠K92♥632♦AQ54♣A86\n    ♠AJ652♥J2♦A9♣Q953 ♠KQ93♥AKT6♦KQ2♣84 ♠T87♥874♦873♣AT72 ♠4♥Q953♦JT654♣KJ6\n    ♠KQJT9♥98♦KT♣K962 ♠♥J65432♦763♣AJ83 ♠A8652♥AQ7♦A8♣T54 ♠743♥KT♦QJ9542♣Q7\n    Tries: 203\n\n\nPredealing and scripting\n------------------------\n\nYour partner opens 1♠ and you hold ♠-♥96532♦A864♣T962... do you pass or bid\na forcing NT?  Let's generate a few hands so that we can see how we would fare.\n\n.. code:: sh\n\n    $ python -mredeal -S '- 96532 A864 T962' examples/onespade.py\n    ♠A8643♥A8♦QT72♣Q8 ♠QT972♥Q♦K95♣K754 ♠♥96532♦A864♣T962 ♠KJ5♥KJT74♦J3♣AJ3\n    ♠AQ864♥4♦KJT72♣QJ ♠JT7♥AJT8♦Q3♣A743 ♠♥96532♦A864♣T962 ♠K9532♥KQ7♦95♣K85\n    ♠AQT765♥7♦J72♣KQ8 ♠K9832♥AKT♦K953♣5 ♠♥96532♦A864♣T962 ♠J4♥QJ84♦QT♣AJ743\n    ♠AJ932♥74♦KQJ7♣KJ ♠KQT65♥AK8♦532♣A4 ♠♥96532♦A864♣T962 ♠874♥QJT♦T9♣Q8753\n    ♠KJ986♥AJT8♦K♣K75 ♠AT73♥Q74♦Q732♣Q8 ♠♥96532♦A864♣T962 ♠Q542♥K♦JT95♣AJ43\n    ♠QJ9732♥A♦QJ♣AQ87 ♠T865♥J87♦K97♣J54 ♠♥96532♦A864♣T962 ♠AK4♥KQT4♦T532♣K3\n    ♠AKQJT732♥K8♦7♣85 ♠4♥AJ74♦K53♣AKQJ4 ♠♥96532♦A864♣T962 ♠9865♥QT♦QJT92♣73\n    ♠AK653♥Q84♦QT5♣J3 ♠982♥AT♦KJ97♣AKQ5 ♠♥96532♦A864♣T962 ♠QJT74♥KJ7♦32♣874\n    ♠AKJ98752♥7♦J5♣A3 ♠Q643♥AQJ4♦Q3♣K85 ♠♥96532♦A864♣T962 ♠T♥KT8♦KT972♣QJ74\n    ♠KJ9863♥♦Q9♣AKJ73 ♠AT75♥QT874♦72♣85 ♠♥96532♦A864♣T962 ♠Q42♥AKJ♦KJT53♣Q4\n    Tries: 31\n\nAgain, one can also give the ``accept`` function at the command line.\n\nOr, one can indicate the predealt cards (\"stacked\", in Deal jargon) in the\nscript, in the ``predeal`` variable:\n\n.. code:: python\n\n   from redeal import * # this is \"reasonably\" safe\n\n   predeal = {\"S\": H(\"- 96532 A864 T962\")} # H is a hand constructor.\n\n   def accept(deal):\n      if len(deal.north.spades) \u003e= 5 and deal.north.hcp \u003e= 12:\n         return True\n\nNote that the predealing occurs outside of the ``accept`` function.  Also, the\n``redeal`` module has to be imported only for scripts in their own files; this\nis done implicitely for the GUI and for functions given at the command line.\n\nShape\n-----\n\nHands also have a ``shape`` attribute, which returns a list of the length in\neach suit.  This can be queried directly, or using ``Shape`` objects, which are\nvery efficient:\n\n.. code:: python\n\n   from redeal import *\n\n   def accept(deal):\n      return balanced(deal.north)\n\n``balanced`` is defined in ``redeal.py`` as\n\n.. code:: python\n\n   balanced = Shape(\"(4333)\") + Shape(\"(4432)\") + Shape(\"(5332)\")\n\nwhere the parentheses have the usual meaning.  ``semibalanced`` is available as\nwell, and one can define other shapes, possibly using ``x`` as a generic\nplaceholder:\n\n.. code:: python\n\n   major_two_suited = Shape(\"(54)xx\") - Shape(\"(54)(40)\")\n\nTo specify extreme shapes, \"T\", \"J\", \"Q\", and \"K\" can be used to specify 10,\n11, 12, and 13 card suits.\n\nVector additive functions\n-------------------------\n\nQuite a few hand evaluation techniques (HCP, controls, suit quality) look at\none suit at a time, and attribute some value to each card.  Just like ``deal``,\n``redeal`` provides ``Evaluator`` for creating such evaluation functions:\n\n.. code:: python\n\n   from redeal import *\n\n   hcp = Evaluator(4, 3, 2, 1)\n   controls = Evaluator(2, 1)\n   top3 = Evaluator(1, 1, 1)\n\nNow you can test the quality of a suit with, for example,\n``top3(deal.north.spades) \u003e= 2`` (this may be relevant when generating weak two\nhands).\n\nSmartstacking\n-------------\n\nRare hand types (say, 22 to 24 balanced) can be annoying to work with, as\n``redeal`` needs to generate a lot of hands before finding any of them.  You\ncan pass the ``-v`` flag (not available from the GUI) to add some progress\ninformation to the output.\n\nFor some rare hand types, Deal and Redeal provide an alternative, faster hand\ndealing technique: smartstacking.  Smartstacking works for only one of the\nfour seats, and can only take two sorts of constraints: a Shape object, and\nbounds on the total value of a vector additive function (i.e. summed over the\nfour suits).  For example, the following example finds hands where North is\n4-4 in the major, has a short minor and 11-15HCP.\n\n.. code:: python\n\n   from redeal import *\n\n   Roman = Shape(\"44(41)\") + Shape(\"44(50)\")\n   predeal = {\"N\": SmartStack(Roman, Evaluator(4, 3, 2, 1), range(11, 16))}\n\nWhen smartstacking is used, Redeal starts by computing the relative\nprobabilities that each holding appears in a hand that satisfies the given\ncondition, which takes some time.  This then allows it to generate deals very\nquickly, much faster than by generating random deals and checking whether they\npass an ``accept`` function.  For the given example, as long as one requests\na couple of dozen of hands, smartstacking is faster than direct dealing.\n\nSmartstacking will take into account other (normally) predealt hands, and an\n``accept`` function can still be used, e.g. to still throw away some of the\nhands.  See ``examples/deal_gambling.py`` for a complete example.\n\nFinally, please note that smartstacking is only available for scripts in their\nown files, not at the command line nor in the GUI.\n\nGenerating deals using Python\n=============================\n\nDeals can also be generated programmatically from Python, instead of using the\n``redeal`` program. Here's an example:\n\n.. code:: python\n\n   from redeal import *\n\n   def accept(deal):\n       return deal.north.hcp \u003e= 18\n\n   dealer = Deal.prepare()\n\n   # A random deal is generated\n   deal1 = dealer()\n\n   # Generate another one, using our accept function above\n   deal2 = dealer(accept)\n\nYou may also use predealing and SmartStacking, as an argument to\n``Deal.prepare``:\n\n.. code:: python\n\n   from redeal import *\n\n   def accept(deal):\n       return deal.north.hcp \u003e= 15\n\n   dealer = Deal.prepare({'S': 'K83 AK83 - QJT972'})\n   deal = dealer(accept)\n\nExternal links\n==============\n\nContent produced by users showcasing the use of Redeal:\n\n- `Using data science in bridge: how important is shape for 3NT and 4S?`__\n\n__ https://www.youtube.com/watch?v=4J6yvoxx_Fg\n\n.. vim: set fileencoding=utf-8:\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanntzer%2Fredeal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanntzer%2Fredeal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanntzer%2Fredeal/lists"}