feat(782-1): 건설 공통 1-2-7 운반 기초 — 계수 표 여덟 · 인력운반 로직 셋
- 계수_건설품셈_01장_적용기준.json 1-2-7 표 덧(CC000341~348): 소운반 거리 · 인력운반 기본공식 상수 · 지게운반 t · V · 벽돌운반 · 인력운반(기계설비) 왕복평균속도 · 준비작업시간 · 경사지 환산계수 α · 화물자동차 적재량 — 옛 표 목록이 1-2-5 밑에 붙였던 1-2-7 표 바로잡음 - 새 로직_건설품셈_01장_적용기준.json(차례 13 · 공통 2장 앞): GC001140 인력운반(지게) · GC001141 인력운반(기계설비) · GC001142 벽돌운반 - 지게 = N = V × T ÷ (120 × α × L + V × t) 또는 운반회수 직접 · 보통인부 = 무게 ÷ 1회 운반량 ÷ N · 무게 0 = 1-2-4 3 단위중량 표 - 새 빌더 build_로직_건설품셈_01장_적용기준.py · 지킴 시험 test_782_1_carry_127.py(재현 넷 0.547619 · 0.163556 · 0.654222 · 0.0132 · check_master) - 기존 표 · 로직 글자 그대로 · check_master 전후 같음 · 계산전부 1461 → 1464 멈춤 0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,619 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""건설품셈 공통 1-2-7 운반 — 계수 표 여덟(계수_건설품셈_01장_적용기준.json 에 덧) + 로직 셋(새 파일).
|
||||
|
||||
돌리기: ./venv/Scripts/python.exe resources/master_data/scripts/build_로직_건설품셈_01장_적용기준.py
|
||||
- 원문 = 건설품셈 공통 `1-02_설계_및_수량.md` 1-2-7 운반(머리 ~ 1-2-8 앞).
|
||||
- 계수 표는 1-2-4 표 뒤 · 1-3-1 표 앞에 글로 끼움(기존 표 글자 그대로) · 화물자동차 적재량은 본문 md 표에서 읽음.
|
||||
- 로직 파일 `로직_건설품셈_01장_적용기준.json` 은 통째로 씀 · 차례 13(같은 차례 공통 2장보다 이름이 앞).
|
||||
- 키는 `_키대장.json` 다음 번호(master_keys.issue) · 이미 넣었으면 멈춤(한 번 돌림).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from decimal import Decimal
|
||||
from pathlib import Path
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
MASTER = HERE.parent
|
||||
sys.path.insert(0, str(HERE))
|
||||
import master_keys as mk # noqa: E402
|
||||
|
||||
COEF = "계수_건설품셈_01장_적용기준.json"
|
||||
LOGIC = "로직_건설품셈_01장_적용기준.json"
|
||||
BODY = (
|
||||
MASTER.parents[1]
|
||||
/ "resources/knowledge/original/원가계산/건설공사_표준품셈/본문/01_공통부문/제01장_적용기준/1-02_설계_및_수량.md"
|
||||
)
|
||||
SRC = "건설품셈 공통 1-2-7"
|
||||
HEAD = {"구분": "건설품셈 공통", "상세구분": "01장 적용기준"}
|
||||
ANGLES = [6, 11, 17, 22, 27, 31, 35, 39, 42, 45]
|
||||
|
||||
|
||||
class N(str):
|
||||
"""원문 그대로의 수 글자."""
|
||||
|
||||
|
||||
def raw(v) -> str:
|
||||
if isinstance(v, N):
|
||||
return str(v)
|
||||
if v is None:
|
||||
return "null"
|
||||
if isinstance(v, list):
|
||||
return "[" + ", ".join(raw(x) for x in v) + "]"
|
||||
if isinstance(v, int) and not isinstance(v, bool):
|
||||
return str(v)
|
||||
if isinstance(v, dict):
|
||||
return (
|
||||
"{"
|
||||
+ ", ".join(f"{json.dumps(k, ensure_ascii=False)}: {raw(x)}" for k, x in v.items())
|
||||
+ "}"
|
||||
)
|
||||
return json.dumps(v, ensure_ascii=False)
|
||||
|
||||
|
||||
def emit(t: dict) -> str:
|
||||
"""기존 공통 1장 표 글 모양 — 머리 넷 한 줄 · 줄은 한 줄씩."""
|
||||
head = ", ".join(f'"{k}": {raw(t[k])}' for k in ("키", "원문번호", "구분", "상세구분"))
|
||||
out = [" {", f" {head},"]
|
||||
for k in ("이름", "기준", "출처", "비고", "용도", "조건", "범위규칙", "값칸"):
|
||||
if k in t:
|
||||
out.append(f" {json.dumps(k, ensure_ascii=False)}: {raw(t[k])},")
|
||||
out.append(' "줄": [')
|
||||
out.append(",\n".join(" " + raw(r) for r in t["줄"]))
|
||||
out.append(" ],")
|
||||
if t["주"]:
|
||||
out.append(' "주": [')
|
||||
out.append(",\n".join(" " + raw(x) for x in t["주"]))
|
||||
out.append(" ]")
|
||||
else:
|
||||
out.append(' "주": []')
|
||||
out.append(" }")
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
# ── 본문 md ──────────────────────────────────────────────────────────
|
||||
def section() -> list[str]:
|
||||
lines = BODY.read_text(encoding="utf-8").split("\n")
|
||||
a = next(i for i, x in enumerate(lines) if x.startswith("### 1-2-7 "))
|
||||
b = next(i for i, x in enumerate(lines) if x.startswith("### 1-2-8 "))
|
||||
return lines[a:b]
|
||||
|
||||
|
||||
def md_tables(lines: list[str]) -> list[list[list[str]]]:
|
||||
out, i = [], 0
|
||||
while i < len(lines):
|
||||
if not lines[i].startswith("|"):
|
||||
i += 1
|
||||
continue
|
||||
rows = []
|
||||
while i < len(lines) and lines[i].startswith("|"):
|
||||
cells = [c.strip() for c in lines[i].strip().strip("|").split("|")]
|
||||
if not all(re.fullmatch(r":?-+:?", c) for c in cells):
|
||||
rows.append([c.replace("<br>", "\n") for c in cells])
|
||||
i += 1
|
||||
out.append(rows)
|
||||
return out
|
||||
|
||||
|
||||
_NUM = r"\d[\d,]*(?:\.\d+)?"
|
||||
|
||||
|
||||
def cell(c: str):
|
||||
"""값 칸 → (값, 원문) · 「-」 · 빈 칸 = (None, None)."""
|
||||
c = c.strip()
|
||||
if c in ("", "-"):
|
||||
return None, None
|
||||
if re.fullmatch(_NUM, c):
|
||||
return N(c.replace(",", "")), None
|
||||
m = re.fullmatch(rf"({_NUM})\s*∼\s*({_NUM})", c)
|
||||
if m:
|
||||
return [N(m[1].replace(",", "")), N(m[2].replace(",", ""))], None
|
||||
m = re.fullmatch(rf"\(({_NUM})\)", c)
|
||||
if m:
|
||||
return N(m[1].replace(",", "")), c
|
||||
m = re.match(rf"({_NUM})\n", c)
|
||||
if m:
|
||||
return N(m[1].replace(",", "")), c.replace("\n", "")
|
||||
raise ValueError(f"값 칸 못 읽음 {c!r}")
|
||||
|
||||
|
||||
TRUCK = ("6톤 차량", "8톤 차량", "11톤 차량", "20톤 트레일러")
|
||||
|
||||
|
||||
def truck_rows(table: list[list[str]]) -> list[dict]:
|
||||
"""화물자동차 적재량 — 「〃」 · 빈 종별 · 빈 단위는 윗줄 · 비고 「모자이크 포함」은 원문 묶음(타일 셋)."""
|
||||
rows, kind, unit = [], "", ""
|
||||
for r in table[2:]:
|
||||
name, spec, u, *vals, note = r
|
||||
kind = kind if name in ("", "〃") else name
|
||||
unit = unit if u in ("", "〃") else u
|
||||
if kind == "페인트" and spec == "":
|
||||
spec = "(18ℓ)/통" # 원문 둘째 줄 = 18ℓ 통 괄호 값
|
||||
row = {"종별": kind, "규격": spec.replace("\n", ""), "단위": unit}
|
||||
for col, v in zip(TRUCK, vals):
|
||||
value, orig = cell(v)
|
||||
if value is not None:
|
||||
row[col] = value
|
||||
if orig is not None:
|
||||
row[col + "원문"] = orig
|
||||
if kind in ("타일", "크링커타일"):
|
||||
row["비고"] = "모자이크 포함"
|
||||
elif note:
|
||||
row["비고"] = note.replace("\n", "")
|
||||
rows.append(row)
|
||||
return rows
|
||||
|
||||
|
||||
def notes(lines: list[str], start: str) -> list[str]:
|
||||
"""`start` 로 시작하는 줄 뒤 「[주]」 묶음(빈 줄까지)."""
|
||||
i = next(i for i, x in enumerate(lines) if x.startswith(start))
|
||||
i = next(j for j in range(i, len(lines)) if lines[j].strip() == "[주]")
|
||||
out = []
|
||||
for x in lines[i + 1 :]:
|
||||
if not x.strip():
|
||||
break
|
||||
out.append(x.strip())
|
||||
return out
|
||||
|
||||
|
||||
# ── 계수 표 ──────────────────────────────────────────────────────────
|
||||
def tables(lines: list[str], logic: dict) -> list[dict]:
|
||||
md = md_tables(lines)
|
||||
jige, brick, slope, truck = md[0], md[1], md[2], md[3]
|
||||
assert jige[2][0] == "토사류" and brick[2][0] == "보통인부" and slope[0][0] == "경사도"
|
||||
t = []
|
||||
|
||||
def add(label, name, src, use, cond, cols, rows, note=(), base="", extra=None):
|
||||
t.append(
|
||||
{
|
||||
"열쇠": f"공통 1-2-7 {label}",
|
||||
"이름": name,
|
||||
"기준": base,
|
||||
"출처": f"{SRC} {src}".strip(),
|
||||
**(extra or {}),
|
||||
"용도": {"공종": "운반", "대상": use, "로직키": logic.get(label, [])},
|
||||
"조건": cond,
|
||||
"값칸": cols,
|
||||
"줄": rows,
|
||||
"주": list(note),
|
||||
}
|
||||
)
|
||||
|
||||
one = [x.strip() for x in lines if re.match(r"^[가-다]\. ", x)][:3]
|
||||
add(
|
||||
"소운반 거리",
|
||||
"소운반 — 품에 포함된 거리 · 경사면 환산",
|
||||
"1",
|
||||
["소운반", "환산"],
|
||||
{},
|
||||
{"소운반거리": "m", "직고": "m", "수평거리": "m"},
|
||||
[{"소운반거리": N("20"), "직고": N("1"), "수평거리": N("6")}],
|
||||
one,
|
||||
base="소운반 규정",
|
||||
)
|
||||
add(
|
||||
"인력운반 기본공식",
|
||||
"인력운반 기본공식 — 1일 실작업시간 · 1회 운반량",
|
||||
"2",
|
||||
["인력", "작업량 조건"],
|
||||
{},
|
||||
{"실작업시간": "분", "1회 운반량": "㎏"},
|
||||
[{"실작업시간": "480 - 30", "실작업시간원문": "480분-30분", "1회 운반량": N("25")}],
|
||||
notes(lines, "2\\. "),
|
||||
base="기본공식 상수",
|
||||
extra={
|
||||
"비고": "식 Q = N × q · N = T/(60 × L × 2/V + t) = VT/(120L + Vt) — Q 1일 운반량 · N 1일 운반횟수 · q 1회 운반량 · T 1일 실작업시간(분) · L 운반거리(m) · t 적재적하 시간(분) · V 평균왕복속도(m/hr) · 1회 운반량 25㎏ = [주] 「25㎏을 1인의 비율로」 · 3 주③"
|
||||
},
|
||||
)
|
||||
rows = []
|
||||
for kind, tt in (("토사류", jige[2][1]), ("석재류", jige[3][1])):
|
||||
for road, v in zip(("양호", "보통", "불량"), jige[2][2:5]):
|
||||
rows.append(
|
||||
{
|
||||
"종류": kind,
|
||||
"운반로": road,
|
||||
"적재적하시간": N(tt.removesuffix("분")),
|
||||
"평균왕복속도": cell(v)[0],
|
||||
}
|
||||
)
|
||||
add(
|
||||
"지게운반",
|
||||
"지게운반 — 적재적하 시간 · 평균왕복속도",
|
||||
"3",
|
||||
["인력", "작업량 조건"],
|
||||
{"종류": "고르기", "운반로": "고르기"},
|
||||
{"적재적하시간": "분", "평균왕복속도": "m/hr"},
|
||||
rows,
|
||||
notes(lines, "3\\. "),
|
||||
base="기본공식 상수",
|
||||
extra={
|
||||
"비고": "원문 평균왕복속도 칸은 토사류 · 석재류 두 줄에 걸친 한 칸 — 두 종류에 같은 값"
|
||||
},
|
||||
)
|
||||
rows = [
|
||||
{"운반": "인력", "층수": N(str(i + 1)), "보통인부": cell(v)[0]}
|
||||
for i, v in enumerate(brick[2][2:7])
|
||||
]
|
||||
assert "0.31" in brick[3][1]
|
||||
rows.append({"운반": "리프트", "보통인부": N("0.31")})
|
||||
add(
|
||||
"벽돌운반",
|
||||
"벽돌운반 — 층별 인력운반",
|
||||
"4",
|
||||
["인력"],
|
||||
{"운반": "고르기", "층수": "수"},
|
||||
{"보통인부": "인"},
|
||||
rows,
|
||||
notes(lines, "4\\. "),
|
||||
base="1,000매당",
|
||||
extra={
|
||||
"비고": "리프트 줄 = 원문 비고 「리프트를 사용할 경우 보통인부 0.31인을 적용한다」 — 층수 없음(어느 층이든)"
|
||||
},
|
||||
)
|
||||
add(
|
||||
"인력운반(기계설비) 왕복평균속도",
|
||||
"인력운반(기계설비) — 왕복평균속도",
|
||||
"5 가",
|
||||
["인력", "작업량 조건"],
|
||||
{"도로상태": "고르기"},
|
||||
{"왕복평균속도": "km/hr"},
|
||||
[
|
||||
{"도로상태": "양호", "왕복평균속도": N("2")},
|
||||
{"도로상태": "보통", "왕복평균속도": N("1.5")},
|
||||
{"도로상태": "불량", "왕복평균속도": N("1")},
|
||||
{"도로상태": "물논", "왕복평균속도": N("0.5")},
|
||||
],
|
||||
["※ 도로상태 구분은 토목부분 참조"],
|
||||
base="기본공식 상수",
|
||||
)
|
||||
add(
|
||||
"인력운반(기계설비) 준비작업시간",
|
||||
"인력운반(기계설비) — 준비작업시간 · 1회 운반량",
|
||||
"5 가",
|
||||
["인력", "작업량 조건"],
|
||||
{},
|
||||
{"준비작업시간": "분", "1회 운반량": "㎏"},
|
||||
[{"준비작업시간": N("2"), "1회 운반량": N("25")}],
|
||||
base="기본공식 상수",
|
||||
extra={
|
||||
"비고": "장대물 · 중량물 등 인력운반비 산출공식 — 운반비 = M/T × A(60 × 2 × L/V + t) · A 인력운반공 노임 · M 인력운반공 수(총운반량/1인당 1회 운반량) · L 운반거리(km) · V 왕복평균속도(km/hr) · T 1일 실작업시간 · t 준비작업시간"
|
||||
},
|
||||
)
|
||||
pct, ang, alpha = slope[0][2:], slope[1][2:], slope[2][2:]
|
||||
assert [int(a) for a in ang] == ANGLES
|
||||
add(
|
||||
"경사지 운반 환산계수",
|
||||
"경사지 운반 환산계수(α)",
|
||||
"5 나",
|
||||
["환산"],
|
||||
{"경사도": "수", "각도": "수"},
|
||||
{"환산계수": ""},
|
||||
[{"경사도": N(p), "각도": N(a), "환산계수": N(x)} for p, a, x in zip(pct, ang, alpha)],
|
||||
["경사지 환산거리 a×L"],
|
||||
base="환산계수",
|
||||
extra={
|
||||
"비고": "경사도 = % · 각도 = ° · 해석: 1 나 · 3 주⑤(직고 1m = 수평 6m)와 함께 지게운반(3)에도 씀"
|
||||
},
|
||||
)
|
||||
seven = [
|
||||
x.strip()
|
||||
for x in lines[lines.index("7\\. 화물자동차의 적재량") :]
|
||||
if re.match(r"^[가-라]\. ", x)
|
||||
]
|
||||
add(
|
||||
"화물자동차 적재량",
|
||||
"화물자동차의 적재량",
|
||||
"7 라",
|
||||
["작업량 조건", "운반"],
|
||||
{"종별": "고르기", "규격": "고르기"},
|
||||
{**{c: "단위 칸" for c in TRUCK}, "비고": ""},
|
||||
truck_rows(truck),
|
||||
seven,
|
||||
base="차 1대당",
|
||||
extra={
|
||||
"비고": "줄마다 단위 칸 · 「〃」 종별 · 단위와 빈 종별 줄은 윗줄 · 괄호 값은 원문 칸(타일 8㎜ · 페인트 18ℓ — 페인트 둘째 줄 규격 「(18ℓ)/통」은 원문 괄호를 따름) · 범위 값은 [아래, 위]"
|
||||
},
|
||||
)
|
||||
return t
|
||||
|
||||
|
||||
# ── 로직 ────────────────────────────────────────────────────────────
|
||||
def inp(name, desc, unit=None, pick=None, src=None):
|
||||
d = {"이름": name, "설명": desc}
|
||||
if unit:
|
||||
d["단위"] = unit
|
||||
if pick is not None:
|
||||
d["고르기"] = pick
|
||||
if src:
|
||||
d["출처"] = src
|
||||
return d
|
||||
|
||||
|
||||
def weights() -> tuple[list[str], list[str]]:
|
||||
data = json.loads((MASTER / COEF).read_text(encoding="utf-8"))
|
||||
table = next(x for x in data["표"] if x["키"] == "CC000337")
|
||||
kinds = list(dict.fromkeys(r["종별"] for r in table["줄"]))
|
||||
shapes = ["해당 없음", *dict.fromkeys(r["형상"] for r in table["줄"] if "형상" in r)]
|
||||
return kinds, shapes
|
||||
|
||||
|
||||
def logics(key: dict) -> list[dict]:
|
||||
kinds, shapes = weights()
|
||||
angle = inp(
|
||||
"경사각도", "운반로의 경사 각도 — 0 이면 평지(환산계수 1)", "°", [0, *ANGLES], f"{SRC} 5 나"
|
||||
)
|
||||
weight = [
|
||||
inp(
|
||||
"운반무게",
|
||||
"운반할 자재 한 단위의 무게 — 0 이면 아래 재료의 단위중량 표 값(㎏/㎥)",
|
||||
"㎏",
|
||||
src="건설품셈 공통 1-2-4 3",
|
||||
),
|
||||
inp(
|
||||
"재료종별",
|
||||
"단위중량 표에서 고를 재료(운반무게 0 일 때)",
|
||||
pick=kinds,
|
||||
src="건설품셈 공통 1-2-4 3",
|
||||
),
|
||||
inp(
|
||||
"재료형상",
|
||||
"단위중량 표의 형상(운반무게 0 일 때)",
|
||||
pick=shapes,
|
||||
src="건설품셈 공통 1-2-4 3",
|
||||
),
|
||||
]
|
||||
w_step = {
|
||||
"이름": "무게",
|
||||
"식": f"만약(운반무게 > 0, 운반무게, 찾기({key['CC000337']}, 종별=재료종별, 형상=재료형상).위)",
|
||||
"단위": "㎏",
|
||||
}
|
||||
jige = {
|
||||
"키": None,
|
||||
"열쇠": "공통 1-2-7 인력운반(지게)",
|
||||
**HEAD,
|
||||
"이름": "인력운반(지게) — 건설 공통 1-2-7",
|
||||
"결과단위": "원/자재 단위",
|
||||
"출처": f"{SRC} 2 · 3",
|
||||
"소유": "공용",
|
||||
"비고": "품에 포함된 소운반 = 20m 이내(1-2-7 1 가) — 넘거나 2차 운반이면 이 로직으로 별도 계상(1 다) · 해석: 경사지 환산계수 α(5 나 표)를 지게운반에도 씀(1 나 · 3 주⑤ 직고 1m = 수평 6m) · 운반회수를 넣으면 식 대신 그 값(실무 엑셀이 1일 운반횟수를 값으로 넣은 경우) · 운반무게 0 = 재료의 단위중량 표(1-2-4 3) 위끝 · 1회 운반량 0 = 25㎏ · 실작업시간 0 = 450분",
|
||||
"시험입력": {
|
||||
"운반무게": 575,
|
||||
"운반거리": 6,
|
||||
"경사각도": 35,
|
||||
"재료갈래": "석재류",
|
||||
"운반로": "불량",
|
||||
"회당운반량": 0,
|
||||
"실작업시간": 0,
|
||||
"운반회수": 42,
|
||||
},
|
||||
"입력": [
|
||||
*weight,
|
||||
inp(
|
||||
"회당운반량",
|
||||
"한 사람이 한 번에 지는 무게 — 0 이면 25㎏",
|
||||
"㎏",
|
||||
src=f"{SRC} 2 주 · 3 주③",
|
||||
),
|
||||
inp("운반거리", "수평 운반 거리(편도)", "m", src=f"{SRC} 2"),
|
||||
angle,
|
||||
inp(
|
||||
"재료갈래",
|
||||
"적재적하 시간 갈래(석재류 = 자갈 · 부순돌 · 조약돌 등)",
|
||||
pick=["토사류", "석재류"],
|
||||
src=f"{SRC} 3",
|
||||
),
|
||||
inp("운반로", "운반로 상태", pick=["양호", "보통", "불량"], src=f"{SRC} 3 주②"),
|
||||
inp("실작업시간", "1일 실작업시간 — 0 이면 450분", "분", src=f"{SRC} 2"),
|
||||
inp("운반회수", "1일 운반횟수를 직접 넣을 때 — 0 이면 식으로 셈", "회", src=f"{SRC} 2"),
|
||||
],
|
||||
"중간": [
|
||||
w_step,
|
||||
{
|
||||
"이름": "운반량",
|
||||
"식": f"만약(회당운반량 > 0, 회당운반량, 찾기({key['인력운반 기본공식']}).'1회 운반량')",
|
||||
"단위": "㎏",
|
||||
},
|
||||
{
|
||||
"이름": "환산계수",
|
||||
"식": f"만약(경사각도 > 0, 찾기({key['경사지 운반 환산계수']}, 각도=경사각도).환산계수, 1)",
|
||||
},
|
||||
{"이름": "환산거리", "식": "환산계수 * 운반거리", "단위": "m"},
|
||||
{
|
||||
"이름": "작업시간",
|
||||
"식": f"만약(실작업시간 > 0, 실작업시간, 찾기({key['인력운반 기본공식']}).실작업시간)",
|
||||
"단위": "분",
|
||||
},
|
||||
{
|
||||
"이름": "적재적하시간",
|
||||
"식": f"찾기({key['지게운반']}, 종류=재료갈래, 운반로=운반로).적재적하시간",
|
||||
"단위": "분",
|
||||
},
|
||||
{
|
||||
"이름": "평균왕복속도",
|
||||
"식": f"찾기({key['지게운반']}, 종류=재료갈래, 운반로=운반로).평균왕복속도",
|
||||
"단위": "m/hr",
|
||||
},
|
||||
{
|
||||
"이름": "일운반회수",
|
||||
"식": "만약(운반회수 > 0, 운반회수, 평균왕복속도 * 작업시간 / (120 * 환산거리 + 평균왕복속도 * 적재적하시간))",
|
||||
"단위": "회",
|
||||
},
|
||||
],
|
||||
"호표": [
|
||||
{
|
||||
"종류": "인력",
|
||||
"요소": "LB000002",
|
||||
"이름": "보통인부",
|
||||
"단위": "인",
|
||||
"수량": "무게 / 운반량 / 일운반회수",
|
||||
"비목": "노무비",
|
||||
"출처": f"{SRC} 2",
|
||||
}
|
||||
],
|
||||
"덧줄": [],
|
||||
"끝수": None,
|
||||
}
|
||||
machine = {
|
||||
"키": None,
|
||||
"열쇠": "공통 1-2-7 인력운반(기계설비)",
|
||||
**HEAD,
|
||||
"이름": "인력운반(기계설비) — 건설 공통 1-2-7",
|
||||
"결과단위": "원/자재 단위",
|
||||
"출처": f"{SRC} 5",
|
||||
"소유": "공용",
|
||||
"비고": "장대물 · 중량물 등 — 운반비 = M/T × A(60 × 2 × L/V + t) · M = 운반무게 ÷ 1회 운반량 · 해석: T = 1일 실작업시간 450분(1-2-7 2) · 경사지는 환산거리 α × L(5 나)",
|
||||
"시험입력": {
|
||||
"운반무게": 100,
|
||||
"운반거리": 0.1,
|
||||
"도로상태": "보통",
|
||||
"경사각도": 0,
|
||||
"회당운반량": 0,
|
||||
"실작업시간": 0,
|
||||
},
|
||||
"입력": [
|
||||
*weight,
|
||||
inp("회당운반량", "인력운반공 1회 운반량 — 0 이면 25㎏", "㎏", src=f"{SRC} 5 가"),
|
||||
inp("운반거리", "운반 거리(편도)", "km", src=f"{SRC} 5 가"),
|
||||
inp(
|
||||
"도로상태",
|
||||
"운반로 도로상태",
|
||||
pick=["양호", "보통", "불량", "물논"],
|
||||
src=f"{SRC} 5 가",
|
||||
),
|
||||
angle,
|
||||
inp("실작업시간", "1일 실작업시간 — 0 이면 450분", "분", src=f"{SRC} 2"),
|
||||
],
|
||||
"중간": [
|
||||
w_step,
|
||||
{
|
||||
"이름": "운반량",
|
||||
"식": f"만약(회당운반량 > 0, 회당운반량, 찾기({key['인력운반(기계설비) 준비작업시간']}).'1회 운반량')",
|
||||
"단위": "㎏",
|
||||
},
|
||||
{"이름": "인원", "식": "무게 / 운반량", "단위": "인"},
|
||||
{
|
||||
"이름": "환산계수",
|
||||
"식": f"만약(경사각도 > 0, 찾기({key['경사지 운반 환산계수']}, 각도=경사각도).환산계수, 1)",
|
||||
},
|
||||
{"이름": "환산거리", "식": "환산계수 * 운반거리", "단위": "km"},
|
||||
{
|
||||
"이름": "왕복평균속도",
|
||||
"식": f"찾기({key['인력운반(기계설비) 왕복평균속도']}, 도로상태=도로상태).왕복평균속도",
|
||||
"단위": "km/hr",
|
||||
},
|
||||
{
|
||||
"이름": "준비작업시간",
|
||||
"식": f"찾기({key['인력운반(기계설비) 준비작업시간']}).준비작업시간",
|
||||
"단위": "분",
|
||||
},
|
||||
{
|
||||
"이름": "작업시간",
|
||||
"식": f"만약(실작업시간 > 0, 실작업시간, 찾기({key['인력운반 기본공식']}).실작업시간)",
|
||||
"단위": "분",
|
||||
},
|
||||
],
|
||||
"호표": [
|
||||
{
|
||||
"종류": "인력",
|
||||
"요소": "LB000045",
|
||||
"이름": "인력운반공",
|
||||
"단위": "인",
|
||||
"수량": "인원 / 작업시간 * (60 * 2 * 환산거리 / 왕복평균속도 + 준비작업시간)",
|
||||
"비목": "노무비",
|
||||
"출처": f"{SRC} 5 가",
|
||||
}
|
||||
],
|
||||
"덧줄": [],
|
||||
"끝수": None,
|
||||
}
|
||||
brick = {
|
||||
"키": None,
|
||||
"열쇠": "공통 1-2-7 벽돌운반",
|
||||
**HEAD,
|
||||
"이름": "벽돌운반 — 건설 공통 1-2-7",
|
||||
"결과단위": "원/1,000매",
|
||||
"출처": f"{SRC} 4",
|
||||
"소유": "공용",
|
||||
"비고": "기본벽돌(19×9×5.7㎝)을 인력으로 층별(층고 3.6m) 운반 · 리프트를 쓰면 층수와 관계없이 보통인부 0.31인",
|
||||
"입력": [
|
||||
inp("운반", "운반 방법", pick=["인력", "리프트"], src=f"{SRC} 4"),
|
||||
inp("층수", "올릴 층(리프트면 무관)", "층", [1, 2, 3, 4, 5], f"{SRC} 4"),
|
||||
],
|
||||
"중간": [],
|
||||
"호표": [
|
||||
{
|
||||
"종류": "인력",
|
||||
"요소": "LB000002",
|
||||
"이름": "보통인부",
|
||||
"단위": "인",
|
||||
"수량": f"찾기({key['벽돌운반']}, 운반=운반, 층수=층수).보통인부",
|
||||
"비목": "노무비",
|
||||
"출처": f"{SRC} 4",
|
||||
}
|
||||
],
|
||||
"덧줄": [],
|
||||
"끝수": None,
|
||||
}
|
||||
return [jige, machine, brick]
|
||||
|
||||
|
||||
USES = { # 표 → 그 표를 부르는 로직(열쇠)
|
||||
"소운반 거리": [],
|
||||
"인력운반 기본공식": ["인력운반(지게)", "인력운반(기계설비)"],
|
||||
"지게운반": ["인력운반(지게)"],
|
||||
"벽돌운반": ["벽돌운반"],
|
||||
"인력운반(기계설비) 왕복평균속도": ["인력운반(기계설비)"],
|
||||
"인력운반(기계설비) 준비작업시간": ["인력운반(기계설비)"],
|
||||
"경사지 운반 환산계수": ["인력운반(지게)", "인력운반(기계설비)"],
|
||||
"화물자동차 적재량": [],
|
||||
}
|
||||
LOGIC_LABELS = ("인력운반(지게)", "인력운반(기계설비)", "벽돌운반")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
coef_path, logic_path = MASTER / COEF, MASTER / LOGIC
|
||||
text = coef_path.read_text(encoding="utf-8")
|
||||
if '"원문번호": "1-2-7"' in text or logic_path.exists():
|
||||
raise SystemExit("이미 넣음 — 멈춤")
|
||||
book = mk.load_book()
|
||||
lkey = {x: mk.issue(book, "GC", f"공통 1-2-7 {x}", LOGIC) for x in LOGIC_LABELS}
|
||||
uses = {label: [lkey[x] for x in v] for label, v in USES.items()}
|
||||
lines = section()
|
||||
made = tables(lines, uses)
|
||||
ckey = {"CC000337": "CC000337"}
|
||||
for t in made:
|
||||
label = t["열쇠"].removeprefix("공통 1-2-7 ")
|
||||
ckey[label] = mk.issue(book, "CC", t["열쇠"], COEF)
|
||||
t["키"], t["원문번호"] = ckey[label], "1-2-7"
|
||||
t.update(HEAD)
|
||||
at = text.index(' {\n "키": "CC000001"')
|
||||
new_text = text[:at] + "".join(emit(t) + ",\n" for t in made) + text[at:]
|
||||
data = json.loads(new_text, parse_float=Decimal, parse_int=Decimal)
|
||||
assert sum(1 for x in data["표"] if x["원문번호"] == "1-2-7") == len(made)
|
||||
coef_path.write_text(new_text, encoding="utf-8", newline="\n")
|
||||
|
||||
rows = []
|
||||
for row in logics(ckey):
|
||||
label = row.pop("열쇠").removeprefix("공통 1-2-7 ")
|
||||
row["키"], row["원문번호"] = lkey[label], "1-2-7"
|
||||
order = ["키", "원문번호", *[k for k in row if k not in ("키", "원문번호")]]
|
||||
rows.append({k: row[k] for k in order})
|
||||
head = {
|
||||
"그룹": "로직",
|
||||
"원문": "건설품셈",
|
||||
"부문": "공통",
|
||||
"차례": 13,
|
||||
"판": "2026",
|
||||
"줄": rows,
|
||||
}
|
||||
logic_path.write_text(mk._store().dump(head), encoding="utf-8", newline="\n")
|
||||
mk.save_book(mk.finish(book))
|
||||
print("계수", [t["키"] for t in made], "로직", list(lkey.values()))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
main()
|
||||
Reference in New Issue
Block a user