feat(M01): 일위대가 로직 테스트 컨테이너 틀 + 방식 A 질문·답 마법사

- 왼쪽 패널에 「일위대가 로직 테스트」 컨테이너 추가 — 공종 10 개 고르기 + 방식 탭 A·B·C (B·C 는 준비 중)
- 방식 A: 공종 → 조건 질문(한 번에 하나) → 재료·기계 고르기 → 결과 호표 · 식 안 보임 · 저장 없음
- 대상 10 개는 복잡도로 재어 고름(scripts/로직_복잡도_재기.py) · 시험 test_m01_test_container.py

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016WRFJmmhPi4exAzHgPZHMT
This commit is contained in:
2026-09-20 21:34:39 +09:00
co-authored by Claude Sonnet 5
parent 565833bcb8
commit 292568e688
9 changed files with 686 additions and 18 deletions
@@ -0,0 +1,53 @@
"""산림품셈 로직 복잡도 재기 — 입력 수 · 표 찾기 수 · 로직 부르기 · 덧줄 · 재료 가짓수.
사용: python resources/master_data/scripts/로직_복잡도_재기.py [상위 N]
점수 = 입력 + 찾기 + 로직부르기*2 + 덧줄 + 재료 (읽기 전용 · 아무것도 안 씀)
"""
import json
import re
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
FIND = re.compile(r"찾기\(")
CALL = re.compile(r"로직\(")
def measure(row: dict) -> dict:
ho = row.get("호표") or []
text = " ".join(str(h.get("수량", "")) + str(h.get("요소", "")) for h in ho)
text += " ".join(str(m.get("", "")) for m in row.get("중간") or [])
text += " ".join(str(m.get("", "")) for m in row.get("덧줄") or [])
m = {
"입력": len(row.get("입력") or []),
"찾기": len(FIND.findall(text)),
"로직": len(CALL.findall(text)),
"덧줄": len(row.get("덧줄") or []),
"재료": sum(1 for h in ho if h.get("종류") == "재료"),
}
m["점수"] = m["입력"] + m["찾기"] + m["로직"] * 2 + m["덧줄"] + m["재료"]
return m
def main() -> None:
top = int(sys.argv[1]) if len(sys.argv) > 1 else 25
out = []
for f in sorted(ROOT.glob("로직_산림품셈_*.json")):
for row in json.loads(f.read_text(encoding="utf-8"))[""]:
out.append(
{"": row[""], "번호": row["원문번호"], "이름": row["이름"], **measure(row)}
)
out.sort(key=lambda r: -r["점수"])
for r in out[:top]:
print(
r[""],
r["번호"],
r["이름"],
{k: r[k] for k in ("입력", "찾기", "로직", "덧줄", "재료", "점수")},
)
print("", len(out))
if __name__ == "__main__":
main()