{"id":17027893,"url":"https://github.com/sobjornstad/lblsolve","last_synced_at":"2025-03-22T19:43:28.504Z","repository":{"id":62575363,"uuid":"445656514","full_name":"sobjornstad/lblsolve","owner":"sobjornstad","description":"solver for La Belle Lucie solitaire games","archived":false,"fork":false,"pushed_at":"2022-01-07T21:44:48.000Z","size":34,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-28T07:52:01.645Z","etag":null,"topics":["game-solver","solitaire"],"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/sobjornstad.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}},"created_at":"2022-01-07T21:25:25.000Z","updated_at":"2022-08-31T02:54:04.000Z","dependencies_parsed_at":"2022-11-03T18:52:58.368Z","dependency_job_id":null,"html_url":"https://github.com/sobjornstad/lblsolve","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sobjornstad%2Flblsolve","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sobjornstad%2Flblsolve/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sobjornstad%2Flblsolve/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sobjornstad%2Flblsolve/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sobjornstad","download_url":"https://codeload.github.com/sobjornstad/lblsolve/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245013955,"owners_count":20547177,"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":["game-solver","solitaire"],"created_at":"2024-10-14T07:51:09.081Z","updated_at":"2025-03-22T19:43:28.466Z","avatar_url":"https://github.com/sobjornstad.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# La Belle Lucie Solver\n\nThis is an automatic solver for the solitaire game\n[La Belle Lucie](https://en.wikipedia.org/wiki/La_Belle_Lucie)\n(including, optionally, the merci rule).\n\n\n## Installation\n\nThis solver has no dependencies outside the standard library\n(all dependencies in `requirements.txt` are needed for development only).\nYou can install it directly via PyPi:\n\n```\npip install lblsolve\n```\n\nOr, if you'd like to play with the code,\nyou can clone this repository and install the package in editable mode:\n\n```\npip install -r requirements.txt\n```\n\nEither way, the `lbl` command and the `lblsolve` Python package\nwill be available on your system.\n\n\n## Use\n\nThe solver accepts a text representation of your tableau on standard input.\nEach line represents a fan, while cards in each fan are separated with spaces.\nHere's a typical input that's solvable with 3 deals and a *merci*:\n\n```\nKH 2S 8S\n3S 5S QH\nJH 4H 10D\n3D 8C 8D\n4C JS 7D\nAH AS 5H\n7C 2D 5D\nAC 8H 10C\n2H QD 7H\n3H AD KD\n4S 9S 6H\n9D QC 10H\n6C KS JD\n6D 6S 9C\nKC 9H 10S\n5C 4D 7S\n2C 3C JC\nQS\n```\n\nYou don't have to enter cards on the foundations --\nthey're assumed to contain all cards that aren't on the tableau.\n\nIf standard input is connected to your terminal,\nyou'll receive a small help message before being prompted to enter the tableau.\n\nAlternatively, you can use the `--shuffle` option\nto generate a random tableau and attempt to solve that.\n\nThere is currently minimal error-checking on inputs.\nBe warned that you may get very odd results\nif you input a tableau that can't have occurred by making legal moves\n(for instance, if you include a 2♦ and a 4♦ but no 3♦,\n so that the foundation contains A♦ 3♦).\n\nYou can control whether the solver automatically redeals\nand whether it applies the *merci* rule\nwith additional command-line options;\ncheck `lbl --help` for these.\n\nHere's what the output looks like:\n\n```\nLa Belle Lucie solver\nCopyright (c) 2022 Soren Bjornstad.\nUse the --help switch for full command-line options.\n\nAwaiting the tableau to solve on standard input.\nCards look like '5H', where 5 is the number of the card or 'A', 'J', 'Q', or 'K', \nand H the suit of the card, 'C', 'D', 'H', or 'S' (lowercase letters or Unicode suit glyphs also accepted).\nEnter horizontal whitespace between cards of a fan and Return between fans.\nTo finish entering fans, press ^D. The foundations will consist of any cards not on your tableau.\n\nKH 2S 8S\n3S 5S QH\nJH 4H 10D\n3D 8C 8D\n4C JS 7D\nAH AS 5H\n7C 2D 5D\nAC 8H 10C\n2H QD 7H\n3H AD KD\n4S 9S 6H\n9D QC 10H\n6C KS JD\n6D 6S 9C\nKC 9H 10S\n5C 4D 7S\n2C 3C JC\nQS\n[Read fan  0] K♥  2♠  8♠\n[Read fan  1] 3♠  5♠  Q♥\n[Read fan  2] J♥  4♥  10♦\n[Read fan  3] 3♦  8♣  8♦\n[Read fan  4] 4♣  J♠  7♦\n[Read fan  5] A♥  A♠  5♥\n[Read fan  6] 7♣  2♦  5♦\n[Read fan  7] A♣  8♥  10♣\n[Read fan  8] 2♥  Q♦  7♥\n[Read fan  9] 3♥  A♦  K♦\n[Read fan 10] 4♠  9♠  6♥\n[Read fan 11] 9♦  Q♣  10♥\n[Read fan 12] 6♣  K♠  J♦\n[Read fan 13] 6♦  6♠  9♣\n[Read fan 14] K♣  9♥  10♠\n[Read fan 15] 5♣  4♦  7♠\n[Read fan 16] 2♣  3♣  J♣\n[Read fan 17] Q♠\n^D\n\n========== Deal 1 ==========\nStarting tableau:\n[ 0]  K♥   2♠   8♠\n[ 1]  3♠   5♠   Q♥\n[ 2]  J♥   4♥  10♦\n[ 3]  3♦   8♣   8♦\n[ 4]  4♣   J♠   7♦\n[ 5]  A♥   A♠   5♥\n[ 6]  7♣   2♦   5♦\n[ 7]  A♣   8♥  10♣\n[ 8]  2♥   Q♦   7♥\n[ 9]  3♥   A♦   K♦\n[10]  4♠   9♠   6♥\n[11]  9♦   Q♣  10♥\n[12]  6♣   K♠   J♦\n[13]  6♦   6♠   9♣\n[14]  K♣   9♥  10♠\n[15]  5♣   4♦   7♠\n[16]  2♣   3♣   J♣\n[17]  Q♠\n\nDFS for best blocking moves using 7 thread(s):\n  Found 17702 total legal permutation(s) of blocking moves.   \nBest sequence has 39 moves, transferring 18 cards to the foundation and leaving 34 on the tableau.\n\nMove sequence:\n  [Blocking move  ] 10♦ =\u003e 6♣  K♠  J♦\n  [Blocking move  ] 6♥ =\u003e 2♥  Q♦  7♥\n  [Safe build     ] 5♥ =\u003e 2♥  Q♦  7♥  6♥\n  [Safe build     ] 4♥ =\u003e 2♥  Q♦  7♥  6♥  5♥\n  [Safe build     ] 10♥ =\u003e J♥\n  [Foundation move] A♠\n  [Foundation move] A♥\n  [Blocking move  ] J♣ =\u003e 9♦  Q♣\n  [Safe build     ] 10♣ =\u003e 9♦  Q♣  J♣\n  [Safe build     ] 9♣ =\u003e 9♦  Q♣  J♣  10♣\n  [Blocking move  ] 6♠ =\u003e 5♣  4♦  7♠\n  [Safe build     ] 5♦ =\u003e 6♦\n  [Blocking move  ] 9♠ =\u003e K♣  9♥  10♠\n  [Safe build     ] 8♠ =\u003e K♣  9♥  10♠  9♠\n  [Foundation move] 2♠\n  [Safe build     ] Q♥ =\u003e K♥\n  [Safe build     ] 5♠ =\u003e 5♣  4♦  7♠  6♠\n  [Safe build     ] 3♠ =\u003e 4♠\n  [Foundation move] 3♠\n  [Foundation move] 4♠\n  [Foundation move] 5♠\n  [Foundation move] 6♠\n  [Foundation move] 7♠\n  [Foundation move] 8♠\n  [Foundation move] 9♠\n  [Foundation move] 10♠\n  [Safe build     ] 9♥ =\u003e J♥  10♥\n  [Safe build     ] 8♥ =\u003e J♥  10♥  9♥\n  [Safe build     ] 4♦ =\u003e 6♦  5♦\n  [Foundation move] A♣\n  [Blocking move  ] 7♦ =\u003e 3♦  8♣  8♦\n  [Foundation move] J♠\n  [Foundation move] Q♠\n  [Safe build     ] 3♣ =\u003e 4♣\n  [Safe build     ] 2♣ =\u003e 4♣  3♣\n  [Foundation move] 2♣\n  [Foundation move] 3♣\n  [Foundation move] 4♣\n  [Foundation move] 5♣\n\nFinal table state after deal 1:\n[ 0]  K♥   Q♥\n[ 1]  J♥  10♥   9♥   8♥\n[ 2]  3♦   8♣   8♦   7♦\n[ 3]  7♣   2♦\n[ 4]  2♥   Q♦   7♥   6♥   5♥   4♥\n[ 5]  3♥   A♦   K♦\n[ 6]  9♦   Q♣   J♣  10♣   9♣\n[ 7]  6♣   K♠   J♦  10♦\n[ 8]  6♦   5♦   4♦\n[ 9]  K♣\n\n[♠] A♠ 2♠ 3♠ 4♠ 5♠ 6♠ 7♠ 8♠ 9♠ 10♠ J♠ Q♠\n[♥] A♥\n[♣] A♣ 2♣ 3♣ 4♣ 5♣\n\n========== Deal 2 ==========\nStarting tableau:\n[ 0]  6♥   7♣   5♦\n[ 1]  5♥   K♦   2♦\n[ 2]  K♠   K♥   3♥\n[ 3]  2♥   6♣   7♥\n[ 4]  8♥   6♦   7♦\n[ 5] 10♥   4♥   8♣\n[ 6]  8♦   9♦   J♣\n[ 7] 10♣   9♣   Q♣\n[ 8]  K♣   9♥   Q♦\n[ 9]  A♦   4♦   Q♥\n[10]  J♥   3♦   J♦\n[11] 10♦\n\nStarting foundation:\n[♠] A♠ 2♠ 3♠ 4♠ 5♠ 6♠ 7♠ 8♠ 9♠ 10♠ J♠ Q♠\n[♥] A♥\n[♣] A♣ 2♣ 3♣ 4♣ 5♣\n\nDFS for best blocking moves using 3 thread(s):\n  Found 7 total legal permutation(s) of blocking moves.   \nBest sequence has 45 moves, transferring 29 cards to the foundation and leaving 5 on the tableau.\n\nMove sequence:\n  [Blocking move  ] J♦ =\u003e K♣  9♥  Q♦\n  [Safe build     ] 10♦ =\u003e K♣  9♥  Q♦  J♦\n  [Blocking move  ] J♣ =\u003e 10♣  9♣  Q♣\n  [Safe build     ] 9♦ =\u003e K♣  9♥  Q♦  J♦  10♦\n  [Safe build     ] 7♦ =\u003e 8♦\n  [Safe build     ] 6♦ =\u003e 8♦  7♦\n  [Safe build     ] 7♥ =\u003e 8♥\n  [Safe build     ] 5♦ =\u003e 8♦  7♦  6♦\n  [Foundation move] 6♣\n  [Foundation move] 2♥\n  [Foundation move] 7♣\n  [Foundation move] 3♥\n  [Foundation move] 8♣\n  [Foundation move] 4♥\n  [Safe build     ] Q♥ =\u003e K♠  K♥\n  [Safe build     ] 6♥ =\u003e 8♥  7♥\n  [Safe build     ] 4♦ =\u003e 8♦  7♦  6♦  5♦\n  [Safe build     ] 3♦ =\u003e 8♦  7♦  6♦  5♦  4♦\n  [Safe build     ] J♥ =\u003e K♠  K♥  Q♥\n  [Safe build     ] 10♥ =\u003e K♠  K♥  Q♥  J♥\n  [Safe build     ] 2♦ =\u003e 8♦  7♦  6♦  5♦  4♦  3♦\n  [Safe build     ] A♦ =\u003e 8♦  7♦  6♦  5♦  4♦  3♦  2♦\n  [Foundation move] A♦\n  [Foundation move] 2♦\n  [Foundation move] 3♦\n  [Foundation move] 4♦\n  [Foundation move] 5♦\n  [Foundation move] 6♦\n  [Foundation move] 7♦\n  [Foundation move] 8♦\n  [Foundation move] 9♦\n  [Foundation move] 10♦\n  [Foundation move] J♦\n  [Foundation move] Q♦\n  [Foundation move] K♦\n  [Foundation move] 5♥\n  [Foundation move] 6♥\n  [Foundation move] 7♥\n  [Foundation move] 8♥\n  [Foundation move] 9♥\n  [Foundation move] 10♥\n  [Foundation move] J♥\n  [Foundation move] Q♥\n  [Foundation move] K♥\n  [Foundation move] K♠\n\nFinal table state after deal 2:\n[ 0] 10♣   9♣   Q♣   J♣\n[ 1]  K♣\n\n[♠] A♠ 2♠ 3♠ 4♠ 5♠ 6♠ 7♠ 8♠ 9♠ 10♠ J♠ Q♠ K♠\n[♥] A♥ 2♥ 3♥ 4♥ 5♥ 6♥ 7♥ 8♥ 9♥ 10♥ J♥ Q♥ K♥\n[♣] A♣ 2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣\n[♦] A♦ 2♦ 3♦ 4♦ 5♦ 6♦ 7♦ 8♦ 9♦ 10♦ J♦ Q♦ K♦\n\n========== Deal 3 ==========\nStarting tableau:\n[ 0] 10♣   Q♣   9♣\n[ 1]  J♣   K♣\n\nStarting foundation:\n[♠] A♠ 2♠ 3♠ 4♠ 5♠ 6♠ 7♠ 8♠ 9♠ 10♠ J♠ Q♠ K♠\n[♥] A♥ 2♥ 3♥ 4♥ 5♥ 6♥ 7♥ 8♥ 9♥ 10♥ J♥ Q♥ K♥\n[♣] A♣ 2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣\n[♦] A♦ 2♦ 3♦ 4♦ 5♦ 6♦ 7♦ 8♦ 9♦ 10♦ J♦ Q♦ K♦\n\nDFS for best blocking moves using 2 thread(s):\n  Found 2 total legal permutation(s) of blocking moves.   \nBest sequence has 7 moves, transferring 5 cards to the foundation and leaving 0 on the tableau.\n\nMove sequence:\n  [Foundation move] 9♣\n  [Safe build     ] Q♣ =\u003e J♣  K♣\n  [Foundation move] 10♣\n  [Merci          ] J♣ =\u003e J♣  K♣  Q♣\n  [Foundation move] J♣\n  [Foundation move] Q♣\n  [Foundation move] K♣\n\nFinal table state after deal 3:\n\n\n[♠] A♠ 2♠ 3♠ 4♠ 5♠ 6♠ 7♠ 8♠ 9♠ 10♠ J♠ Q♠ K♠\n[♥] A♥ 2♥ 3♥ 4♥ 5♥ 6♥ 7♥ 8♥ 9♥ 10♥ J♥ Q♥ K♥\n[♣] A♣ 2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣ 9♣ 10♣ J♣ Q♣ K♣\n[♦] A♦ 2♦ 3♦ 4♦ 5♦ 6♦ 7♦ 8♦ 9♦ 10♦ J♦ Q♦ K♦\n\nGame solved in 9842.60ms on deal 3.\n```\n\nIf the game isn't solvable,\nthe sequence of moves yielding the smallest possible number\nof remaining cards on the tableau is shown.\n\nThe exit status is 0 if the game was solved,\n1 if it was unsolvable,\nand 255 if the input was invalid.\n\n\n## Computational approach\n\nThe solver categorizes all possible moves\ninto *safe builds*, *foundation moves*, *blocking moves*, and *mercis*.\n\n* **Safe builds**: Cards that can be moved to another location on the tableau\n  without removing any moves from the set of possible future moves\n  (except, of course, the safe build itself).\n  These include moving a card onto a king,\n  moving a card onto a fan with only one card,\n  and moving a card onto a sequence of two or more descending cards of the same suit.\n\n  There are other edge cases that are safe builds,\n  but the only consequence of leaving them out of the solver's definition\n  is that the search might take a bit longer,\n  so they're ignored for simplicity.\n\n* **Foundation moves**: Cards that can be moved directly onto a foundation.\n  These are also safe in the sense that they don't remove any possible future moves.\n\n* **Blocking moves**: Other moves of cards onto other cards in the tableau.\n  While these moves can allow further safe builds or foundation moves\n  that wouldn't otherwise be possible,\n  they can also prevent other cards from being moved to useful places,\n  and they cannot ever be undone or the card moved again to anywhere other than the foundation,\n  so these moves need to be considered carefully.\n\n* **Mercis**: In the ruleset including a *merci*,\n  at some point during the third deal,\n  you can pick up one card that's not at the top of its fan\n  and place it somewhere on the tableau or foundation.\n  The solver weights these equally with blocking moves\n  and considers them at the same time,\n  when mercis are enabled, the current deal is the last deal,\n  and no merci has yet happened this deal.\n  Otherwise, it skips looking for them entirely.\n\nWe benefit from doing safe builds and foundation moves\nas soon as they're available,\nwhile blocking moves and mercis should be done\nonly when these possibilities are exhausted.\nCompleting safe builds and foundation moves as soon as they're available\nremoves enough computational complexity that a brute-force depth-first search\non blocking moves and mercis\nbecomes practical;\noptimally solved games typically use a single-digit number of blocking moves.\n\nThe general structure of the solver algorithm is as follows:\n\n1. Starting from the initial position,\n   the solver builds an implicit tree (via recursion)\n   of all possible sequences of blocking moves or mercis\n   (if enabled and allowed on the current deal).\n2. After every blocking move/merci,\n   it applies all possible safe builds and foundation moves\n   (alternating between doing all the safe builds possible\n    and all the foundation moves possible\n    until there are no more of either).\n   Then it tries another blocking move or merci.\n3. Recursion continues until the tableau is empty\n   or there are no more legal moves.\n4. At every branch,\n   the child candidate sequence of moves that results in\n   the most cards transferred to the foundation\n   is passed back up to the parent.\n   Since the tableau will be reshuffled (or useless, on the last deal)\n   after all foundation moves are made,\n   nothing else matters.\n   (If at any point there are multiple possible sequences\n    with the same number of foundations transfers,\n    the one chosen is the one tried first.)\n5. Back at the top level,\n   the best possible sequence and the resulting tableau and foundations\n   are displayed to the user.\n6. If the tableau isn't empty,\n   redeals were requested,\n   and this wasn't the last deal,\n   the tableau is gathered up, reshuffled, and redealt,\n   and the process begins again from step 1.\n\nThe first level of the recursive tree is split into threads\nto speed up the process.\nThis is often suboptimal\ndepending on how many possible moves there are in the initial state,\nbut it's a very quick and easy way to get a usually reasonable number,\nand the solver almost always finishes in under a minute\n(often seconds or milliseconds -- the complexity of deals seems to have high variance)\nanyway.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsobjornstad%2Flblsolve","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsobjornstad%2Flblsolve","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsobjornstad%2Flblsolve/lists"}