tmp/ 가 창끼리 안 건너가는 것이 확정돼(랩탑이 시간 두고 두 번 확인) 시험·예외가 저절로 건너가도록 git 안으로 옮김. 사용자 확정. - 내용은 하나도 안 고침 — 자리만 옮김. tmp/tests 는 남겨 둠. - 같은 이름이 이미 있던 64 개는 랩탑 것을 그대로 두고 건너뜀. - helper_b05_*.js 둘은 랩탑이 .cjs 로 이미 올린 것과 **줄바꿈만 다른 같은 내용**이라 복사본을 도로 뺌(시험이 .cjs 를 부름). - resources/tester/ 에서 전체 1176 통과 · 29 건너뜀 · 실패 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
137 lines
5.5 KiB
Python
137 lines
5.5 KiB
Python
"""돌쌓기 표준경사 — 직고·메찰·성절토로 갈린다 (2026-09-09 사용자 확정 ⑨).
|
||
|
||
⚠ 겨누는 것 여섯
|
||
① 표대로 갈린다 — 우리 종전 0.3 은 「메쌓기·성토·1.5m 이하」 한 칸이었다
|
||
② ⚠ 경계값은 **앞 칸** — 원문이 `∼3` 이라 직고 3.0m 은 `~3` 칸이다
|
||
③ 7m 초과라야 마지막 칸이다
|
||
④ 사용자가 정했으면 **그 값이 이긴다**
|
||
⑤ 근거 문구에 **어느 칸에서 왔는지**와 **성토 열로 잠정임**이 적힌다
|
||
⑥ ⚠ 큰돌쌓기는 이 표의 대상이 아니다(교본 「1:0.3 이상」)
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import math
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
sys.path.insert(0, str(ROOT))
|
||
|
||
from B08_Quantity.B08_Quantity_Engine_UnitQuantity import ( # noqa: E402
|
||
boulder_masonry,
|
||
face_slope_ratio,
|
||
stone_masonry,
|
||
)
|
||
|
||
|
||
def 기울기(wet: bool, height_m: float, face: str | None = "성토", **options: object) -> float:
|
||
"""⚠ 성토/절토는 **판정 한 벌**(`common_util_structure_face_role`)이 준다 —
|
||
시험에서는 그 자리를 명시해 표의 어느 열을 보는지 분명히 한다."""
|
||
return face_slope_ratio(dict(options), wet=wet, height_m=height_m, face=face)[0]
|
||
|
||
|
||
def test_표대로_갈린다() -> None:
|
||
# 메쌓기 성토
|
||
assert 기울기(False, 1.2) == 0.30
|
||
assert 기울기(False, 2.0) == 0.35
|
||
assert 기울기(False, 4.0) == 0.40
|
||
assert 기울기(False, 6.0) == 0.45
|
||
# 찰쌓기 성토
|
||
assert 기울기(True, 1.2) == 0.25
|
||
assert 기울기(True, 2.5) == 0.30
|
||
assert 기울기(True, 4.0) == 0.35
|
||
|
||
|
||
def test_경계값은_앞_칸이다() -> None:
|
||
"""⚠ 원문 표기가 `∼1.5 · ∼3` 이라 **이하**로 읽는다 — 한 칸 밀리면 값이 갈린다."""
|
||
assert 기울기(True, 1.5) == 0.25 # `~1.5` 칸
|
||
assert 기울기(True, 1.51) == 0.30 # 다음 칸
|
||
assert 기울기(False, 3.0) == 0.35 # `~3` 칸
|
||
assert 기울기(False, 3.01) == 0.40
|
||
|
||
|
||
def test_7m_초과라야_마지막_칸() -> None:
|
||
assert 기울기(False, 7.0) == 0.45
|
||
assert 기울기(False, 7.01) == 0.50
|
||
|
||
|
||
def test_사용자가_정하면_그_값이_이긴다() -> None:
|
||
ratio, basis = face_slope_ratio({"face_slope_ratio": 0.5}, wet=True, height_m=2.5, face="성토")
|
||
assert ratio == 0.5
|
||
assert "사용자 지정" in basis
|
||
|
||
|
||
def test_근거에_칸과_잠정임이_적힌다() -> None:
|
||
_, basis = face_slope_ratio(
|
||
{}, wet=False, height_m=2.0, face="성토", face_reason="right_cut · 좌측 → 성토면"
|
||
)
|
||
assert "13-4-4" in basis and "메쌓기" in basis
|
||
# ⚠ 어느 단면유형에서 왔는지가 근거에 실린다 — 값만 있고 까닭이 없으면 못 되짚는다.
|
||
assert "right_cut" in basis
|
||
|
||
|
||
def test_면적이_그_기울기로_선다() -> None:
|
||
"""메쌓기 H=2.0 은 1:0.35 — 종전 0.3 보다 **면적이 커진다**."""
|
||
components, _ = stone_masonry(
|
||
2.0, 10.0, {"height_m": 2.0, "length_m": 10.0, "back_len_cm": 35}, False, "성토"
|
||
)
|
||
area = next(c for c in components if c.name == "돌쌓기")
|
||
assert area.amount == 20.0 * math.hypot(1.0, 0.35)
|
||
assert "표준경사" in area.basis
|
||
|
||
|
||
def test_큰돌쌓기는_이_표의_대상이_아니다() -> None:
|
||
"""교본이 「1:0.3 **이상**」으로만 두었다 — 직고로 갈리지 않는다."""
|
||
components, _ = boulder_masonry(
|
||
5.0, 10.0, {"height_m": 5.0, "length_m": 10.0, "stone_cm": "60~80"}
|
||
)
|
||
area = next(c for c in components if c.name == "큰돌쌓기")
|
||
assert area.amount == 50.0 * math.hypot(1.0, 0.3)
|
||
|
||
|
||
def test_표_밖_값도_그대로_쓴다() -> None:
|
||
"""⚠ 실무 도면에 **S0.7·0.8** 이 실재한다(품셈 표는 0.20~0.50).
|
||
|
||
표 밖이라고 막거나 가까운 칸으로 **접지 않는다** — 접으면 사용자가 넣은 값이 조용히
|
||
다른 값으로 돌아간다(뒷길이에서 이미 겪은 자리). 「사용자 지정」으로 그대로 쓴다.
|
||
"""
|
||
for value in (0.7, 0.8, 1.2):
|
||
ratio, basis = face_slope_ratio(
|
||
{"face_slope_ratio": value}, wet=True, height_m=2.5, face="성토"
|
||
)
|
||
assert ratio == value
|
||
assert "사용자 지정" in basis
|
||
|
||
components, _ = stone_masonry(
|
||
2.5,
|
||
10.0,
|
||
{"height_m": 2.5, "length_m": 10.0, "back_len_cm": 45, "face_slope_ratio": 0.7},
|
||
wet=True,
|
||
)
|
||
area = next(c for c in components if c.name == "돌쌓기")
|
||
assert area.amount == 25.0 * math.hypot(1.0, 0.7)
|
||
|
||
|
||
def test_성절토를_못_가르면_눅이지_않는다() -> None:
|
||
"""⚠ `both_cut` + 「자동」처럼 **가를 근거가 없는 자리**가 있다(판정 한 벌이 `None` 을 줌).
|
||
|
||
성토로 눅여 표를 고르면 **임의값이 금액으로 굳는다.** 종전값으로 서되 **왜 못 갈랐는지**를
|
||
근거에 적어 사용자가 무엇이 없는지 보게 한다.
|
||
"""
|
||
ratio, basis = face_slope_ratio(
|
||
{}, wet=True, height_m=2.5, face=None, face_reason="both_cut · 자동 — 세울 성토면이 없음"
|
||
)
|
||
assert ratio == 0.3
|
||
assert "both_cut" in basis and "종전값" in basis
|
||
|
||
|
||
def test_판정_한_벌을_그대로_쓴다() -> None:
|
||
"""⚠ 판정을 두 벌로 짜면 예외에서 갈린다 — 공용 함수 결과가 그대로 흘러야 한다."""
|
||
from common_util.common_util_structure_face_role import structure_face_role
|
||
|
||
role, reason = structure_face_role("right_cut", "좌")
|
||
assert role == "성토"
|
||
_, basis = face_slope_ratio({}, wet=True, height_m=2.5, face=role, face_reason=reason)
|
||
assert reason in basis
|