Merge remote-tracking branch 'origin/sub_laptop_7' into main_laptop_1
This commit is contained in:
@@ -331,7 +331,8 @@ def _rounded(value: Any, r: dict) -> Any:
|
||||
|
||||
|
||||
def _lookup(rule: dict, block: Any, conds: dict) -> tuple[Any, str | None]:
|
||||
"""표에서 찾기 — 같음 · 범위(아래 < 값 ≤ 위 · 빈 끝 열림 · 아래 = 위면 같음) · 맞은 줄 하나."""
|
||||
"""표에서 찾기 — 같음 · 범위(아래 < 값 ≤ 위 · 빈 끝 열림 · 아래 = 위면 같음) · 맞은 줄 하나
|
||||
· 빈 조건 칸 = 무엇이든 · 꺼낼 칸이 빈 줄은 뺌(옛 엔진 find 와 같음 · Rule lookup 과 같음)."""
|
||||
if not isinstance(block, list) or len(block) < 2:
|
||||
return None, "오류"
|
||||
head = [str(h if h is not None else "") for h in block[0]]
|
||||
@@ -343,7 +344,7 @@ def _lookup(rule: dict, block: Any, conds: dict) -> tuple[Any, str | None]:
|
||||
col, want = str(c.get("col")), _cond_of(conds, c.get("from") or {})
|
||||
if col in head:
|
||||
i = head.index(col)
|
||||
tests.append(lambda row, i=i, want=want: _same(row[i], want))
|
||||
tests.append(lambda row, i=i, want=want: row[i] is None or _same(row[i], want))
|
||||
elif col + dv.RANGE_LOW in head and col + dv.RANGE_HIGH in head:
|
||||
lo, hi, x = (
|
||||
head.index(col + dv.RANGE_LOW),
|
||||
@@ -364,13 +365,14 @@ def _lookup(rule: dict, block: Any, conds: dict) -> tuple[Any, str | None]:
|
||||
tests.append(fits)
|
||||
else:
|
||||
return None, "오류"
|
||||
hits = [row for row in block[1:] if all(t(list(row) + [None] * len(head)) for t in tests)]
|
||||
at = head.index(out)
|
||||
rows = [list(r) + [None] * len(head) for r in block[1:]]
|
||||
hits = [r for r in rows if r[at] not in (None, "") and all(t(r) for t in tests)]
|
||||
if not hits:
|
||||
return None, "표에 없는 조건"
|
||||
if len(hits) > 1:
|
||||
return None, "표에 여럿 맞음"
|
||||
value = hits[0][head.index(out)]
|
||||
return (None, "오류") if value is None else (value, None)
|
||||
return hits[0][at], None
|
||||
|
||||
|
||||
def apply_rule(rule: dict, value: Any, conds: dict) -> tuple[Any, str | None]:
|
||||
@@ -463,11 +465,8 @@ def _sheet_of(box: dict, arrived: dict, given: dict) -> dict:
|
||||
for p in func.get("inputs") or []:
|
||||
if str(p.get("cell") or "").strip():
|
||||
port = p.get("port")
|
||||
_place(
|
||||
cells,
|
||||
p["cell"],
|
||||
arrived[port] if arrived.get(port) is not None else given.get(port),
|
||||
)
|
||||
v = arrived[port] if arrived.get(port) is not None else given.get(port)
|
||||
_place(cells, p["cell"], {"식": "NA()"} if v == NA_VALUE else v)
|
||||
for v in func.get("variables") or []:
|
||||
if v.get("cell"):
|
||||
_place(cells, v["cell"], given.get(v.get("name"), v.get("example")))
|
||||
@@ -475,6 +474,7 @@ def _sheet_of(box: dict, arrived: dict, given: dict) -> dict:
|
||||
|
||||
|
||||
REST = "앞 조건이 안 맞아 쉬는 갈래"
|
||||
NA_VALUE = "#N/A" # 함수 칸으로 가는 표 찾기 실패 — 칸에 NA() · 결과 오류일 때만 끊긴 곳(Eval 같음)
|
||||
|
||||
|
||||
def run(lg: dict, values: dict, load: Loader, local: list[dict], stack: list | None = None) -> dict:
|
||||
@@ -486,6 +486,7 @@ def run(lg: dict, values: dict, load: Loader, local: list[dict], stack: list | N
|
||||
errors, breaks, ports, arrived, outputs = [], [], {}, {}, {}
|
||||
blocked: set[str] = set()
|
||||
resting: set[str] = set() # 조건이 안 맞아 쉬는 상자 — Eval 과 같은 뜻
|
||||
late: dict[str, list[dict]] = {} # 함수로 가는 표 찾기 실패 — 결과가 오류일 때만 끊긴 곳
|
||||
cost: dict[str, Any] = {**dict.fromkeys(COSTS, Decimal(0)), "값들": {}}
|
||||
|
||||
def through(ln: dict) -> Any:
|
||||
@@ -503,23 +504,28 @@ def run(lg: dict, values: dict, load: Loader, local: list[dict], stack: list | N
|
||||
conds[f"{p.get('box')}|{p.get('name')}"] = got_v
|
||||
got, why = apply_rule(rule, v, conds)
|
||||
if why:
|
||||
blocked.add(ln["to"].get("box"))
|
||||
if why == "통과 안 됨":
|
||||
resting.add(ln["to"].get("box"))
|
||||
text = f"「{name(src.get('box'))}」 → 「{name(ln['to'].get('box'))}」 {why}"
|
||||
kind = "오류" if why in ("표에 여럿 맞음", "오류") else why
|
||||
to = ln["to"]
|
||||
breaks.append(
|
||||
{
|
||||
"kind": kind,
|
||||
# 무게 — 통과 안 됨 = 쉼 · 나머지 = 문제(Eval CfBreak.level 과 같음)
|
||||
"level": "쉼" if kind == "통과 안 됨" else "문제",
|
||||
"box": to.get("box"),
|
||||
"port": to.get("name"),
|
||||
"link": ln.get("id"),
|
||||
"text": text,
|
||||
}
|
||||
)
|
||||
brk = {
|
||||
"kind": kind,
|
||||
# 무게 — 통과 안 됨 = 쉼 · 나머지 = 문제(Eval CfBreak.level 과 같음)
|
||||
"level": "쉼" if kind == "통과 안 됨" else "문제",
|
||||
"box": to.get("box"),
|
||||
"port": to.get("name"),
|
||||
"link": ln.get("id"),
|
||||
"text": text,
|
||||
}
|
||||
if (
|
||||
rule.get("kind") == "lookup"
|
||||
and boxes.get(to.get("box"), {}).get("kind") == "function"
|
||||
):
|
||||
late.setdefault(to.get("box"), []).append(brk)
|
||||
return NA_VALUE
|
||||
blocked.add(to.get("box"))
|
||||
if why == "통과 안 됨":
|
||||
resting.add(to.get("box"))
|
||||
breaks.append(brk)
|
||||
if why != "통과 안 됨":
|
||||
errors.append(text)
|
||||
return None if why else got
|
||||
@@ -601,6 +607,10 @@ def run(lg: dict, values: dict, load: Loader, local: list[dict], stack: list | N
|
||||
if out.get("round") and _num_of(value) is not None:
|
||||
value = _rounded(value, out["round"])
|
||||
ports[f["id"]] = {out.get("name"): value}
|
||||
if value is None or (isinstance(hit, dict) and "오류" in hit):
|
||||
for brk in late.get(f["id"], []):
|
||||
breaks.append(brk)
|
||||
errors.append(brk["text"])
|
||||
for b in boxes.values(): # 출력 상자 · 원가(Eval 과 같음)
|
||||
if b.get("kind") != "output":
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user