- B08_Quantity_Haul_Cycle.py · .ts 짝 — 건설품셈 8-2-8 덤프트럭 · 거창 25 단가산출 1308~1347행 재현(t1 5.33 · t2 101.23 · Cm 109.78) - 로직 입력 이름 채움 Cm · 사이클시간 · t2 · 운반거리 · 덮은 칸(own) 그대로 - B09 셈(hand_sources) 때 거리이정표 거리로 다시 채움 · 덮개 ref 에 cycle · own 남김 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JywHxQuWPk6UYXTebyrBoU
94 lines
3.6 KiB
TypeScript
94 lines
3.6 KiB
TypeScript
/* =============================================================================
|
||
* B08_Quantity_Haul_Cycle.ts
|
||
* B08 운반 사이클시간(PLAN 253-2) — 건설품셈 8-2-8 덤프트럭 · 거리이정표 거리 → 운반 로직 입력.
|
||
*
|
||
* ⚠ 짝 = `B08_Quantity_Haul_Cycle.py`(같은 식) — 한쪽을 고치면 다른 쪽도 ·
|
||
* 거울 시험 `resources/tester/test_253_2_haul_cycle.py`.
|
||
* 조작 중은 이 파일(「운반 단가」 모달)이 바로 셈 · B09 셈 때 서버가 짝으로 다시 채움(정본).
|
||
*
|
||
* 식 = q = T / rt × f · n = q / (qs × k) · t1 = Cms × n / (60 × Es) ·
|
||
* t2 = (L1/V1 + L1/V2 + L2/V3 + L2/V4) × 60 · Cm = t1 + … + t6 · 끝수 = 소수 둘째 자리 ·
|
||
* 속도 0 = 그 항 0 · 로직 입력 채움 = Cm · 사이클시간 = Cm · t2 · 운반거리 = L1 + L2 ·
|
||
* `own` = 사용자가 덮은 칸(그 값이 이김).
|
||
* ========================================================================== */
|
||
|
||
export const CYCLE_DEFAULTS: Record<string, number> = {
|
||
L1: 0,
|
||
L2: 0,
|
||
V1: 30,
|
||
V2: 35,
|
||
V3: 10,
|
||
V4: 15,
|
||
T: 15,
|
||
rt: 1.7,
|
||
f: 1,
|
||
qs: 1.72,
|
||
k: 1,
|
||
Es: 0.6,
|
||
Cms: 37.4,
|
||
t3: 0.8,
|
||
t4: 0.42,
|
||
t5: 0.5,
|
||
t6: 1.5,
|
||
};
|
||
/** 로직 입력 이름 → 셈 결과 칸 */
|
||
export const CYCLE_FILL: Record<string, "cm" | "t2" | "L"> = {
|
||
Cm: "cm",
|
||
사이클시간: "cm",
|
||
t2: "t2",
|
||
운반거리: "L",
|
||
};
|
||
|
||
export interface CycleResult {
|
||
q: number;
|
||
n: number;
|
||
t1: number;
|
||
t2: number;
|
||
cm: number;
|
||
L: number;
|
||
}
|
||
export interface CycleRef {
|
||
given?: Record<string, unknown> | null;
|
||
cycle?: Record<string, unknown> | null;
|
||
own?: string[] | null;
|
||
}
|
||
export type Dist = { L1?: number | null; L2?: number | null } | null | undefined;
|
||
|
||
/** 소수 둘째 자리 반올림(0.5 올림 · 파이썬 짝 `r2`) */
|
||
export const r2 = (value: number): number => Math.floor(value * 100 + 0.5) / 100;
|
||
const div = (a: number, b: number): number => (b ? a / b : 0);
|
||
const num = (value: unknown): number | null =>
|
||
typeof value === "number" && Number.isFinite(value) ? value : null;
|
||
|
||
/** 사이클 입력(빈 칸 = 기본값 · t1 있으면 그 값) → {q, n, t1, t2, cm, L} */
|
||
export function cycleTime(inputs: Record<string, unknown> | null | undefined): CycleResult {
|
||
const v: Record<string, number> = {};
|
||
for (const [k, d] of Object.entries(CYCLE_DEFAULTS)) v[k] = num(inputs?.[k]) ?? d;
|
||
const q = r2(div(v.T, v.rt) * v.f);
|
||
const n = r2(div(q, v.qs * v.k));
|
||
const t1 = num(inputs?.t1) ?? r2(div(v.Cms * n, 60 * v.Es));
|
||
const t2 = r2((div(v.L1, v.V1) + div(v.L1, v.V2) + div(v.L2, v.V3) + div(v.L2, v.V4)) * 60);
|
||
const cm = r2(t1 + t2 + v.t3 + v.t4 + v.t5 + v.t6);
|
||
return { q, n, t1, t2, cm, L: Math.floor((v.L1 + v.L2) * 1000 + 0.5) / 1000 };
|
||
}
|
||
|
||
/** 연결 `ref.cycle` + 거리이정표 거리 — 덮은 L1 · L2(`ref.own`)는 그대로 */
|
||
export function cycleInputs(ref: CycleRef | null | undefined, dist: Dist): Record<string, unknown> {
|
||
const cycle: Record<string, unknown> = { ...(ref?.cycle || {}) };
|
||
const own = new Set(ref?.own || []);
|
||
for (const name of ["L1", "L2"] as const)
|
||
if (!own.has(name) && num(dist?.[name]) !== null) cycle[name] = dist?.[name];
|
||
if (!own.has("t1")) delete cycle.t1;
|
||
return cycle;
|
||
}
|
||
|
||
/** 로직 입력값 다시 채움 — names = 그 로직 입력 이름 · 덮은 칸은 그대로 */
|
||
export function fillGiven(ref: CycleRef, names: string[], dist: Dist): Record<string, unknown> {
|
||
const own = new Set(ref.own || []);
|
||
const got = cycleTime(cycleInputs(ref, dist));
|
||
const given: Record<string, unknown> = { ...(ref.given || {}) };
|
||
for (const [name, slot] of Object.entries(CYCLE_FILL))
|
||
if (names.includes(name) && !own.has(name)) given[name] = got[slot];
|
||
return given;
|
||
}
|