{"id":49488454,"url":"https://github.com/fluttersmith/bulls-and-cows-solver","last_synced_at":"2026-05-01T03:04:19.141Z","repository":{"id":351379582,"uuid":"1210703439","full_name":"FlutterSmith/bulls-and-cows-solver","owner":"FlutterSmith","description":"A Knuth-minimax Bulls and Cows solver with a rich terminal UI. Cracks any 4-unique-digit secret in ~5 guesses.","archived":false,"fork":false,"pushed_at":"2026-04-14T18:15:24.000Z","size":35,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-14T20:17:06.812Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/FlutterSmith.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-14T17:14:15.000Z","updated_at":"2026-04-14T18:15:31.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/FlutterSmith/bulls-and-cows-solver","commit_stats":null,"previous_names":["fluttersmith/bulls-and-cows-solver"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/FlutterSmith/bulls-and-cows-solver","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FlutterSmith%2Fbulls-and-cows-solver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FlutterSmith%2Fbulls-and-cows-solver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FlutterSmith%2Fbulls-and-cows-solver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FlutterSmith%2Fbulls-and-cows-solver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FlutterSmith","download_url":"https://codeload.github.com/FlutterSmith/bulls-and-cows-solver/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FlutterSmith%2Fbulls-and-cows-solver/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32483405,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"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":[],"created_at":"2026-05-01T03:03:57.683Z","updated_at":"2026-05-01T03:04:19.135Z","avatar_url":"https://github.com/FlutterSmith.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Bulls and Cows Solver\n\nA **Knuth-minimax** Bulls and Cows solver shipped two ways — a Python CLI with a rich terminal UI, and a polished single-page web app with glass-morphism panels, animated candidate-pool counters, and confetti on win. Think of it as a tiny chess-style engine for the 4-unique-digit number game — it evaluates every possible guess, picks the one that maximally shrinks the candidate pool in the worst case, and usually cracks any secret in **4–5 guesses**.\n\n**[▸ Live web demo](https://fluttersmith.github.io/bulls-and-cows-solver/)**\n\n```\n ____        _ _         ___     ____\n| __ ) _   _| | |___    ( _ )   / ___|_____      _____\n|  _ \\| | | | | / __|   / _ \\/\\| |   / _ \\ \\ /\\ / / __|\n| |_) | |_| | | \\__ \\  | (_\u003e  \u003c| |__| (_) \\ V  V /\\__ \\\n|____/ \\__,_|_|_|___/   \\___/\\/ \\____\\___/ \\_/\\_/ |___/\n\n                  S  O  L  V  E  R\n```\n\n---\n\n## What is Bulls and Cows?\n\nYou pick a secret 4-digit number with **unique digits** (e.g. `7392`). I guess, you tell me:\n\n- **bulls** — digits that are in the right place\n- **cows** — digits that are in the number but the wrong place\n\nI use that feedback to whittle the candidate pool down and make the next guess. Repeat until you're staring at your own secret number on the screen.\n\n---\n\n## Features\n\n- **Knuth minimax solver** — for every candidate guess, groups the remaining pool by the score each would yield, then picks the guess whose worst-case bucket is smallest. Tiebreaks by information entropy and prefers guesses that could win outright.\n- **Four modes:**\n  - `solve` — you pick the secret, the tool guesses it interactively\n  - `auto` — the tool picks a random secret, then solves it in front of you with a narrated top-5 move table every turn\n  - `play` — classic mode: you guess a secret the tool picked, it scores you\n  - `benchmark` — run the solver against every possible secret and print the turn distribution\n- **Candidate-set cache** — identical candidate sets reuse the last minimax result, so benchmark runs of 5k+ secrets finish in under a minute instead of hours.\n- **Gorgeous terminal UI** — powered by [rich](https://github.com/Textualize/rich): panels, colored tables, banners, candidate-pool status with color-coded urgency.\n- **Zero external deps beyond `rich`.** Pure standard library underneath.\n\n---\n\n## Install\n\n```bash\ngit clone https://github.com/FlutterSmith/bulls-and-cows-solver.git\ncd bulls-and-cows-solver\npip install -r requirements.txt\n```\n\nRequires Python 3.10+.\n\n---\n\n## Usage\n\n### Watch the solver crack a random secret\n\n```bash\npython main.py auto\n```\n\nOr hand it a specific secret:\n\n```bash\npython main.py auto --secret 7392 --delay 0.3\n```\n\n### Let the solver guess your secret\n\n```bash\npython main.py solve\n```\n\nPick a 4-digit secret with unique digits, then type the bulls/cows after each of my guesses (`2 1`, `1 0`, etc.).\n\n### You play against the solver\n\n```bash\npython main.py play\n```\n\n### Benchmark\n\n```bash\npython main.py benchmark --limit 500\n```\n\nRun `--limit 0` to benchmark all 5040 secrets. Takes a minute or two on the first run; subsequent runs in the same process are instant thanks to the cache.\n\n---\n\n## Algorithm\n\nThe solver keeps track of the **candidate pool** — every secret still consistent with every scored guess so far. On each turn it does this:\n\n1. **For every possible guess** `g` (all 5040 unique-digit strings), simulate scoring `g` against every remaining candidate, and group them by the resulting `(bulls, cows)` score.\n2. Each group represents the candidates that would remain if that score came back. The **largest** group is the worst-case outcome for that guess.\n3. Pick the guess whose worst-case group is **smallest**. That's minimax.\n4. Tiebreak: prefer the guess with higher information entropy across the groups; among equal-entropy guesses, prefer one still in the candidate pool (so it could win outright).\n\nThe very first guess is hardcoded to `0123` because turn 1 always sees the full 5040-secret pool, and `0123` is a proven strong opener for 4-unique-digit Bulls and Cows. Turn 1 minimax would give the same answer but cost ~5 seconds — skipping the computation is purely an optimization.\n\n### Why a cache?\n\nMinimax is `O(|guesses| × |candidates|)` per turn. Without the cache, the full 5040-secret benchmark would re-run minimax on every single game, even though many games share the same mid-game candidate sets. Keying the cache on the `frozenset` of remaining candidates means the solver computes each distinct pool exactly once — typical benchmark runs populate ~100 cache entries total.\n\n---\n\n## Project layout\n\n```\nbulls-and-cows-solver/\n├── main.py         # CLI entry point, argparse, mode dispatch\n├── game.py         # scoring, validation, candidate generation\n├── solver.py       # Knuth minimax with cache and entropy tiebreak\n├── display.py      # rich terminal UI — banner, tables, panels\n├── docs/           # web app (deployed to GitHub Pages)\n│   ├── index.html\n│   ├── styles.css\n│   ├── solver.js   # JS port of the Python solver\n│   └── app.js      # UI state machine, animations, confetti\n├── requirements.txt\n├── LICENSE\n└── README.md\n```\n\nEach module has a single responsibility and none is over ~300 lines.\n\n## Web app\n\nThe `docs/` folder is a zero-build, single-page web app. Animations include:\n\n- Animated aurora gradient background with floating blobs\n- Glass-morphism cards with backdrop blur\n- Candidate pool counter that animates down as the solver eliminates possibilities\n- Guess history timeline with slide-in cards and colored bull/cow chips\n- Top-5 moves panel with entropy bars\n- Flip animation on each new guess\n- Confetti burst + gradient victory panel on solve\n\nTo run locally:\n\n```bash\ncd docs \u0026\u0026 python -m http.server 8765\n```\n\nThen open `http://localhost:8765`.\n\n---\n\n## Terminal preview\n\n```\n─────────────────────────────────── turn 3 ────────────────────────────────────\nturn 3 · candidate pool: 64 possibilities remaining\n                     Top candidate moves\n┌──────┬───────┬────────────┬────────────────┬───────────────┐\n│ rank │ guess │ worst case │ entropy (bits) │ still viable? │\n├──────┼───────┼────────────┼────────────────┼───────────────┤\n│    1 │ 6730  │      12/64 │           3.14 │      yes      │\n│    2 │ 6830  │      12/64 │           3.14 │      yes      │\n│    3 │ 7630  │      12/64 │           3.14 │      yes      │\n│    4 │ 7830  │      12/64 │           3.14 │      yes      │\n│    5 │ 2390  │      14/64 │           3.00 │      yes      │\n└──────┴───────┴────────────┴────────────────┴───────────────┘\n\n  play -\u003e 6730   result -\u003e 0 bulls, 2 cows\n```\n\n---\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluttersmith%2Fbulls-and-cows-solver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffluttersmith%2Fbulls-and-cows-solver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluttersmith%2Fbulls-and-cows-solver/lists"}