AI가 실제로 2048을 이기는 방법 (LLM이 아닌 Expectimax)
요약
2048 게임을 해결하기 위해 LLM 대신 Expectimax 탐색 알고리즘을 사용하는 원리를 설명합니다. 확률적 요소가 포함된 게임 환경에서 최적의 수를 찾기 위한 Max 레이어와 Chance 레이어의 작동 방식 및 휴리스틱 설계법을 다룹니다.
핵심 포인트
- LLM은 텍text 예측 모델로 게임 트리 탐색에는 부적합함
- Expectimax는 무작위 타일 생성을 확률적으로 고려하는 알고리즘임
- Minimax와 달리 자연(Nature)의 확률적 움직임을 모델링함
- 위치, 빈 칸, 매끄러움 등을 활용한 휴리스틱 점수 산정이 핵심임
이 포스트의 모든 수치는 우리가 직접 실행 가능한 250회 게임 셀프 플레이(self-play) 벤치마크에서 도출되었습니다. 여기에는 추정치가 포함되어 있지 않습니다.
만약 여러분이 "실제로 2048을 이길 수 있는 AI 도구가 있나요?"라고 물어본 적이 있다면, 대답은 '예'입니다. 그리고 흥미로운 점은 어떤 종류의 AI가 이를 수행하느냐 하는 것입니다. 그것은 언어 모델(Language Model)이 아닙니다. 2048을 해결하는 AI는 네트워크 호출 없이 브라우저 탭에서 실행할 수 있는 작고 결정론적인 탐색 알고리즘(deterministic search algorithm)입니다. 여기에서 그 알고리즘이 정확히 어떻게 작동하는지, 그리고 어디에서 한계에 부딪히는지 설명합니다.
왜 LLM이 아닌가?
보드 상태를 채팅 모델에 붙여넣고 다음 수를 물어볼 수는 있습니다. 그러면 모델은 종종 그럴듯한 수를 제시하겠지만, 때로는 불법적인 수나 패배로 이어지는 수를 제시하기도 합니다. 왜냐하면 언어 모델은 _텍스트(text)_의 다음 토큰(token)을 예측하는 것이지, _게임 트리(game tree)_의 다음 수를 예측하는 것이 아니기 때문입니다. 운에 맡기는 게임에서 승리하는 것은 탐색 문제(search problem)이며, 우리는 이미 이를 위한 정확한 알고리즘을 가지고 있습니다.
| 게임 트리 탐색 (Game-tree search) | 언어 모델 (A language model) | |
|---|---|---|
| 수가 선택되는 방식 | 트리를 탐색하여 특정 합법적인 수를 반환 | 토큰을 예측; "수"는 모델이 쓰는 내용 그 자체 |
| ... |
핵심 아이디어: Expectimax
2048은 운과 싸우는 게임입니다. 여러분이 방향을 선택하면, 게임은 무작위 빈 칸에 무작위 타일(90% 확률로 2, 10% 확률로 4)을 떨어뜨립니다. 이에 적합한 도구는 두 가지 레이어 유형이 교차하는 트리인 **Expectimax 탐색 (expectimax search)**입니다.
- Max 레이어에서 AI는 네 가지 모든 수를 시도하고 가장 좋은 수를 유지합니다.
- Chance 레이어에서 AI는 새로운 타일이 떨어질 수 있는 모든 칸을 고려하며, 확률에 따라 가중치를 두어 결과의 _평균(average)_을 냅니다.
여러 레이어를 깊게 살펴봄으로써, AI는 현재 좋아 보이는 것을 덥석 잡는 대신, 운 나쁜 타일 생성(spawn)까지 고려하여 가능성 높은 미래가 가장 강력한 수를 선택합니다.
왜 Minimax가 아닌가? Minimax는 당신에게 가장 _최악_의 타일을 내놓는 적대자(adversary)가 있다고 가정합니다. 하지만 2048의 타일은 무작위일 뿐, 악의적이지 않습니다. 결과의 평균을 내는 것(expectimax)이 실제 게임을 모델링합니다. 반면 minimax는 너무 방어적으로 플레이할 것입니다. 이것은 교과서적인 구분입니다. 체스에는 minimax를, 자연(nature)을 상대로 하는 게임에는 expectimax를 사용합니다.
휴리스틱 (Heuristic): 보드 점수 산정
탐색(Search)을 수행하려면 끝까지 플레이할 수 없는 보드에 점수를 매길 방법이 필요합니다. 전체 평가는 다음 세 가지 항으로 구성됩니다.
score = positional + empties × 200000 + smoothness × 4000
- Positional (corner-snake) — 각 칸은 고정된 순위(rank)를 가집니다. 타일의 값은
4^rank를 곱하여 계산됩니다. 가중치가 4의 거듭제곱으로 증가하기 때문에, 구석에 있는 큰 타일 하나가 모든 것을 압도합니다. 따라서 탐색 과정에서 가치를 구석 방향으로 스네이크(snake) 순서에 따라 쌓아 올릴수록 보상을 받게 됩니다. - Empty squares (빈 칸) — 모든 빈 셀은 고정값
200000의 가치를 가집니다. 빈 공간은 향후 움직임을 유효하게 유지해 주는 핵심 요소이므로, 타일의 크기가 아무리 크더라도 보드가 거의 가득 차면 점수는 거의 0에 가깝게 산정됩니다. - Smoothness (매끄러움) — 인접한 각 쌍에 대해
|log2(a) − log2(b)|를 뺍니다. 합칠 수 있는 인접 타일들은 비용이 거의 들지 않지만, 2 옆에 512가 있는 경우는 감점을 받습니다. 들쭉날쭉한 보드는 더 낮은 점수를 받습니다.
실제로 얼마나 잘 플레이할까?
우리는 헤드리스(headless) 상태로 정확한 탐색 코드를 250번의 전체 게임 동안 실행했습니다.
| 대상 / 항목 | 최고 타일 | 비고 |
|---|---|---|
| 이론적 최대치 (Theoretical maximum) | 131,072 | 4×4 보드의 절대적 한계 |
| ... |
결과적으로 단순한 expectimax 솔버는 약 **70%**의 게임에서 2048 승리 조건을 달성하며, 약 **30%**의 게임에서는 4096까지 도달합니다. 그리고 기본적으로 8192에는 거의 도달하지 못합니다. 최첨단 연구용 AI(expectiminimax 및 엔드게임 테이블베이스 포함)는 두 단계 더 높은 65,536까지 도달하지만, 이들조차 약 8%의 확률로만 달성합니다. 이론적인 한계치인 131,072는 일반적인 플레이에서는 결코 도달할 수 없습니다.
직접 해보기 / 재현하기
**lkforge.com/games/2048**의 무료 브라우저 게임에서 Autoplay를 켜면 이 솔버가 실행되는 모습을 직접 볼 수 있습니다. 설치나 계정이 필요 없으며, 완전히 사용자의 기기에서 실행됩니다. 전체 휴리스틱 분석과 벤치마크 방법론은 원본 글에서 확인할 수 있습니다.
엔진은 직접 코드를 읽거나, require()로 불러오거나, 직접 벤치마크 (benchmark)를 실행하고 싶다면 **오픈 소스 (open source, MIT)**로 공개되어 있습니다: github.com/lucian-devops/2048-ai-solver — 또한 AI가 플레이하는 모습을 지켜볼 수 있는 실시간 셀프 플레이 데모 (live self-play demo)도 있습니다.
직접 구현해보고 싶다면: 3~5 단계의 깊이 (depth)를 가진 엑스펙티맥스 (Expectimax) 알고리즘을 구현하고, 위에서 언급한 3개 항 휴리스틱 (three-term heuristic)을 사용한 뒤, 수백 번의 셀프 플레이 게임을 실행하여 본인만의 도달률 (reach rates)을 측정해 보세요. 이 모든 과정은 수백 줄의 JavaScript 코드로 충분히 구현 가능합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기