testsAndMisc/python_pkg/puzzle_solver/main.py

110 lines
3.5 KiB
Python
Raw Normal View History

2026-03-16 19:49:52 +01:00
"""CLI for the sliding-square puzzle solver.
Usage
-----
# 1) Parse a screenshot → JSON (review & hand-edit if needed)
python puzzle_solver/main.py parse screenshot.png -o puzzle.json
# 2) Solve from JSON
python puzzle_solver/main.py solve puzzle.json
# 3) One-shot: parse + solve (skip manual review)
python puzzle_solver/main.py run screenshot.png
# 4) Draw debug overlay showing detected squares
python puzzle_solver/main.py debug screenshot.png -o debug.png
"""
from __future__ import annotations
import argparse
import json
from pathlib import Path
import sys
from python_pkg.puzzle_solver.parse_image import draw_debug, parse_image, save_puzzle
from python_pkg.puzzle_solver.solver import Puzzle, print_puzzle, print_solution, solve
2026-03-16 19:49:52 +01:00
def cmd_parse(args: argparse.Namespace) -> None:
"""Parse a screenshot into editable puzzle JSON."""
puzzle = parse_image(args.image, threshold=args.threshold)
out = args.output or args.image.rsplit(".", 1)[0] + "_puzzle.json"
save_puzzle(puzzle, out)
if puzzle.get("notes"):
for _n in puzzle["notes"]:
pass
def cmd_solve(args: argparse.Namespace) -> None:
"""Solve a puzzle from a JSON file."""
with Path(args.puzzle).open() as f:
data = json.load(f)
puzzle = Puzzle.from_json(data)
print_puzzle(puzzle)
moves = solve(puzzle)
if moves is None:
sys.exit(1)
print_solution(puzzle, moves)
def cmd_run(args: argparse.Namespace) -> None:
"""Parse a screenshot and solve in one shot."""
data = parse_image(args.image, threshold=args.threshold)
if data.get("notes"):
for _n in data["notes"]:
pass
puzzle = Puzzle.from_json(data)
print_puzzle(puzzle)
moves = solve(puzzle)
if moves is None:
out = args.image.rsplit(".", 1)[0] + "_puzzle.json"
save_puzzle(data, out)
sys.exit(1)
print_solution(puzzle, moves)
def cmd_debug(args: argparse.Namespace) -> None:
"""Draw a debug overlay showing detected square types."""
data = parse_image(args.image, threshold=args.threshold)
out = args.output or args.image.rsplit(".", 1)[0] + "_debug.png"
draw_debug(args.image, data, out)
from collections import Counter
counts = Counter(sq["type"] for sq in data["squares"])
for _t, _n in counts.most_common():
pass
def main() -> None:
"""Entry point for the puzzle solver CLI."""
ap = argparse.ArgumentParser(description="Sliding-square puzzle solver")
sub = ap.add_subparsers(dest="command", required=True)
p_parse = sub.add_parser("parse", help="Parse screenshot → puzzle JSON")
p_parse.add_argument("image")
p_parse.add_argument("-o", "--output", help="Output JSON path")
p_parse.add_argument("-t", "--threshold", type=int, default=55)
p_solve = sub.add_parser("solve", help="Solve puzzle from JSON")
p_solve.add_argument("puzzle", help="Puzzle JSON file")
p_run = sub.add_parser("run", help="Parse + solve in one shot")
p_run.add_argument("image")
p_run.add_argument("-t", "--threshold", type=int, default=55)
p_debug = sub.add_parser("debug", help="Draw debug overlay on image")
p_debug.add_argument("image")
p_debug.add_argument("-o", "--output", help="Output image path")
p_debug.add_argument("-t", "--threshold", type=int, default=55)
args = ap.parse_args()
{"parse": cmd_parse, "solve": cmd_solve, "run": cmd_run, "debug": cmd_debug}[
args.command
](args)
if __name__ == "__main__":
main()