
블록 퍼즐 난이도 설계: 지지 않는 게임을 시뮬레이션 봇으로 고친 과정
트레이마다 세 조각을 모두 놓을 수 있게 보장하면, 해법을 찾는 플레이어는 절대 지지 않습니다. 그래서 그 보장은 처음 10트레이에만 둡니다.
한판블록 클래식 모드는 처음 설계대로라면 게임 오버가 나지 않는 게임이었습니다. PRD 초안 그대로 만든 첫 공급 규칙(v1)에 트레이 전체를 계산하는 계획 봇을 붙였더니 80판이 전부 3,000수 상한까지 갔습니다. 사람이 해 보기 전, 2026년 10월 3일 봇 실험에서 나온 결과입니다. 출시본에 들어간 v7에서는 계획 봇 판당 중앙값이 122수, 탐욕 봇이 47수입니다.
숫자는 sugar-game 저장소의 공급 실험 기록(docs/block/lab.md, 2026-10-03 측정), PRD 검증 보고서, 엔진 코드와 테스트에서 가져왔습니다. 기준일은 2026년 10월 19일입니다.
목차 (7)
"항상 놓을 수 있다"는 약속이 게임 오버를 지웠습니다
한판블록은 8×8 판에 조각 세 개를 받아 놓고, 가로나 세로 줄이 차면 지워지는 블록 퍼즐입니다. 이 세 조각 묶음을 트레이라고 부릅니다. 세 조각을 다 놓으면 다음 트레이가 나옵니다.
출발점이 된 PRD v2.0 초안의 7.1절은 이렇게 약속했습니다. "새 세 조각을 받을 때, 현재 판에서 그 세 조각을 모두 놓을 수 있는 순서가 적어도 하나 있다." 블록 공급이 억울하다는 반응을 막으려는 문장이었고, "배치 선택 때문에 중간에 막힐 수 있다"는 단서도 붙어 있었습니다.
이 단서는 배치를 잘못하는 사람에게만 해당합니다. 잘하는 사람에게는 이렇게 됩니다.
- 트레이를 받는 순간, 세 조각을 다 놓는 해법이 있습니다.
- 그 해법대로 두면 트레이가 빕니다.
- 다음 트레이도 같은 보장을 받습니다. 1번으로 돌아갑니다.
판이 끝나지 않습니다. 이 증명은 조각 가중치와 상관이 없어서, 어려운 조각을 많이 섞어도 결론이 바뀌지 않습니다(아래 표의 v3, v4).
탐욕 봇과 계획 봇을 같은 시드로 돌렸습니다
봇은 두 종류입니다. 엔진이 판을 64비트 정수 하나로 다루기 때문에, 판 평가도 비트 연산 몇 번으로 끝납니다.
- 탐욕 봇: 지금 둘 수 있는 모든 수를 아래 점수로 매기고 가장 높은 수를 둡니다. 줄 하나가 10점이라 대개 줄을 가장 많이 지우는 수가 뽑힙니다.
- 계획 봇: 트레이에 남은 조각의 모든 순서와 위치를 계산하고, 가장 좋은 계획의 첫 수만 둡니다. 다음 수에서 다시 계산합니다.
두 봇이 쓰는 점수는 같습니다.
점수 = 지운 줄 × 10 − 3 × 구멍 − 0.3 × 찬 칸 + 2 × 큰 조각 자리
구멍 = 상하좌우가 모두 막힌 빈칸 수
큰 조각 자리 = 3×3 정사각형, 가로 4칸, 세로 4칸이 각각 들어갈 곳이 있는지 (0~3)
최종 비교에서는 버전마다 탐욕 봇 160판, 계획 봇 80판을 돌렸고, 판 시드는 모든 버전이 같습니다. 3,000수에 닿으면 판을 끊습니다. 봇은 사람의 모형이 아닙니다. 사람은 두 봇 사이 어딘가에 있다고 보고, 봇 숫자는 버전끼리 순위를 매기는 데만 씁니다.
결정에 쓴 지표 네 개
- 계획 봇의 3,000수 상한 도달 수: 0이 아니면 그 버전은 탈락입니다.
- 계획 봇 중앙값 / 탐욕 봇 중앙값: 실력 차이가 판 길이로 얼마나 드러나는지 봅니다. 점수 도전 모드에서는 "잘하면 오래 간다"가 재미의 대부분입니다.
- 탐욕 봇 판 길이: 서툰 사람이 너무 빨리 끝나지 않는지 봅니다.
- 트레이 생성 시간 p95: 기기에서 공급 비용이 문제가 되는지 봅니다.
공급 규칙 v1~v7 비교
어려운 조각은 3×3 정사각형, 2×3 직사각형 두 방향, 4칸 직선 두 방향입니다. "압력"은 일정 수마다 이 조각들의 가중치를 기본값의 1배씩 더 올리는 규칙입니다.
| 버전 | 공급 규칙 | 탐욕 p50 | 계획 p50 | 계획 봇 상한 도달 | 판정 |
|---|---|---|---|---|---|
| v1 | PRD 그대로: 모든 트레이에서 세 조각 전부 보장 | 56수 | 3,000수 | 80/80 | 탈락 |
| v2 | v1 + 빈칸이 28개 미만이면 3칸 이하 조각 가중치 3배 | 결과 표에 없음 | 폐기(판을 쉽게 만드는 방향) | ||
| v3 | v1 + 압력(30수마다, 최대 5배) | 결과 표에 없음 | 60/60 | 탈락 | |
| v4 | v1 + 압력(20수마다, 최대 8배) | 결과 표에 없음 | 60/60 | 탈락 | |
| v5 | v7 + 압력(30수마다, 최대 5배) | 44수 | 80수 | 0 | A/B 후보 |
| v6 | v7 + 압력(20수마다, 최대 8배) | 44수 | 82수 | 0 | 채택 안 함 |
| v7 | 처음 10트레이만 전부 보장, 이후에는 "한 조각 이상 놓을 수 있음"만 보장 | 47수 | 122수 | 0 | 기본값 |
v1에서 계획 봇은 판당 트레이 중앙값 1,001개, 점수 중앙값 26,772점을 찍었습니다. v7에서는 41트레이, 998점입니다. 수치가 남은 네 버전(v1, v5, v6, v7)에서 탐욕 봇은 한 판도 상한에 닿지 않았습니다.
v7을 고른 이유는 실력 차이입니다. 계획 122수 대 탐욕 47수로 2.6배인데, 압력을 얹은 v5와 v6는 이 차이가 1.8~1.9배로 줄어듭니다. 판이 짧으면 판이 끝나는 횟수는 늘지만, 잘하는 사람이 덜 보상받습니다. 그래서 v7로 출시하고 v5를 A/B 후보로 남겼습니다.

공급 비용은 걱정할 수준이 아니었습니다. 트레이 생성 p95는 표에 수치가 있는 버전 모두 0.2ms 이하였고, PRD가 둔 마지막 복구 단계(1칸 조각 세 개)는 Python 시뮬레이션 2,710트레이에서 한 번도 쓰이지 않았습니다.
PRD에 "항상 ~할 수 있다"는 약속이 있다면, 그 약속을 끝까지 이용하는 봇부터 돌리십시오. 문장 검토로는 이 결함이 보이지 않습니다.
AI의 첫 검증은 반대 방향을 권했습니다
같은 날 앞서 나온 PRD 검증 보고서(AI 코딩 에이전트가 작성)는 Python으로 공급을 그대로 구현해 무작위 봇과 한 수 탐욕 봇을 150판씩 돌렸습니다. 판당 중앙값은 17수와 26수였습니다. 트레이 전체를 읽는 봇도 시도했지만, 빈 판에서 트레이 하나를 탐색하는 데 10분이 넘어 중단했습니다.
보고서는 짧은 판만 보고 "해법 보장은 판 길이를 보장하지 않는다"고 결론 냈습니다. 그리고 판이 꽉 차면 작은 조각을 더 주는 "여유 공급"을 추가하자고 권했습니다. 표의 v2가 그것입니다.
보고서는 가장 약한 봇으로, 가장 강한 플레이어에게만 드러나는 약속을 검증했습니다. Kotlin 엔진(64비트 비트보드)이 나온 뒤에야 계획 봇이 현실적인 시간에 돌았고, 거기서 v1의 계획 봇 판이 전부 상한에 닿았습니다. v2는 폐기됐고 PRD는 v2.1에서 공급 약속을 v7로 고쳤습니다. 이 과정은 커밋 cd62087(2026-10-04)에 엔진, 실험 도구, 테스트와 함께 들어갔습니다.
(Python 쪽 탐욕 봇은 판 평가 식이 달랐습니다. 큰 조각 자리 항이 없었죠. 그래서 Kotlin 탐욕 봇의 v1 중앙값 56수와 직접 비교하지 않습니다.)
v1이 지지 않는다는 사실은 ClassicTest의 a planner cannot be stopped under the full guarantee로 고정했습니다. 시드 20개에서 매 트레이 해법대로 두면 300수를 넘기는지 확인하는 테스트입니다.
다음에 확인할 것
- 사람의 판 길이는 아직 모릅니다. 목표는 판당 중앙값 60~150수(약 4~10분)이고, 벗어나면 v5로 바꿉니다. 판 끝에 수를 함께 보내는
post_score이벤트는 2026-10-17 GA4 분석 기준으로 전체 기간 2회뿐이었습니다. 같은 분석에서 클래식 모드가 첫 실행 흐름에 보이지 않는다는 점도 확인해, 1.1.2(d1f6de1)에서 마지막 튜토리얼 뒤에 클래식으로 가는 버튼을 붙였습니다. - 1.1.4(
b2d305d, 2026-10-17)부터 클래식 부활이 판당 2회입니다. 공급 실험은 부활 없이 돌렸으므로, 부활을 넣은 판 길이를 다시 재야 합니다. - 기본 공급의 규칙 자체는 테스트(
default supply guarantees the first ten trays fully and never deals a dead tray after)가 지키고 있어서, 기본값을 v1으로 되돌리면 이 테스트가 깨집니다. 하지만 기본 공급에서 계획 봇이 실제로 상한 전에 지는지는 테스트가 없습니다. 지금은 공급 실험을 다시 돌려야만 알 수 있습니다.
같은 저장소에서 앱 네 개를 먼저 낸 과정은 AI 코딩 에이전트로 20일 만에 Android 앱 4개를 출시한 방법에 있습니다.
자주 묻는 질문
블록 퍼즐 게임 오버 조건은 어떻게 정하나요?
남은 조각 중 어느 것도 놓을 곳이 없으면 게임 오버입니다. 다만 공급 규칙이 "항상 전부 놓을 수 있는 트레이"만 주면 잘하는 사람에게는 이 조건이 오지 않습니다. 한판블록은 처음 10트레이 뒤로는 "한 조각 이상 놓을 수 있음"만 보장합니다.
어려운 조각 가중치를 올리면 해결되지 않나요?
해결되지 않았습니다. 어려운 조각 가중치를 최대 8배까지 올린 v4에서도 계획 봇 판이 전부 3,000수 상한까지 갔습니다. 전부 보장이 남아 있는 한, 가중치는 어떤 풀리는 트레이가 나올지만 바꿉니다.
밸런스 시뮬레이션 봇은 몇 판이나 돌려야 하나요?
한판블록은 최종 비교에서 버전마다 탐욕 봇 160판, 계획 봇 80판을 돌렸고, 같은 시드를 모든 버전에 썼습니다(앞선 v3, v4 실험은 계획 봇 60판). 이 정도로도 상한 도달 80/80과 0/80처럼 결론이 갈리는 차이는 분명하게 보였습니다.
이 글은 SugarMount가 직접 측정한 값으로 쓰고, 초안 작성에 AI 코딩 에이전트를 썼습니다.
다른 AX 노트
- 화살표 퍼즐 1,100판을 만든 역구성 생성기와 G2 게이트
- '시간이 너무 길어서 쉬움' 테스터 의견을 시뮬레이션으로 검증해 퍼즐 목표 시간을 30% 줄였다
- 퍼즐 게임 첫날 이탈 분석: 기기별 이벤트 순서와 판별 계산으로 찾은 첫 장의 벽 4판
- Android assets를 미리 gzip한 실측: APK 이득은 0, .pack.gz는 .pack이 되어 FileNotFoundException
- SKT 판매 삼성 폰에서 market://을 열면 스토어 선택 창이 뜬다: Play 패키지부터 지정하기
- addOnCompleteListener(this)가 onStop에서 지운 리스너 때문에 스플래시에 멈춘 버그