Files
Aislo/resources/tester/test_782_3_capacity_82.py
T
eomsangdonandClaude Opus 5.5 58a3e039b3 feat(813-2): 보조 문서 부품 표지 73 · 작업량당 기계경비 6 지움 · 단가산출 목록에서 뺌 · 기계 → 부품 길
- 표지 = 수식 문서 머리 · 옛 로직 줄 칸 「부품」 — 기계경비식 9 · 작업량 틀 60(기종 = 기계표 상세구분 · 규격 열쇠) · 계수식 4 · 변환기가 옮김 · 틀 문서 9 장
- 지움 = 작업량당 기계경비 6(GC001145 · 1148 · 1151 · 1156 · 1159 · 1166 · 부르는 곳 0 · 요구 734-4 · 735-4) — 수식 문서 · 옛 로직 · 키대장 폐기 칸 · 빌더 · 변수표
- 이름 꼬리 4 = 원문 제목(지게운반 · 인력운반(기계설비) · 벽돌운반 · 수중펌프 설치 및 해체) · 키 폐기 0
- 서버 = `M01_MasterData_Parts` — M01 `/logics` · M02 `/logic-lib/logics` 목록에서 부품 뺌(1,440) · 키로 열기 · 부르기 그대로 · `/m01/parts`(기종 계산식 · 틀 · 계수식) · `/m02/logic-lib/machine-parts` · 연결 찾기 과녁에서 부품 뺌(1,444 → 1,435 · 판정 코드 그대로)
- 금액 전후 = 문서 1,513 · 셈 9,626(기본 + 옵션 표본) 모두 같음 · 791_1 지문 남은 1,513 같음 → 지문 다시 뜸 · 802_2 변환 대조 1,513 · 목록 xlsx 다시 씀(요약 수)
- 낡은 시험 = 1,519 · 1,518 기대 → 1,513 · GC001148 견본 → 같은 꼴 GF000089 토사깍기(기계)(블록 Q 39.293 · 합계 2,190) · 지운 6 을 셈하던 줄 걷음 · 목록 수 1,440 · 묶음 328 · 부르는 수 507
- 새 지킴 시험 test_813_2_parts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 20:49:52 +09:00

253 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""782-3 건설 공통 8-1-4 · 8-2 시공능력 · 기계설비 13-2-7 — 계수 표 146 · 로직 49 · 실무 엑셀 Q 재현 · check_master."""
import sys
from decimal import Decimal as D
from pathlib import Path
import pytest
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "master_data/scripts"))
import check_master as cm # noqa: E402
import master_formula as mf # noqa: E402
COEF = "계수_건설품셈_08장_건설기계.json"
LOGIC = "로직_건설품셈_08장_건설기계.json"
LOGIC13 = "로직_건설품셈_13장_플랜트설비공사.json"
EXC, DUMP, ROLL_A, CHIP = "GC001147", "GC001155", "GC001158", "GC001189"
K = {
"0.9": "위의 토질보다 약간 단단한 토질로서 버킷에 거의 가득 채울 수 있는 모래, 보통토 및 조건이 좋은 점토인 경우",
"0.7": "버킷에 가득 채우기가 어렵거나 가벼운 발파를 필요로 하는 것으로서 단단한 점토질, 점토, 역토질인 경우",
"0.55": "버킷에 넣기 어렵고 불규칙한 공극이 생기는 것으로서 발파 또는 리퍼작업 등에 의하여 얻어진 암과 파쇄암, 호박돌, 역 등인 경우",
}
@pytest.fixture(scope="module")
def whole():
return cm.master()
def near(got, want, tol="0.005"):
return abs(got / D(want) - 1) <= D(tol)
def excavator(whole, q, k, f, e, angle, cycle=0):
q = D(q)
size = "0.12∼0.4" if q <= D("0.4") else "0.6∼0.8" if q <= D("0.8") else "1.0∼1.2"
given = {
"버킷용량": q,
"규격구분": size,
"선회각도": angle,
"버킷조건": K[k],
"현장조건": "흐트러진 상태",
"등급": "보통",
"토질명": "모래, 사질토",
"E보정": "해당 없음",
"협소현장": "해당 없음",
"f": D(f),
"E입력": D(e),
"싸이클입력": cycle,
}
return mf.run(whole, EXC, given)["결과"]
@pytest.mark.parametrize(
"q, k, f, e, angle, want",
[
("1", "0.9", "0.7", "0.75", 135, "81"), # 북부청임도 단산4 적사
("0.6", "0.55", "1", "0.35", 90, "23.1"), # 북부청임도 단산6 채집
("0.6", "0.55", "1", "0.35", 135, "20.79"), # 북부청임도 단산6 상차
("1", "0.7", "0.76923", "0.65", 90, "66.32"), # 북부청임도 단산27
("1", "0.7", "1", "0.65", 135, "78"), # 북부청임도 단산52
("1", "0.55", "1", "0.4", 135, "37.71"), # 북부청임도 단산53
("0.7", "0.55", "0.67", "0.35", 180, "14.77"), # 북부청임도 단산75~80 집토
("1", "0.55", "0.62", "0.4", 135, "23.38"), # 북부청임도 단산89
("1", "0.55", "0.65", "0.4", 135, "24.51"), # 북부청사방 단산10
("0.7", "0.9", "1", "0.75", 135, "85.05"), # 동부청영월 111
("0.4", "0.55", "0.87", "0.45", 135, "17.23"), # 동부청영월 411 채집
("0.4", "0.7", "0.87", "0.45", 135, "21.92"), # 동부청영월 411 상차
],
)
def test_굴착기_재현(whole, q, k, f, e, angle, want):
assert near(excavator(whole, q, k, f, e, angle), want)
def test_굴착기_엑셀_다른_싸이클(whole):
# 영덕계류 1427 · 1438 — 엑셀이 0.12∼0.4㎥ 에 0.6∼0.8㎥ 줄 싸이클(135° 20초 · 90° 18초)을 씀
assert excavator(whole, "0.36", "0.55", "1", "0.35", 135) == D("13.860") # 표 18초
assert near(excavator(whole, "0.36", "0.55", "1", "0.35", 135, 20), "12.47")
assert near(excavator(whole, "0.36", "0.55", "1", "0.45", 90, 18), "17.82")
assert near(excavator(whole, "0.29", "0.55", "1", "0.45", 90, 18), "14.36")
BASE_DUMP = {
"f": 1,
"도로상태": "교차가 힘든 산간지도로 및 제방 등의 도로",
"적하토질": "모래, 역, 호박돌",
"적하조건": "불량",
"적재장소": "적재장소가 넓지는 않으나 목적장소에 불편없이 진입할 수 있을 때",
"덮개": "해당 없음",
"세륜": "안 함",
"적재방법": "적재기계",
"인력종류": "토사류",
"적재시간입력": 0,
"E입력": 0,
}
@pytest.mark.parametrize(
"given, want",
[
# 북부청임도 단산4 — 15t · γ 1.8 · L 1.25 · f 0.7 · 0.08㎞ · 굴착기 1.0㎥ 21초
(
{
"적재용량": 15,
"단위중량": D("1.8"),
"체적변화율": D("1.25"),
"f": D("0.7"),
"운반거리": D("0.08"),
"적재싸이클": 21,
"적재버킷": 1,
"버킷계수": D("0.9"),
"적재효율": D("0.75"),
},
"51.02",
),
# 북부청임도 단산6 — 4.5t · γ 1.75 · 0.5㎞
(
{
"적재용량": D("4.5"),
"단위중량": D("1.75"),
"체적변화율": 1,
"운반거리": D("0.5"),
"적재싸이클": 20,
"적재버킷": D("0.6"),
"버킷계수": D("0.55"),
"적재효율": D("0.35"),
},
"9.96",
),
# 북부청임도 단산19 — 열악한 도로 7 · 8 · 좁은 적재장소 0.7분
(
{
"적재용량": 15,
"단위중량": D("1.9"),
"체적변화율": D("1.3"),
"f": D("0.77"),
"운반거리": D("0.5"),
"도로상태": "토취장 또는 토사장 등 열악한 조건의 도로",
"적재장소": "적재장소가 좁아서 목적장소에 진입하는데 불편을 느낄 때",
"적재싸이클": 21,
"적재버킷": 1,
"버킷계수": D("0.9"),
"적재효율": D("0.85"),
},
"29.36",
),
# 동부청영월 411 — 적하 보통 0.8분
(
{
"적재용량": D("4.5"),
"단위중량": D("0.575"),
"체적변화율": D("1.15"),
"f": D("0.87"),
"운반거리": D("0.5"),
"적하조건": "보통",
"적재싸이클": 18,
"적재버킷": 1,
"버킷계수": D("0.7"),
"적재효율": D("0.45"),
},
"28.59",
),
],
)
def test_덤프트럭_재현(whole, given, want):
assert near(mf.run(whole, DUMP, {**BASE_DUMP, **given})["결과"], want)
def test_롤러_임목파쇄_브레이커(whole):
roll = {
"다짐기계": "진동롤러(자주식)",
"규격": "10.0",
"다짐층": "노체, 축제, 노상",
"다짐횟수": 2,
"E공종": "노체, 축제, 노상",
"E기계": "불도저",
"현장조건": "보통",
"E입력": 0,
}
assert mf.run(whole, ROLL_A, roll)["결과"] == D("2280.000") # 북부청임도 단산27
assert (
mf.run(whole, CHIP, {"규격": "93.25㎾", "스크린": "75㎜", "작업조건": "보통"})["결과"] == 6
) # 동부청영월 111
# 북부청임도 단산75~78 — 엑셀 Q = 구조물 헐기 표 범위 평균치(적용방법 ②)
rows = {r["구분"]: r for r in whole.get("CC000065")["줄"]}
mean = lambda v: (v[0] + v[1]) / 2 # noqa: E731
assert mean(rows["구조물의 평균두께 30㎝ 이상"]["무근구조물"]) == D("3.6")
assert mean(rows["구조물의 평균두께 30㎝ 미만"]["무근구조물"]) == D("4.6")
assert mean(rows["구조물의 평균두께 30㎝ 이상"]["철근구조물"]) == D("2.05")
assert mean(rows["구조물의 평균두께 30㎝ 미만"]["철근구조물"]) == D("2.45")
# 대형브레이커 작업량당 기계경비(GC001166) = 813-2 지움 — 단가산출에 기계 하나 넣어 만듦
def test_기본식_원가로직(whole):
got = mf.run(
whole,
"GC001143",
{"싸이클시간": 21, "시간단위": "초", "작업량": D("0.9"), "f": D("0.7"), "E": D("0.75")},
)
assert got["중간"]["n"] == D("171.43") and got["결과"] == D("81.001")
# 굴착기 작업량당 기계경비(GC001148) = 813-2 지움 — 기계 넣기 + 작업량 틀(test_813_2_parts)
def test_아세틸렌(whole):
assert mf.run(whole, "GC001191", {"아세틸렌부피": 22400})["결과"] == 26
def test_check_master():
files, whole = cm.load([COEF, LOGIC, LOGIC13, "기계.json"]), cm.master()
found = [x for name, data in files.items() for x in cm.check_form(name, data)]
found += cm.check_body(files) + cm.check_logics(files, whole)
assert found == []
new = [t["키"] for t in files[COEF]["표"] if "CC000349" <= t["키"] <= "CC000494"]
assert len(new) == 146
logic = [r["키"] for r in files[LOGIC]["줄"] if r["키"] >= "GC001143"]
gone = (1145, 1148, 1151, 1156, 1159, 1166) # 813-2 작업량당 기계경비 지움
assert logic == [f"GC00{n}" for n in range(1143, 1191) if n not in gone]
assert files[LOGIC13]["줄"][-1]["키"] == "GC001191"
for name in (LOGIC, LOGIC13):
for row in files[name]["줄"]:
if row["키"] >= "GC001143":
mf.run(whole, row["키"], cm.시험입력(row)) # 시험 입력으로 멈춤 없음
GUARD = __import__("re").compile(r"만약\((\w+) > 0, \1,")
def test_가드_칸_자동값(whole):
# 분석 635 — 「0 이면 기본」 가드 칸은 견본 자동값 1 로 셈해도 터무니없지 않게:
# 범위 [0, 원문 끝] 칸은 자동값 0(= 원문 기본) · 범위 없는 가드 칸은 1 이어도 기본의 10배 안
import master_auto as ma
files = cm.load([LOGIC, LOGIC13])
rows = [r for f in files.values() for r in f["줄"] if r["키"] >= "GC001143"]
loose = set()
for row in rows:
auto = ma.values(whole, row)
got = mf.run(whole, row["키"], auto)
value = got.get("결과", got.get("계"))
assert value >= 0, row["키"]
spec = {i["이름"]: i for i in row["입력"]}
for name in GUARD.findall(" ".join(ma._texts(row))):
if "범위" in spec.get(name, {}):
assert auto[name] == 0, (row["키"], name)
elif name in spec:
loose.add(name)
base = cm.시험입력(row)
zero = mf.run(whole, row["키"], {**base, name: 0})["결과"]
one = mf.run(whole, row["키"], {**base, name: 1})["결과"]
assert one / zero < 10, (row["키"], name)
assert loose == {"전진거리", "후진거리", "주행거리", "혼합횟수", "플랜트싸이클"}