feat(z01·b09): 코드에 박혀 있던 기계 작업량 밑값을 마스터로 꺼냄 — 새 자료 data_machine_productivity(불도저 속도 25 · 삽날 10 · 덤프 운반·적재 밑값 9 · 재료별 3) · B09 는 그 파일을 읽음(값은 한 칸도 안 바꿈 · 원문 pum_const C0426·C0427 대조 시험) · Z01 kind machine_productivity 로 관리자가 고칠 수 있게 · 식은 값이 아니라 로직이라 코드에 남김 · 이름표에 없는 새 자료는 폴더에서 찾음(사용자 원칙 「마스터 = 관리자가 제어할 값 · 코드 안에 있으면 안 됨」 · 브레인)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
"""B09 — 기계 작업량 **밑값**을 마스터에서 읽는다(2026-09-16 사용자 원칙 · 브레인 지시).
|
||||
|
||||
마스터 = 관리자가 제어할 값 · **코드 안에 있으면 안 됨.**
|
||||
|
||||
그동안 불도저 속도·삽날 용량(건설품셈 8-2-1)과 덤프 운반·적재 식 계수(산림품셈 10-12)가
|
||||
코드 상수로 박혀 있었다. 값은 그대로 두고 자리만 옮긴다 —
|
||||
`resources/data_machine_productivity/machine_productivity_<판>.json`.
|
||||
⚠ **식은 여기 없다.** `Q = n·q·f·E` 같은 식은 값이 아니라 로직이라 계산 모듈에 남는다.
|
||||
⚠ 옮기면서 값을 하나도 안 바꿨다 — 원문(pum_const C0426·C0427)과의 대조는 시험이 지킨다.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from decimal import Decimal
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
DATA_DIR = Path(__file__).resolve().parent.parent / "resources" / "data_machine_productivity"
|
||||
PREFIX = "machine_productivity_"
|
||||
|
||||
|
||||
class MachineProductivityDataError(FileNotFoundError):
|
||||
"""밑값 판이 없다 — 지어내지 않고 멈춘다."""
|
||||
|
||||
|
||||
@lru_cache(maxsize=2)
|
||||
def _read(path: str, _mtime_ns: int) -> dict[str, Any]:
|
||||
return json.loads(Path(path).read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def load() -> dict[str, Any]:
|
||||
"""끝 판 한 벌(이름 차례)."""
|
||||
found = sorted(DATA_DIR.glob(PREFIX + "*.json")) if DATA_DIR.is_dir() else []
|
||||
if not found:
|
||||
raise MachineProductivityDataError(f"기계 작업량 밑값 판이 없습니다: {DATA_DIR}")
|
||||
return _read(str(found[-1]), found[-1].stat().st_mtime_ns)
|
||||
|
||||
|
||||
def records(variable: str) -> list[dict[str, Any]]:
|
||||
return load()["variables"][variable]["records"]
|
||||
|
||||
|
||||
def dozer_speeds() -> dict[str, dict[Decimal, dict[int, tuple[Decimal, Decimal]]]]:
|
||||
"""{무한궤도·타이어: {규격(ton): {단: (전진, 후진)}}} — 후진이 원문에 없는 단은 담기지 않는다."""
|
||||
out: dict[str, dict[Decimal, dict[int, tuple[Decimal, Decimal]]]] = {}
|
||||
for row in records("dozer_speed"):
|
||||
track = out.setdefault(row["track"], {})
|
||||
gears = track.setdefault(Decimal(row["tonnage_ton"]), {})
|
||||
gears[int(row["gear"])] = (
|
||||
Decimal(row["forward_m_per_min"]),
|
||||
Decimal(row["reverse_m_per_min"]),
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
def dozer_blades() -> dict[tuple[str, Decimal], Decimal]:
|
||||
"""{(무한궤도·타이어, 규격(ton)): 삽날 용량 q˚(㎥)}."""
|
||||
return {
|
||||
(row["track"], Decimal(row["tonnage_ton"])): Decimal(row["blade_m3"])
|
||||
for row in records("dozer_blade")
|
||||
}
|
||||
|
||||
|
||||
def haul_params() -> dict[str, Decimal]:
|
||||
"""덤프 운반·적재 식이 쓰는 밑값(적재 규격 T · 버켓 q · 싸이클 · 주행속도 · 적하·대기·덮개)."""
|
||||
return {row["key"]: Decimal(row["value"]) for row in records("dump_haul")}
|
||||
Reference in New Issue
Block a user