feat(800-2): 수식 변수 정의 영역 서버 — 정의 칸(안 탄 갈래 뺌 · 겹침 합침 · 열쇠 글 0) · 새 기호 연결 고침 · 후보 길
- 수식 응답 새 칸 정의 — 만약 탄 갈래 표지 걸림 그대로 · 같은 기호 한 줄 · 연결 사람 말 · 값 · 단위 · DB 열쇠 없음 - 고침 할일 연결(입력 · 표 · 요소 · 로직 · 상수) · 모르는 기호 까닭 · 후보 길 M01 · M02 equation/links - 낡은 시험 test_796_1 「모르는 이름」 → 「모르는 기호」(까닭 문구 바뀜) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""수식 변수 정의 영역(PLAN 800-2 · 요구 660-2 · 3 · 6) — 수식 나무 → 오른쪽 「변수 정의」 목록.
|
||||
|
||||
줄 구분 없이 한 목록 · 같은 변수는 한 번만(겹침 합침) · 기호 : 국문 이름 — 연결(입력 · 표 찾기 ·
|
||||
요소 · 로직 · 계산을 사람 말로) · 값 · 단위 · DB 열쇠 글은 담지 않음.
|
||||
지금 고른 옵션 갈래만 — 만약의 탄 갈래 표지 `걸림`(1 참 · 2 거짓 · 0 모름 = 둘 다)을 그대로 씀(새 판정 없음) ·
|
||||
`안씀` = 어느 식에도 안 쓰이는 입력(지울 수 있음) · 쓰는 변수 지움 막기는 `master_equation_edit._drop`.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
CAT = {"LB": "인력", "EQ": "기계", "MT": "재료", "MO": "재료"}
|
||||
WHAT = {
|
||||
"입력": "입력",
|
||||
"중간": "계산",
|
||||
"결과": "계산 결과",
|
||||
"찾기": "표 찾기",
|
||||
"요소": "요소",
|
||||
"블록": "로직 부르기",
|
||||
}
|
||||
|
||||
|
||||
def visible(node: dict | None, out: list[dict]) -> list[dict]:
|
||||
"""나무에서 보이는(탄 갈래) 변수 · 블록 마디를 차례대로."""
|
||||
if not isinstance(node, dict):
|
||||
return out
|
||||
kind = node.get("꼴")
|
||||
if kind in ("변수", "블록"):
|
||||
out.append(node)
|
||||
elif kind == "조건":
|
||||
visible(node.get("조건"), out)
|
||||
for key, at in (("참", 1), ("거짓", 2)):
|
||||
if node.get("걸림") in (0, None, at):
|
||||
visible(node.get(key), out)
|
||||
else:
|
||||
for key in ("좌", "우", "안", "위", "아래"):
|
||||
visible(node.get(key), out)
|
||||
for arg in node.get("인자") or []:
|
||||
visible(arg, out)
|
||||
return out
|
||||
|
||||
|
||||
def _link(node: dict, spec: dict | None, leaf: dict | None) -> str:
|
||||
"""연결 설명 — 사람 말(열쇠 · 값 · 단위 없음)."""
|
||||
kind = node.get("갈래") or ("블록" if node.get("꼴") == "블록" else "")
|
||||
if kind == "입력":
|
||||
return "입력 — " + ("옵션에서 고름" if (spec or {}).get("고르기") else "직접 적음")
|
||||
if kind == "중간" and leaf is not None and leaf is not node:
|
||||
return _link(leaf, None, None)
|
||||
if kind == "찾기":
|
||||
cond = " · ".join(f"{k} = {v}" for k, v in (node.get("조건식") or {}).items())
|
||||
head = f"표 찾기 — {node.get('표이름') or '표'}"
|
||||
return head + (f" · 조건 {cond}" if cond else "") + f" · 칸 {node.get('칸') or ''}".rstrip()
|
||||
if kind == "요소":
|
||||
pick = node.get("고르기")
|
||||
if isinstance(pick, dict):
|
||||
return "요소 · 재료 고름 — " + " · ".join(str(v) for v in pick.values() if v)
|
||||
return f"요소 · {CAT.get(str(node.get('식') or '')[:2], '단가')} — {node.get('이름') or ''}"
|
||||
if kind == "블록":
|
||||
return f"로직 부르기 — {node.get('이름') or ''}"
|
||||
return WHAT.get(kind, "계산") + (" — 수식 영역의 식" if kind in ("중간", "결과") else "")
|
||||
|
||||
|
||||
def definitions(lines: list[dict], row: dict, rows: list[dict], unused) -> list[dict]:
|
||||
"""보이는 식의 변수 정의 목록 — `rows` = 변수 표 · `unused(열쇠)` = 어느 식에도 안 쓰임."""
|
||||
specs = {str(s.get("이름")): s for k in ("입력", "중간") for s in row.get(k) or []}
|
||||
table = {v["열쇠"]: v for v in rows}
|
||||
got: dict[str, dict] = {}
|
||||
leaf: dict[str, dict] = {}
|
||||
for line in lines:
|
||||
head, tree = line.get("결과"), line.get("이름식")
|
||||
if line.get("갈래") in ("중간", "결과") and isinstance(tree, dict):
|
||||
if tree.get("갈래") in ("찾기", "요소") or tree.get("꼴") == "블록": # 한 마디 식
|
||||
leaf[str(line.get("열쇠"))] = tree
|
||||
found = ([head] if head and line.get("갈래") in ("중간", "결과") else []) + visible(
|
||||
tree, []
|
||||
)
|
||||
for node in found:
|
||||
key = str(node.get("열쇠") or "")
|
||||
if key and key not in got and node.get("갈래") in (*WHAT, "합", None):
|
||||
got[key] = node
|
||||
out: dict[tuple, dict] = {} # 같은 기호 글 = 같은 정의(겹침 합침) — 연결은 모아 보임
|
||||
for key, node in got.items():
|
||||
mine = table.get(key)
|
||||
look = mine or node
|
||||
kind = node.get("갈래") or "블록"
|
||||
if kind == "합":
|
||||
kind = "결과" if key == "결과" else "중간"
|
||||
if key.startswith("줄."): # 위 호표 줄 금액 부름
|
||||
name, link = key[2:].strip("'"), f"호표 줄 금액 — {key[2:].strip(chr(39))}"
|
||||
else:
|
||||
link = _link({**node, "갈래": kind}, specs.get(key), leaf.get(key))
|
||||
name = (look.get("이름") or key) if mine else look.get("이름") or ""
|
||||
name = node.get("칸") or name if kind == "찾기" else name
|
||||
one = {
|
||||
"열쇠": key if mine else "",
|
||||
"기호": (look.get("기호") or name) if not key.startswith("줄.") else name,
|
||||
"위": look.get("위") or "",
|
||||
"아래": look.get("아래") or "",
|
||||
"이름": name,
|
||||
"갈래": kind,
|
||||
"연결": [link],
|
||||
"고침": bool(mine),
|
||||
}
|
||||
same = out.setdefault((one["기호"], one["위"], one["아래"]), one)
|
||||
if same is not one:
|
||||
same["연결"] += [x for x in one["연결"] if x not in same["연결"]]
|
||||
if one["열쇠"] and not same["열쇠"]:
|
||||
same |= {k: one[k] for k in ("열쇠", "이름", "갈래", "고침")}
|
||||
out = list(out.values())
|
||||
seen = {d["열쇠"] for d in out}
|
||||
for v in rows: # 어느 식에도 안 쓰이는 입력 — 지울 수 있게
|
||||
if v["갈래"] == "입력" and v["열쇠"] not in seen and unused(v["열쇠"]):
|
||||
out.append(
|
||||
{
|
||||
"열쇠": v["열쇠"],
|
||||
"기호": v["기호"],
|
||||
"위": v["위"],
|
||||
"아래": v["아래"],
|
||||
"이름": v["이름"],
|
||||
"갈래": "입력",
|
||||
"연결": ["입력 — 쓰는 식 없음"],
|
||||
"고침": True,
|
||||
"안씀": True,
|
||||
}
|
||||
)
|
||||
return out
|
||||
Reference in New Issue
Block a user