feat(792-3): run_line · B09 산근 셈이 엔진 새 의미를 따름 — 네 길 같은 금액

- master_cut: 엔진 답 덧칸 `셈법`(새 칸 뗀 작은 로직) · `plain(got, gone)` 이 셈법 있으면 줄 자리 · 합밖 · 단계 · 블록 끝전 · 조정 그대로(켜쌓기율 · 별도계상 뒤 다시 버림이 큰나머지 · 조정을 덮던 흠) · `kept`
- M02_Labor_Doc: run_line 답이 단계 · 셈법을 넘김 · drop_apart 가 plain 에 뺄 줄 차례를 줌(686 줄 · 늘지 않음)
- 새 B09_Estimation_Sangeun_Sum: 산근 풀이 · 산근 글이 새 의미 로직만 엔진 규칙(표시 · 줄 자리 · 합밖 · 번지 · 단계 · 끝전 · 조정) · 옛 로직 = Q ROUND 2 · ROUNDDOWN 1 · 0 그대로
- B09 산근 글: 로직 줄(중기 세 줄) 금액을 줄 하나로 묶어 차례를 호표와 맞춤(합 같음)
- 지킴 시험 test_792_3_engine_paths: 견본 넷(봉화 · 소광 · 영월 · 임도) + 단위 로직 = 엔진 · M02 SK · SC 한 줄 · B09 산근(글 계 포함) 같은 금액 · 다시 버림 셈법 지킴
- test_791_1: 견본 넷을 만들기 함수로 떼어 냄(같은 기대)
- test_222_1 낡은 기대 셋 고침: 751-3 끝수 뒤 별도계상 뺀 기준 = 남은 줄 비목 합 원 버림(소수 없음) · 옛 기대는 「원 버린 기준 − 소수 재료 금액」이라 0.6 원 어긋남
- test_145_1: 작업량 Q 이름 규칙이 B09_Estimation_Sangeun_Sum 으로 옮김

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-05 18:04:11 +09:00
co-authored by Claude Opus 5.5
parent d26f7a7e1a
commit a0bcf5b48a
10 changed files with 356 additions and 52 deletions
+33 -9
View File
@@ -133,7 +133,7 @@ def engine(master, ref: str, got: dict, depth: int = 0) -> dict:
# 중간 = 덧줄이 본 값(버린 줄 합 · 덧줄 값 · `줄`) — 시험 계산 중간 칸
return {**got, "줄": lines, **costs, "계": sum(costs.values()), "중간": env}
costs = settle(logic, total)
more = {"단계": ms.steps(logic, lines)}
more = {"단계": ms.steps(logic, lines), "셈법": ms.rule(logic)}
return {**got, "줄": lines, **costs, "계": sum(costs.values()), "중간": env, **more}
@@ -150,17 +150,41 @@ def settle(logic: dict, total: dict) -> dict:
return {k: down(v, 0) for k, v in costs.items()}
def plain(got: dict) -> dict:
def kept(got: dict) -> dict:
"""`run_line` 이 엔진 답에서 그대로 넘기는 덧칸(792-3) — 단계 · 셈법."""
return {k: got[k] for k in ("단계", "셈법") if k in got}
def plain(got: dict, gone=()) -> dict:
"""로직 줄 답(`run_line` 꼴 `{기준, 줄, 재료}`)을 줄만 다시 버림 —
켜쌓기율 곱 · 별도계상 뺀 뒤 · 기준 = 남은 줄 비목 합 ROUNDDOWN 0."""
켜쌓기율 곱 · 별도계상 뺀 뒤(`gone` = 뺄 줄 차례) · 기준 = 남은 줄 비목 합 ROUNDDOWN 0 ·
답 `셈법`(791-1 새 의미 로직) = 줄 자리 · 합밖 · 단계 · 블록 끝전 · 조정 그대로(`settle`)."""
if not got.get("기준"):
return got
rule = got.get("셈법")
places = [x.get("자리") for x in ms.items(rule)] if rule else []
skip = set(gone) | (ms.skipped(rule) if rule else set())
def at(n):
return places[n] if isinstance(n, int) and 0 <= n < len(places) else None
lines, total = [], dict.fromkeys(COSTS, Decimal(0))
for line in got.get("줄") or []:
cut, money = _parts(dict(line.get("비목") or {}))
for n, line in enumerate(got.get("줄") or []):
cut, money = _parts(dict(line.get("비목") or {}), at(n))
for k, v in cut.items():
total[k] += Decimal(str(v or 0))
total[k] += 0 if n in skip else Decimal(str(v or 0))
lines.append({**line, "비목": cut, "금액": money})
mats = [{**m, "금액": down(m.get("금액"), 1)} for m in got.get("재료") or []]
base = {k: down(v, 0) for k, v in total.items()}
return {**got, "줄": lines, "재료": mats, "기준": {**base, "계": sum(base.values())}}
mats = [{**m, "금액": _line(m.get("금액"), at(m.get("차례")))} for m in got.get("재료") or []]
kept = [x for n, x in enumerate(lines) if n not in gone]
if not rule:
base = {k: down(v, 0) for k, v in total.items()}
return {**got, "줄": kept, "재료": mats, "기준": {**base, "계": sum(base.values())}}
base = settle(rule, total)
steps = ms.steps(rule, [{} if n in gone else x for n, x in enumerate(lines)])
return {
**got,
"줄": kept,
"재료": mats,
"기준": {**base, "계": sum(base.values())},
"단계": steps,
}
@@ -33,6 +33,17 @@ def uses(row: dict) -> bool:
return any(k in row for k in ROW_KEYS) or any(k in x for x in items(row) for k in LINE_KEYS)
def rule(row: dict) -> dict:
"""셈법(792-3) — 새 의미 칸만 뗀 작은 로직 꼴(이 모듈 · `master_cut.settle` 이 읽음) ·
엔진 답 `셈법` 으로 실어 켜쌓기율 · 별도계상 뒤 다시 버림(`master_cut.plain`)이 씀."""
keep = ("이름", *LINE_KEYS)
lines = {
k: [{x: one[x] for x in keep if x in one} for one in row.get(k, [])]
for k in ("호표", "덧줄")
}
return {**lines, **{k: row[k] for k in (*ROW_KEYS, "끝수") if k in row}}
def shown(step: dict, value):
"""중간 `표시` = 값을 n 자리 반올림해 뒤 줄에 넘김(STmate `X = 식 =`)."""
if step.get("표시") is None or not isinstance(value, Decimal):