"""Entry point: GUI by default, CLI when --cli is passed.""" from __future__ import annotations import argparse import sys from typing import List from .renderer import save_solution from .slabs import SLABS, SLABS_BY_VALUE from .solver import solve def _cli(argv: List[str]) -> int: p = argparse.ArgumentParser( prog="sephiria_inv", description="Optimize Sephiria slab placement and render the result.", ) p.add_argument( "--cli", action="store_true", help="Run in CLI mode (no GUI).", ) p.add_argument( "-s", "--slab", action="append", default=[], help="Slab value to include. Use value (e.g. 'harvesting') with optional ':N' " "multiplier (e.g. 'harvesting:3'). Repeat as needed.", ) p.add_argument( "--slots", type=int, default=34, help="Inventory slot count (18..60).", ) p.add_argument("--seed", type=int, default=None) p.add_argument( "--time-limit", type=float, default=4.0, help="Solver time budget in seconds.", ) p.add_argument( "-o", "--output", default="sephiria_layout.png", help="Output PNG path.", ) p.add_argument( "--list", action="store_true", help="List known slab values and exit.", ) p.add_argument( "--no-download", action="store_true", help="Skip CDN download (text-only render).", ) p.add_argument( "--screenshot", default=None, help="Read slab list from a game screenshot (PNG/JPG).", ) p.add_argument( "--bbox", default=None, help="Required with --screenshot. Pixel bbox of the inventory grid as " "'left,top,right,bottom'.", ) args = p.parse_args(argv) if args.list: for s in SLABS: print(f" {s.value:<16s} {s.ko_label:<6s} ({s.tier})") return 0 basket: List[str] = [] if args.screenshot: if not args.bbox: print("--screenshot 사용 시 --bbox 'l,t,r,b' 가 필요합니다.", file=sys.stderr) return 2 try: l, t, r, b = (int(v) for v in args.bbox.split(",")) except ValueError: print("--bbox 형식: left,top,right,bottom (정수)", file=sys.stderr) return 2 from .screenshot import recognize, recognized_values recs = recognize(args.screenshot, (l, t, r, b), slot_num=args.slots) basket.extend(recognized_values(recs)) print(f"인식된 석판: {len(basket)}개 from screenshot") for raw in args.slab: if ":" in raw: v, n = raw.split(":", 1) try: count = int(n) except ValueError: print(f"잘못된 개수: {raw}", file=sys.stderr) return 2 else: v, count = raw, 1 if v not in SLABS_BY_VALUE: print(f"알 수 없는 석판 value: {v} (use --list)", file=sys.stderr) return 2 basket.extend([v] * count) if not basket: print("최소 하나 이상의 --slab 을 지정하세요.", file=sys.stderr) return 2 sol = solve(basket, slot_num=args.slots, time_limit=args.time_limit, seed=args.seed) save_solution(sol, args.output, download=not args.no_download) print(f"score={sol.score} placed={len(sol.placements)} → {args.output}") return 0 def main(argv: List[str] | None = None) -> int: argv = list(argv if argv is not None else sys.argv[1:]) if "--cli" in argv or "--list" in argv or any(a.startswith("-s") or a.startswith("--slab") for a in argv): return _cli(argv) # Fall back to GUI from .gui import main as gui_main return gui_main() if __name__ == "__main__": raise SystemExit(main())