feat(746-1): 불러오기 고름 대기 후보 블록 줄비교 · 못옮김 · 기계 줄 M01 요소 후보 · 단위 별칭 hr = 시간 · 개소 = 개
- 고름 대기 후보 앞 셋에 그 기초와 줄마다 견준 `줄비교`(같음 · 품다름 · 엑셀만 · 기초만 · 1 단위 품 · 못옮김) — 고르면 만드는 SK 와 같은 셈(`_Plan` 기록) · 판정 · 순위 · 미리 고름 그대로 - 못옮김 `후보` · 안 이은 기계 줄 `남은줄[].후보` = M01 요소 셋(새 `M02_Hopyo_Elem` — 이름 · 규격 점수 › 엑셀 단가 가까운 차례) - 단위 모듈 짝(master_unit.py ↔ master_unit_swap.ts) 별칭 hr = 시간 · 개수 묶음에 개소 — 거울 시험 사례 셋 더함 - 실측(여덟 파일): 고름 대기 89 중 1위 줄비교 72(셋 중 하나 82) · 골든 1위 163 그대로 · 판정 수 그대로 · 개 ↔ 개소 1 블록 견줌 풀림 · 못옮김 후보 8/9 · 기계 줄 후보 32/32 · M01 로직 3,992 값 전후 같음 - 새 지킴 시험 test_746_1_hopyo_compare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
조합 알약 배(`M01_MasterData_Store_Combo`) · 엑셀 맞춤 배(`M02_Hopyo_Ours` · `_Match`) ·
|
||||
표 기준배(`master_basis`) · 계산서 줄 환산 근거(714-1). 서버 단독(③) — TS 는 서버가 준 글만 씀.
|
||||
- 단 SK 단위 바꿈 환산(`swap` · 728-1)은 짝(①) — `A00_Common/master_unit_swap.ts` · 거울 시험 `test_728_1_unit_swap.py`.
|
||||
- 개수 묶음(개 · EA · 본 · 매) = 1 : 1 같은 성격 · 조 · 세트는 묶음 밖(한 조 = 여럿).
|
||||
- 개수 묶음(개 · EA · 본 · 매 · 개소) = 1 : 1 같은 성격 · hr = 시간(별칭) · 조 · 세트는 묶음 밖(한 조 = 여럿).
|
||||
- 부피 ↔ 무게 = 단위중량 표 CC000337 에서 고른 줄(`unit_weight`)을 받을 때만 · 기본 줄 없음
|
||||
(사용자 확인 거리) · 밀도(kg ↔ ℓ) · ㎾h 등은 환산 없이 경고 글만.
|
||||
"""
|
||||
@@ -17,7 +17,16 @@ import unicodedata
|
||||
from decimal import Decimal
|
||||
|
||||
# 맞대기 꼴(`plain`) 별칭 — NFKC · 소문자 · 빈칸 없앤 뒤
|
||||
ALIAS = {"ea": "개", "ton": "톤", "t": "톤", "l": "ℓ", "리터": "ℓ", "set": "조", "세트": "조"}
|
||||
ALIAS = {
|
||||
"ea": "개",
|
||||
"ton": "톤",
|
||||
"t": "톤",
|
||||
"l": "ℓ",
|
||||
"리터": "ℓ",
|
||||
"set": "조",
|
||||
"세트": "조",
|
||||
"hr": "시간",
|
||||
}
|
||||
# 보이는 꼴(`shown`) 별칭 — 표 기준 · 결과단위 분모(원문 기호 ㎡ · ㎥ 그대로)
|
||||
SHOWN = {"ea": "개", "톤": "ton", "t": "ton", "㎞": "km", "hr": "시간", "min": "분", "㎏": "kg"}
|
||||
# 같은 성격 — {성격: {맞대기 단위: 기준 단위 몇 배}}
|
||||
@@ -26,7 +35,7 @@ UNITS = {
|
||||
"길이": {"mm": 1, "cm": 10, "m": 1000, "km": 1000000},
|
||||
"넓이": {"cm2": 1, "m2": 10000},
|
||||
"부피": {"cm3": 1, "ℓ": 1000, "m3": 1000000},
|
||||
"개수": {"개": 1, "본": 1, "매": 1},
|
||||
"개수": {"개": 1, "본": 1, "매": 1, "개소": 1},
|
||||
}
|
||||
_SCALE = {u: (kind, n) for kind, group in UNITS.items() for u, n in group.items()}
|
||||
WEIGHT_TABLE = "CC000337" # 건설품셈 공통 1-2-4 재료의 단위중량(㎏/㎥)
|
||||
|
||||
@@ -40,6 +40,9 @@ CASES = [
|
||||
["톤", "㎥", 1600, None],
|
||||
["10㎥", "kg", 2400, None],
|
||||
["조", "개", None, None],
|
||||
["hr", "시간", None, None], # 746-1 별칭
|
||||
["개소", "개", None, None],
|
||||
["10개소", "개", None, None],
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
"""746-1 지킴 — 불러오기 고름 대기 후보 블록 줄비교 · 못옮김 · 기계 줄 M01 요소 후보 · 단위 별칭(요구 585).
|
||||
|
||||
고름 대기 블록(북부청 임도 실물 엑셀 · 읽기만) = 판정 · 후보 차례 그대로 + 앞 셋 `줄비교`(같음 · 품다름 · 엑셀만 ·
|
||||
기초만 · 엑셀 품 = 엑셀 지문 품) · 그 기초로 고르면 만드는 SK 와 같은 셈(더한줄 · 뺀줄 수) · 요소 후보 셋 ·
|
||||
hr = 시간 · 개소 = 개(같은 성격). 쓰기 없음 · master_data 원본 그대로.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from M01_MasterData import M01_MasterData_Store as m01
|
||||
from M02_MasterTemplete import M02_Hopyo_Elem as elem
|
||||
from M02_MasterTemplete import M02_Hopyo_Finger as finger
|
||||
from M02_MasterTemplete import M02_Hopyo_Match as hm
|
||||
from M02_MasterTemplete import M02_Hopyo_Ours as ours
|
||||
from M02_MasterTemplete import M02_Hopyo_Sangeun as sg
|
||||
from M02_MasterTemplete import M02_Hopyo_SkLink as sklink
|
||||
from M02_MasterTemplete import M02_Hopyo_SkPatch as skp
|
||||
from M02_MasterTemplete import M02_Hopyo_Verdict as verdict
|
||||
from resources.tester import helper_m02_hopyo_golden as golden
|
||||
from resources.tester.test_m02_hopyo_excel import master_hash
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "resources/master_data/scripts"))
|
||||
import master_unit as mu # noqa: E402
|
||||
|
||||
FILE, BLOCK = "북부청임도", 38 # 고름 대기 · 1위와 견줌 되는 블록
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def wait():
|
||||
before = master_hash()
|
||||
if not ours.ready():
|
||||
ours.build()
|
||||
blocks, first = sg.calls(golden.read(FILE))
|
||||
block, line = blocks[BLOCK], first[BLOCK]
|
||||
entry = verdict.block(block, line, hm.targets())
|
||||
got = skp.plan(entry, block, line, m01.loaded()[1])
|
||||
yield {"entry": entry, "block": block, "line": line, "plan": got}
|
||||
assert master_hash() == before
|
||||
|
||||
|
||||
def test_판정_후보_차례_그대로_앞_셋_줄비교(wait):
|
||||
got, entry = wait["plan"], wait["entry"]
|
||||
assert got["갈래"] == skp.WAIT
|
||||
assert [c["로직"] for c in got["후보"]] == [c["로직"] for c in entry["후보"][: len(got["후보"])]]
|
||||
assert all("줄비교" in c for c in got["후보"][: skp.COMPARE])
|
||||
assert all("줄비교" not in c for c in got["후보"][skp.COMPARE :])
|
||||
first = got["후보"][0]["줄비교"]
|
||||
assert first and first["줄"]
|
||||
assert sum(first["수"].values()) == len(first["줄"])
|
||||
assert {x["꼴"] for x in first["줄"]} <= set(skp.LOOKS)
|
||||
|
||||
|
||||
def test_줄비교_엑셀_품_지문_그대로_고르면_같은_셈(wait):
|
||||
first = wait["plan"]["후보"][0]
|
||||
rows = first["줄비교"]["줄"]
|
||||
efp = finger.excel(wait["block"], wait["line"])
|
||||
labor = {t: x["품"] for t, x in efp["인력"].items() if x.get("품")}
|
||||
for x in rows:
|
||||
if x["갈래"] == "인력":
|
||||
assert x["엑셀"] == pytest.approx(labor.get(x["이름"]) or None), x
|
||||
assert x["단위"] == "인"
|
||||
if x["꼴"] == "같음":
|
||||
assert x["엑셀"] == pytest.approx(x["기초"], rel=0.01), x
|
||||
if x["꼴"] == "엑셀만":
|
||||
assert x["엑셀"] and not x["기초"]
|
||||
if x["꼴"] == "기초만":
|
||||
assert x["기초"] and not x["엑셀"]
|
||||
made = skp.plan(
|
||||
wait["entry"], wait["block"], wait["line"], m01.loaded()[1], {"로직": first["로직"]}
|
||||
)
|
||||
gone = sum(1 for x in rows if x["꼴"] == "기초만" and x["갈래"] != "자재")
|
||||
assert len(made["뺀줄"]) == gone
|
||||
assert made["못옮김"] == first["줄비교"]["못옮김"]
|
||||
|
||||
|
||||
def test_요소_후보_셋():
|
||||
got = elem.labor("작업반장")
|
||||
assert 0 < len(got) <= elem.TOP and {x["이름"] for x in got[:2]} == {"작업반장"}
|
||||
assert all(x["키"].startswith("LB") and x["단가"] for x in got)
|
||||
got = elem.machines("굴착기 0.7㎥")
|
||||
assert got and all(x["키"].startswith("EQ") and "굴착기" in x["이름"] for x in got)
|
||||
got = elem.materials("시멘트", "kg")
|
||||
assert got and all(x["키"].startswith("MT") for x in got) and len(got) <= elem.TOP
|
||||
lost = {"갈래": "기계", "이름": "굴착기", "규격": "0.7"}
|
||||
assert elem.lost(lost)[0]["키"].startswith("EQ")
|
||||
|
||||
|
||||
def test_안_이은_기계_줄_EQ_후보():
|
||||
line = {"차례": 0, "이름": "굴착기(타이어)", "규격": "0.7㎥", "단위": "hr", "갈래": "기계"}
|
||||
got = sklink.left(line, None)
|
||||
assert got["까닭"] == sklink.WHY["기계"]
|
||||
assert got["후보"] and all(x["키"].startswith("EQ") for x in got["후보"])
|
||||
|
||||
|
||||
def test_단위_별칭_hr_시간_개소_개():
|
||||
assert mu.plain("hr") == mu.plain("시간") and mu.plain("HR") == "시간"
|
||||
assert mu.same_kind("개소", "개") and mu.swap("개소", "개")["배"] == 1
|
||||
assert mu.swap("10개소", "개")["배"] == 10 and mu.swap("hr", "시간")["계수"] is None
|
||||
assert mu.swap("조", "개소")["계수"] == "사용자" # 조는 묶음 밖 그대로
|
||||
Reference in New Issue
Block a user