[TIL] 2026-06-16 — 가구 운반 시스템 추가분: 수식 정식화·튜닝 노브·수용 기준 + LeetCode 416 DP
어제 정리한 “Project A 가구 옮기기” 기획안의 후속 추가분을 정리한다. 팀이 시스템 기획을 별도 스펙 문서(
furniture-carry-system.md)로 떼어내면서, 어제 발행본에는 없던 수식 정식화·튜닝 노브 표·수용 기준·미결 확장이 새로 들어왔다. 여기서는 그 신규 부분만 추린다. 더해 이날 푼 LeetCode 416 Partition Equal Subset Sum DP 풀이를 요약한다.
무엇이 새로 추가됐나 (어제 발행본 대비)
어제 발행본은 Google Doc 기준으로 One Pager·코어 루프·역할·상태 변수·IPOF·예외 케이스·DataTable·에셋 접두사까지 다뤘다. 별도 스펙 문서에서 그 위에 새로 얹힌 부분만 정리하면 아래와 같다.
| 신규 섹션 | 어제 발행본 | 추가분 |
|---|---|---|
| Player Fantasy | 코어 판타지를 One Pager에 한 줄로만 | “왁자지껄한 협동 파티” 의도를 별도 절로 명문화 |
| Formulas | 감속 공식을 IPOF 안에 한 줄 언급 | 감속·충돌 데미지 공식을 절로 분리 + 예시 수치 계산 |
| Tuning Knobs | DataTable(가구 4행)만 | 조정 가능 값 표(각 노브의 영향·비고) 신설 |
| Acceptance Criteria | 없음 | 구현 검증용 체크리스트 8항목 신설 |
| 미결 사항 | 2항목(점프·달리기, 던지기) | +2항목(감속 공식 방향성, 낙하 데미지 산정) |
| Dependencies | 입력/출력/연동 나열 | 상호참조 지시(타 시스템 문서에서 의존 명시) |
상태 변수·IPOF·예외 케이스·DataTable 4행은 어제와 동일하므로 다시 옮기지 않는다.
Player Fantasy 명문화
어제는 코어 판타지를 One Pager 안에 “긴장감 + 우정 파괴” 두 줄로만 적었는데, 스펙 문서에서는 이를 독립된 절로 끌어올려 의도를 못박았다.
“친구와 손발을 맞춰 무거운 가구를 옮기는 협동의 쾌감 — 그리고 한 끗 어긋났을 때의 폭소(우정 파괴).”
핵심은 실패가 곧 콘텐츠라는 설계 의도다. 여러 명이 같은 가구를 들고 방향을 맞춰야만 나아가고, 한 명이 엇나가거나 놓으면 가구가 멈추거나 떨어진다. 성공하면 합이 맞는 쾌감, 실패하면 책임 공방과 웃음 — “왁자지껄한 협동 파티”를 노린다는 톤이 문서에 박혔다. 단순 문구 추가가 아니라, 뒤따르는 수식·튜닝 노브가 무엇을 위해 존재하는지(실패 순간의 재미를 만들기 위한 손잡이)를 정해주는 기준점이다.
수식 정식화
어제 발행본은 감속을 IPOF 안에 한 줄(정상 − (현재인원/필요인원)×10)로만 적었다. 스펙 문서는 두 공식을 절로 분리하고 예시 수치로 계산해 검증한다.
이동 속도 (인원 부족 시 감속)
1
2
3
4
5
인원 충족 (CurrentGrabbedPlayer >= RequiredPlayer):
Speed = BaseSpeed
인원 부족 (CurrentGrabbedPlayer < RequiredPlayer):
Speed = BaseSpeed − (CurrentGrabbedPlayer / RequiredPlayer) × 10
- 변수:
BaseSpeed(가구별 기준 속도, DT),CurrentGrabbedPlayer(현재 인원),RequiredPlayer(최소 인원) - 예시: Long_Sofa(BaseSpeed 80, RequiredPlayer 2)를 1명이 들 때 →
80 − (1/2)×10 = 75
어제 메모로만 짚었던 문제가 문서에 공식 미결로 명시됐다. 이 식은 든 인원이 적을수록 빼는 값이 작아진다. 즉 혼자 들수록 오히려 덜 느려져서 “혼자선 훨씬 굼떠야 한다”는 의도와 반대다. 문서는 대안으로 곱셈형 BaseSpeed × (CurrentGrabbedPlayer / RequiredPlayer)를 제시한다. 같은 예시를 이 대안으로 풀면 80 × (1/2) = 40으로, 인원이 적을수록 확실히 느려진다. 팀과 확정해야 할 1순위 항목.
충돌 데미지
1
2
CurrentHealth −= 충격량(Impulse) × CollisionDamageMultiplier
파괴 판정: CurrentHealth <= 0 → 가구 완전 파괴
- 변수:
충격량(물리 엔진 충돌 impulse),CollisionDamageMultiplier(가구별 배율, DT) - 예시: TV(Multiplier 40) 충돌, 충격량 7 →
CurrentHealth −= 280
TV는 MaxHealth가 250인데 한 번의 충돌(충격량 7)이 280을 깎는다. 단 한 번의 큰 충돌로 즉사한다는 뜻이다. DataTable에서 TV가 “2인이지만 충돌 시 치명적”이라고 적힌 이유가 이 수식으로 수치화됐다. 배율 40은 “TV는 절대 부딪히면 안 되는 가구”라는 난이도 장치다.
튜닝 노브 표
어제는 가구별 수치(DataTable 4행)만 있었는데, 스펙 문서는 각 값이 게임플레이에 어떤 방향으로 작용하는지를 따로 표로 정리했다. 밸런싱할 때 “이 숫자를 올리면 뭐가 바뀌나”를 한눈에 보는 손잡이 맵이다.
| 노브 | 영향 | 비고 |
|---|---|---|
MaxHealth | 가구가 견디는 충돌량 | 클수록 파손에 관대 |
RequiredPlayer | 협동 강제 정도 | 클수록 협동 필수 |
BaseSpeed | 운반 템포 | 무거운 가구일수록 낮게 |
CollisionDamageMultiplier | 충돌 페널티 강도 | 클수록 “조심” 압박 |
감속 계수(현재 ×10) | 인원 부족 시 페널티 | 감속 식 확정 후 범위 설정 |
| 낙하 데미지 계수 | 놓기 페널티 | [확인 필요] |
| 1인 잔류 자동 낙하 시간(현재 3초) | 우정파괴 텀 | 길수록 만회 기회↑ |
마지막 두 행이 “우정 파괴” 판타지와 직접 연결된다. 1인 잔류 자동 낙하 시간(2인 이상에서 한 명만 놓았을 때 자동으로 떨어지기까지의 텀, 현재 3초)을 길게 잡으면 동료가 다시 잡아 만회할 여지가 커지고, 짧게 잡으면 실수 한 번이 곧바로 파손으로 이어진다. 이 노브가 게임의 관대함/잔혹함 비율을 직접 조절한다.
수용 기준 (Acceptance Criteria)
어제 발행본에 없던 구현 검증용 체크리스트가 신설됐다. 기획이 “이렇게 동작해야 함”을 테스트 가능한 문장으로 못박은 것이라, 구현·QA의 기준선이 된다.
- 상호작용 입력 시
CurrentGrabbedPlayer가 +1,bIsGrabbed가 True로 전환 CurrentGrabbedPlayer >= RequiredPlayer면 BaseSpeed, 미만이면 감속 공식 결과 속도로 이동- 두 플레이어 정반대 입력 시 가구 제자리 정지(
CombinedVelocity == 0) - 충돌 시
CurrentHealth -= 충격량 × CollisionDamageMultiplier, 0 이하면 파괴 + 점수 하락 - 이동 중 놓기 / 2인 중 1명만 놓고 3초 경과 자동 낙하 시 낙하 데미지 적용
- 트럭에 실으면 잔여 내구도 반영 점수가 GameMode로 전달
- DT_FurnitureData 4행(Chair/Sofa/Fridge/TV) 수치가 런타임 정상 적용(하드코딩 없음)
- 잡기/이동/인원부족/충돌 피드백이 IPOF 표대로 재생
이 목록을 보면 시스템이 3개 시스템과 맞물려 있음이 명확하다. 캐릭터 컨트롤(입력) → 가구(물리·내구도) → GameMode(점수). “하드코딩 없음” 기준은 곧 DataTable 연동을 강제하는 항목이다.
미결 사항 확장 · 상호참조
미결이 어제 2개에서 4개로 늘었다(추가분만 표시).
- (기존) 가구를 든 상태에서 캐릭터 움직임 제한(점프·달리기) 여부
- (기존) 가구 던지기 기능 추가 여부
- (신규) 감속 공식의 방향성/단위 — 현재 식이 의도와 반대일 가능성, 재검토 필요
- (신규) 낙하 데미지 수치 산정 방식
또한 Dependencies에 상호참조 지시가 붙었다. 캐릭터 컨트롤 / GameMode(점수 판정) / 가구 Prop 문서에서 본 시스템을 “의존 대상”으로 역으로 명시하라는 것 — 시스템 문서들이 서로를 가리키도록 묶어 누락 연결을 막으려는 의도다.
LeetCode 416 — Partition Equal Subset Sum
이날 푼 알고리즘. 양의 정수 배열을 합이 같은 두 부분집합으로 나눌 수 있는지 판정한다. 풀이 전문은 별도 발행본에 있고, 여기서는 핵심만 요약한다.
- 환원: “두 집합을 같게 나눈다” = “전체 합의 절반
target을 만드는 부분집합이 있는가”. 한쪽이 target이면 나머지도 자동 target이라 부분집합 하나만 찾으면 된다. - 가지치기: 전체 합이 홀수면 즉시 false(절반이 정수가 안 됨).
- DP:
dp[j]= 원소를 골라 합j를 만들 수 있는가.dp[0]=true에서 시작, 각num에 대해j를target → num역순으로 돌며dp[j] |= dp[j-num]. 정답은dp[target]. - 역순이 핵심: 정순으로 돌면 방금 갱신한
dp[j-num]을 같은 패스에서 다시 참조해 한 원소를 중복 사용하는 꼴이 된다. 역순이라야 0/1(원소 1회) 제약이 지켜진다. - 제약
nums[i] <= 100, 길이<= 200→ target 최대 1만,O(n·target)로 충분히 빠름.
전문: LeetCode 416 발행본
오늘 배운 것 정리
- 기획 문서는 “수치를 식으로 박는 순간” 검증 가능해진다. 어제 한 줄이던 감속 표현이 예시 계산(80→75)으로 풀리자마자, 식의 방향이 의도와 반대라는 게 드러났다. 글로 두루뭉술하면 안 보이던 버그가 수식+예시에서 잡힌다.
- 튜닝 노브 표 = 밸런싱 손잡이 맵. 각 변수의 “영향/비고”를 분리해두면, 게임이 너무 어렵거나 쉬울 때 어떤 숫자를 만질지 바로 안다. 특히 “1인 잔류 자동 낙하 시간”이 게임의 관대함을 직접 조절한다.
- 수용 기준은 기획·구현의 계약서다. 테스트 가능한 문장 8개로 적으니, 캐릭터 컨트롤→가구→GameMode 3개 시스템의 경계와 “하드코딩 금지(DataTable 강제)”가 명확해졌다.
- 냅색 DP는 환원과 역순이 전부다. “양분 가능?”을 “절반 만들기 가능?”으로 바꾸고, 역순 순회로 원소 1회 제약을 지키면 끝. 홀수 합 가지치기로 입력 절반을 즉시 건다.