{"id":35124287,"url":"https://github.com/juliendubost/black-jack-resolver","last_synced_at":"2026-03-18T02:33:33.681Z","repository":{"id":249196944,"uuid":"819313151","full_name":"juliendubost/black-jack-resolver","owner":"juliendubost","description":"Black Jack's game resolver.  A determinist solver that produce the best strategy depending on house rules and give the whole game expected value. For each house rules set, best moves and expected values can be generated.  ","archived":false,"fork":false,"pushed_at":"2025-12-28T20:01:28.000Z","size":121,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"develop","last_synced_at":"2025-12-29T19:10:30.828Z","etag":null,"topics":["blackjack","blackjack-game","resolver","solver","strategy"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/juliendubost.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2024-06-24T08:59:41.000Z","updated_at":"2025-12-28T20:01:31.000Z","dependencies_parsed_at":"2024-08-29T22:57:22.130Z","dependency_job_id":null,"html_url":"https://github.com/juliendubost/black-jack-resolver","commit_stats":null,"previous_names":["juliendubost/black-jack-resolver"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/juliendubost/black-jack-resolver","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/juliendubost%2Fblack-jack-resolver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/juliendubost%2Fblack-jack-resolver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/juliendubost%2Fblack-jack-resolver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/juliendubost%2Fblack-jack-resolver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/juliendubost","download_url":"https://codeload.github.com/juliendubost/black-jack-resolver/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/juliendubost%2Fblack-jack-resolver/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30642995,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-18T01:41:58.583Z","status":"online","status_checked_at":"2026-03-18T02:00:07.824Z","response_time":104,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["blackjack","blackjack-game","resolver","solver","strategy"],"created_at":"2025-12-28T01:37:57.614Z","updated_at":"2026-03-18T02:33:33.674Z","avatar_url":"https://github.com/juliendubost.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"```text\n                 ... Black Jack Resolver ...\n                 \n                            _ _   \n                           | A | \n                           | _ | \n                         bank card\n                           \n                     _ _                _ _\n                 _ _| J |           _ _| K | \n                | A | _ |          | Q | _ |\n                | _ |              | _ |\n                            _ _     [Stand]  \n                         _ _| 2 | \n                        | 5 | _ |                   \n                        | _ |   \n                          [Hit]\n\n```\n\n# Description\n\nBlack Jack resolver is a simple python app that compute and display expected values and best player move for each bank's start cards\n\nSolving is determinist and based on a [directed acyclic graph](https://en.wikipedia.org/wiki/Directed_acyclic_graph) representation of hand states\nA monte-carlo validation is implemented as unit tests to check some pre-computed values. Not the whole game have been modeled using a montecarlo validation\n\nHypothesis are:\n- An infinite number of decks, at any time the probability of drawing card that is not ten-valued is 1/13 and 4/13 for a 10-valued card.\n- No possibility to double after a split\n- Infinite number of splits\n\nOptions: \n- Dealer's peeked: mostly use in America where dealer stop the game before serving players if the face down card would reveal a blackjack (disable using --no-peek)\n- Stand or hit on soft 17: control either dealer stand or hit on a soft 17 (enable hit on soft 17 using --hos option)\n- No draw on aces split: only one card is dealt on each ace when a pocket aces hand is split (enable it using --ace-no-draw option)\n- No black jack on aces split: a ten valued with an ace do not give a blackjack when a pocket aces hand is split, you get 21 instead (enable it using --ace-no-bj option)\n\n\nHere are the computed game expected values (NO YET VALIDATED) depending on house rules, using the best strategy:\n\n| dealer's peeked    | hit on soft 17  | ace no draw  | ace no BJ  | EV        | tables folder                                                  | \n|--------------------|-----------------|--------------| ---------- |-----------|----------------------------------------------------------------|\n|                    |                 |              |            | 1.002063  | [no_peek](tables/no_peek)                                      | \n| X                  |                 |              |            | 1.012566  | [peeked](tables/peeked)                                        |\n|                    | X               |              |            | 1.000686  | [no_peek_hos](tables/no_peek_hos)                              |\n| X                  | X               |              |            | 1.010486  | [peeked_hos](tables/peeked_hos)                                |\n|                    |                 | X            | X          | 0.99808   | [no_peek_no_bj_no_draw](tables/no_peek_no_bj_no_draw)          |\n| X                  |                 | X            | X          | 1.008584  | [peeked_no_bj_no_draw](tables/peeked_no_bj_no_draw)            |\n|                    | X               | X            | X          | 0.996722  | [no_peek_hos_no_bj_no_draw](tables/no_peek_hos_no_bj_no_draw)  |\n| X                  | X               | X            | X          | 1.006536  | [peeked_hos_no_bj_no_draw](tables/peeked_hos_no_bj_no_draw)    |\n\n\nAll best moves and expected values tables computable using this resolver are available in the `tables` directory.\n\n# EV tables\n\nBest moves table (see below) is issued from the EV tables for each bank card and player's start hand probabilities (see the `START_HAND_WEIGHTS` variable in `blackjack/constants.py`)\n\nEV table approach is to compute, for each possible state:\n- the standing EV\n- the EV of hitting only 1 card then standing\n- the maximum EV you can reach from this state using the best strategy\n\nIn the example below, best move is to surrender, because:\n- the maximum EV you can reach from this state is `0.493`.\n- if you stand, EV is `0.231`\n- if you surrender, you get an EV of `0.5` (dealer take half of your bet) \n\nConsequently, best move is to surrender if possible, else hit.\n```text\n-------------------------------------------------------------------------------\nPlayer state        EV stand       EV hit \u0026 stand      Max EV         Best move      \n-------------------------------------------------------------------------------\n12                  0.231          0.437               0.493          U-H   \n```\n\nIn the other example, best move is to double if possible, else stand, because:\n- stand EV is `0.828`\n- max EV is `1.154`, net gain is `0.154`\n- hit only 1 card then stand EV is `1.118`, net gain if you double from here is 2 times `0.118` = `0.236`\n\nConsequently, because `0.236` is greater than `0.154` the maximum net gain is obtained using a double strategy.\n\nIf the EV of hitting only 1 card and standing would have been lesser than `0.154`, best move would have be to hit.\n\n\n```text\n-------------------------------------------------------------------------------\nPlayer state        EV stand       EV hit \u0026 stand      Max EV         Best move      \n-------------------------------------------------------------------------------\n9                   0.828          1.118               1.154          D-H            \n```\n\n# Contributions\n\nIf you want to contribute, feel free to suggest and/or ask any questions.\n\nHere are some ideas of things that could be done: \n- an external review of this code base to validate the approach.\n- a full montecarlo game model to validate strategy expected values.\n- a way to estimate the game variance to determine how many hands should be played to ensure player have a good chance to be wining.\n\n\n# Install using poetry\n\n```shell\npoetry install\n```\n\n# Run tests\n\n```shell\npytest  # run on a single thread\npytest -s  # run on a single thread and display logs\npytest -n 8  # run on 8 cores using pytest-xdist\n```\n\n# Usage \nActivate poetry env\n\n```shell\npoetry shell\n```\n\nThen run `jack.py` to display expected values for a given bank card or best moves table\n\nFor example, to display best moves table and strategy total expected value, use:\n\n```shell\npython jack.py best_moves\n```\n\nDefault is to have the dealer's peeked option and stand on soft 17 .\n\nThis can be changed options `--no-peek` (disable dealer's peeked) and `--hos` (activate hit on soft 17) options.\n\nExample output for standard use case (no hit on soft 17 and dealer peeked): \n\n```text\n-----------------------------------------------------------------------------------\nPlayer best move for each bank card (first line) and each state (first column)\n-----------------------------------------------------------------------------------\n\t2\t3\t4\t5\t6\t7\t8\t9\tF\tA\t\n-----------------------------------------------------------------------------------\n20\tS\tS\tS\tS\tS\tS\tS\tS\tS\tS\t\n19\tS\tS\tS\tS\tS\tS\tS\tS\tS\tS\t\n18\tS\tS\tS\tS\tS\tS\tS\tS\tS\tS\t\n17\tS\tS\tS\tS\tS\tS\tS\tS\tS\tU-S\t\n16\tS\tS\tS\tS\tS\tH\tH\tU-H\tU-H\tU-H\t\n15\tS\tS\tS\tS\tS\tH\tH\tH\tH\tU-H\t\n14\tS\tS\tS\tS\tS\tH\tH\tH\tH\tU-H\t\n13\tS\tS\tS\tS\tS\tH\tH\tH\tH\tU-H\t\n12\tH\tH\tS\tS\tS\tH\tH\tH\tH\tU-H\t\n11\tD-H\tD-H\tD-H\tD-H\tD-H\tD-H\tD-H\tD-H\tD-H\tH\t\n10\tD-H\tD-H\tD-H\tD-H\tD-H\tD-H\tD-H\tD-H\tH\tH\t\n9\tH\tD-H\tD-H\tD-H\tD-H\tH\tH\tH\tH\tH\t\n8\tH\tH\tH\tH\tH\tH\tH\tH\tH\tH\t\n7\tH\tH\tH\tH\tH\tH\tH\tH\tH\tH\t\n6\tH\tH\tH\tH\tH\tH\tH\tH\tH\tH\t\n5\tH\tH\tH\tH\tH\tH\tH\tH\tH\tH\t\n4\tH\tH\tH\tH\tH\tH\tH\tH\tH\tH\t\n-----------------------------------------------------------------------------------\n10-20\tS\tS\tS\tS\tS\tS\tS\tS\tS\tS\t\n9-19\tS\tS\tS\tS\tS\tS\tS\tS\tS\tS\t\n8-18\tS\tD-S\tD-S\tD-S\tD-S\tS\tS\tH\tH\tH\t\n7-17\tH\tD-H\tD-H\tD-H\tD-H\tH\tH\tH\tH\tH\t\n6-16\tH\tH\tD-H\tD-H\tD-H\tH\tH\tH\tH\tH\t\n5-15\tH\tH\tH\tD-H\tD-H\tH\tH\tH\tH\tH\t\n4-14\tH\tH\tH\tD-H\tD-H\tH\tH\tH\tH\tH\t\n3-13\tH\tH\tH\tH\tD-H\tH\tH\tH\tH\tH\t\n2-12\tH\tH\tH\tH\tH\tH\tH\tH\tH\tH\t\n-----------------------------------------------------------------------------------\n1-1\tSp\tSp\tSp\tSp\tSp\tSp\tSp\tSp\tSp\tSp\t\n10-10\tS\tS\tS\tS\tS\tS\tS\tS\tS\tS\t\n9-9\tSp\tSp\tSp\tSp\tSp\tS\tSp\tSp\tS\tS\t\n8-8\tSp\tSp\tSp\tSp\tSp\tSp\tSp\tSp\tSp\tU-H\t\n7-7\tSp\tSp\tSp\tSp\tSp\tSp\tH\tH\tH\tU-H\t\n6-6\tH\tSp\tSp\tSp\tSp\tH\tH\tH\tH\tU-H\t\n5-5\tD-H\tD-H\tD-H\tD-H\tD-H\tD-H\tD-H\tD-H\tH\tH\t\n4-4\tH\tH\tH\tH\tH\tH\tH\tH\tH\tH\t\n3-3\tH\tH\tSp\tSp\tSp\tSp\tH\tH\tH\tH\t\n2-2\tH\tH\tSp\tSp\tSp\tSp\tH\tH\tH\tH\t\n-----------------------------------------------------------------------------------\nlegend:\n\tS: Stand\n\tH: Hit\n\tSp: Split\n\tD-S: Double if possible else stand\n\tD-H: Double if possible else hit\n\tU-S: Surrender if possible else stand\n\tU-H: Surrender if possible else hit\n\tU-Sp: Surrender if possible else split\n-----------------------------------------------------------------------------------\nTotal expected value using this strategy if double, split and surrender are allowed is: 1.00715\n(you win a total of 1.00715 every time you do an initial bet of 1)\n-----------------------------------------------------------------------------------\n```\n\n\nTo display expected values table for an Ace on the bank, use:\n\n```text\npython jack.py --ev-table -card A\n```\n\nPossible values are: `2`, `3`,`4`,`5`,`6`,`7`,`8`,`9`,`F` (a ten-valued card),  \n\nOutput:\n\n```text\n-------------------------------------------------------------------------------\nBank card: A\n-------------------------------------------------------------------------------\nPlayer state        EV stand       EV hit \u0026 stand      Max EV         Best move      \n-------------------------------------------------------------------------------\n2                   0.231          0.231               0.552          H              \n3                   0.231          0.231               0.535          H              \n4                   0.231          0.231               0.517          H              \n5                   0.231          0.231               0.502          H              \n6                   0.231          0.241               0.482          U-H            \n7                   0.231          0.301               0.478          U-H            \n8                   0.231          0.412               0.556          H              \n9                   0.231          0.542               0.647          H              \n10                  0.231          0.687               0.749          H              \nF                   0.231          0.742               0.803          H              \n11                  0.231          0.73                0.791          H              \n12                  0.231          0.405               0.45           U-H            \n13                  0.231          0.387               0.418          U-H            \n14                  0.231          0.37                0.388          U-H            \n15                  0.231          0.352               0.36           U-H            \n16                  0.231          0.334               0.334          U-H            \n17                  0.361          0.306               0.361          U-S            \n18                  0.623          0.259               0.623          S              \n19                  0.885          0.191               0.885          S              \n20                  1.146          0.102               1.146          S              \nA                   0.231          0.948               1.117          H              \n2-12                0.231          0.476               0.678          H              \n3-13                0.231          0.476               0.653          H              \n4-14                0.231          0.476               0.627          H              \n5-15                0.231          0.476               0.602          H              \n6-16                0.231          0.476               0.578          H              \n7-17                0.361          0.506               0.568          H              \n8-18                0.623          0.567               0.628          H              \n9-19                0.885          0.627               0.885          S              \n10-20               1.146          0.687               1.146          S              \n21                  1.331          0                   1.331          S              \n1-1                 0.231          0.476               0.678          Sp             \n2-2                 0.231          0.231               0.517          H              \n3-3                 0.231          0.241               0.482          U-H            \n4-4                 0.231          0.412               0.556          H              \n5-5                 0.231          0.687               0.749          H              \n6-6                 0.231          0.405               0.45           U-H            \n7-7                 0.231          0.37                0.388          U-H            \n8-8                 0.231          0.334               0.334          U-H            \n9-9                 0.623          0.259               0.623          S              \n10-10               1.146          0.102               1.146          S              \nBJ                  2.038          0                   2.038          S       \n-------------------------------------------------------------------------------\nLegend:\n  [Player state] State of player game:\n    10: a score of ten that can't lead to a black jack, for example 8 \u0026 2 or 5 \u0026 5 or 6 \u0026 4, ...\n    F: a single figure, this can be obtained only by splitting a pocket figure hand\n  [EV stand] Give the expected value of standing in this position (1.0 = even)\n  [EV hit \u0026 stand] Give the expected value of hit and stand from this position (useful to evaluate if a double is relevant)\n  [Max EV] Give the maximum expected value that can be obtained from this position using only stand or hit choices\n  [Best move] Give the best move from this position:\n    S: Stand\n    H: Hit\n    Sp: Split\n    D-S: Double if possible else stand\n    D-H: Double if possible else hit\n    U-S: Surrender if possible else stand\n    U-H: Surrender if possible else hit\n    U-Sp: Surrender if possible else split\n-------------------------------------------------------------------------------\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjuliendubost%2Fblack-jack-resolver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjuliendubost%2Fblack-jack-resolver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjuliendubost%2Fblack-jack-resolver/lists"}