쇼우 HN: 소코반 AI 솔버
1980년대 퍼즐 게임 소코반(창고지기)을 순수 자바스크립트로 포팅한 최적 해 솔버를 해커뉴스에 공개했습니다. 이 솔버는 매크로 푸시 A* 탐색, 비트마스크 상태 압축, 데드락 가지치기 등을 활용해 증명된 최소 이동 수의 최적해를 브라우저에서 밀리초 단위로 계산하며, 원래 C++ 네이티브 솔버를 웹으로 옮긴 것입니다.
소코반
소코반("창고지기")은 1980년대 퍼즐 게임으로, 모든 상자를 목표 지점으로 밀어 넣어야 합니다. 이 변형에서는 창고지기 역시 목표 지점 위에서 끝나야 합니다.
보드: 초기화, 되돌리기, AI로 풀기. AI 속도: 느림 / 보통 / 빠름. 다음 →
이동 횟수: 0 / 최적: – ▲ ◀ ▶ ▼
창고지기(플레이어) / 상자 / 목표 지점 / 목표 위의 상자 / 벽
게임 방법 및 규칙
창고는 격자(grid)로 되어 있습니다. 각 턴마다 창고지기는 위, 아래, 왼쪽, 오른쪽으로 한 칸씩 이동합니다. 창고지기는 벽이나 상자가 있는 칸으로 걸어 들어갈 수 없습니다. 상자 바로 너머의 칸(밀어내는 방향으로)이 빈 바닥이거나 목표 지점인 경우에만 상자 하나를 밀 수 있습니다. 한 턴에 움직이는 상자는 하나뿐이며, 공간을 만들기 위해 목표 지점 위의 상자를 다시 밀어낼 수도 있습니다.
조작법: 방향키 또는 W A S D, 혹은 화면상의 패드. '되돌리기'는 한 턴 뒤로 갑니다. '초기화'는 보드를 원래대로 되돌립니다.
목표: 움직일 수 있는 모든 개체, 즉 모든 상자와 창고지기가 목표 지점 위에 앉으면 퍼즐이 완성됩니다. 그래서 각 보드에는 상자보다 하나 더 많은 목표 지점이 있는 것입니다. 마지막 목표 지점은 창고지기의 것입니다.
목적: 최소한의 이동으로 그 상태에 도달하는 것입니다. 일부 보드의 경우 최적 이동 수가 알려져 있어 위에 표시됩니다. AI(허용 가능한 휴리스틱 사용)는 완전 탐색이 가능한 보드에서 최적해를 반환합니다.
AI 솔버의 작동 원리
소코반은 A* 탐색 문제이지만, 창고지기의 이동을 한 걸음씩 탐색하는 단순한 버전은 상자가 많은 보드에서 폭발적으로 늘어납니다. 여기서 실행되는 것은 제가 작성한 네이티브 C++ 최적 솔버의 순수 자바스크립트 포팅입니다. 그냥 어떤 해가 아니라 증명된 최소 이동 수의 해를 반환합니다:
이동 최적 매크로 푸시 A*. 각 탐색 간선(edge)은 상자 하나를 통째로 미는 것이며, 비용은 (밀 위치까지의 창고지기 최단 걷기 거리) + 1로 계산됩니다. 따라서 총합이 창고지기 이동 수의 실제 최솟값이 되는 동시에, 탐색은 개별 걸음을 건너뜁니다.
컴팩트 비트마스크 상태. 상자들은 보드의 도달 가능한 "살아있는" 칸들에 대해 32비트 정수 하나로 압축되고, 창고지기는 또 하나의 숫자로 표현됩니다. 즉 하나의 상태 전체가 약 1KB짜리 객체가 아니라 약 8바이트 키 하나가 됩니다. 수백만 개의 상태가 수십 MB에 들어갑니다.
다이얼 버킷 큐 + 개방 주소 해시. A* 프론티어는 비용을 키로 하는 버킷 큐이고, 방문 집합(해의 부모 링크 포함)은 평평한 타입드 배열 해시에 저장됩니다. 할당 없이(allocation-free) 캐시 친화적입니다.
데드락 가지치기. 정적 데드 스퀘어 테이블(목표 지점으로부터의 역방향 도달성)과 프리즈 검사를 통해 풀 수 없음이 증명된 상태를 버리며, 벽을 고려한 푸시 거리 하한으로 A*의 허용 가능성(admissibility, 즉 최적성)을 유지합니다.
보드 1~14는 브라우저에서 밀리초 만에 증명된 최적해로 실시간 해결됩니다(위에 "최적"으로 표시된 이동 수가 정확히 이 솔버가 반환하는 값입니다).
보드 15, 즉 8상자 미로는 예외입니다. 최적 탐색이 약 4,900만 개 상태를 살펴야 하고 1GB 이상의 메모리가 필요해 브라우저 탭 안에서 실행하기엔 너무 오래 걸립니다. 따라서 그 최적해(184 이동)는 이 알고리즘 자체의 네이티브 C++ 빌드(병렬 A* 탐색, 24코어에서 약 5초)로 오프라인 계산되고 재생으로 검증되었으며, 페이지는 단순히 그 미리 계산된 해를 재생합니다. 그래서 보드 15의 정답은 여기서 탐색되지 않고 하드코딩되어 있는 것입니다.
제 소코반 솔버에서 만들어졌습니다. 소코반에 대하여 →