주말 동안 2048을 만든 방법 — 게임 루프 전체
2026-06-29
최근 ToolKoala에 2048을 추가했는데, 가장 기분 좋은 놀라움은 실제 게임이 얼마나 작은가였습니다. 애니메이션과 다듬기에는 시간이 걸리지만, 규칙 — 슬라이드, 합치기, 생성, 게임 오버 확인 — 은 약 예순 줄에 들어맞아요. 루프 전체가 어떻게 동작하는지 보겠습니다.
보드는 그냥 평면 배열
그리드는 4×4이지만, 저는 이걸 숫자 16개의 평면 배열로 저장합니다. 0은 빈 칸을 뜻해요:
[2, 0, 0, 4,
0, 2, 0, 0,
0, 0, 0, 0,
4, 0, 0, 2]
평면 배열은 복사하고, 비교하고, localStorage에 저장하기 쉽습니다. 행 r, 열 c는 인덱스 r * 4 + c에 있어요.
함수 하나가 진짜 일을 다 한다
모든 이동 — 좌, 우, 상, 하 — 은 네 타일로 이루어진 한 줄에 대한 동일한 연산입니다: 모두를 한쪽 끝으로 밀고, 같은 이웃은 한 번만 합치기. 그게 함수 하나예요:
function compress(line) {
const arr = line.filter(v => v) // 0을 버린다
const res = []
let gained = 0
for (let i = 0; i < arr.length; i++) {
if (arr[i] === arr[i + 1]) { // 같은 타일 둘이 닿음 → 합친다
res.push(arr[i] * 2)
gained += arr[i] * 2
i++ // 방금 합친 것은 건너뛴다
} else {
res.push(arr[i])
}
}
while (res.length < 4) res.push(0) // 다시 길이 4로 채운다
return { line: res, gained }
}
합친 뒤의 i++가 4 4 4 4가 단일 16으로 무너지는 것을 막는 규칙입니다. 그건 8 8이 돼요 — 각 타일은 한 번의 이동에서 최대 한 번만 합쳐집니다.
한 방향에서 네 방향
저는 "왼쪽으로 슬라이드"만 작성했습니다. 나머지 셋은 이걸 재사용해요:
- 오른쪽 — 행을 뒤집고, 왼쪽으로 압축하고, 다시 뒤집는다.
- 위 / 아래 — 보드를 행 대신 열로 읽은 다음, 같은 좌/우 로직.
그래서 한 이동은 각 행이나 열을 잡고, 선택적으로 뒤집고, compress를 돌리고, 다시 써넣습니다. 화살표마다 별도 코드가 없어요 — 그저 어느 줄을 읽느냐와 뒤집느냐만 다를 뿐입니다.
생성한 뒤, 막혔는지 확인하기
보드를 실제로 바꾼 이동 후에는, 무작위 빈 칸에 새 타일이 나타납니다 — 대부분 2, 가끔 4. 그런 다음 아직 가능한 이동이 있는지 확인해요: 빈 칸이 있는가, 아니면 같은 이웃 둘이 있는가? 없다면 게임 오버입니다.
function canMove(g) {
if (g.includes(0)) return true // 빈 칸 → 가능
// 같은 가로/세로 이웃이 있는가 → 아직 합치기 가능
// ...작은 루프로 확인...
return false
}
"보드가 실제로 바뀌었는가?" 확인은 중요합니다: 이동이 아무것도 안 했다면, 공짜 새 타일을 받아선 안 돼요. 벽에 대고 왼쪽을 누르는 것은 아무 동작도 없어야 합니다.
내게 ref를 쓰게 가르쳐 준 버그
첫 버전은 키 핸들러 안에서 React 상태로부터 보드를 곧장 읽었습니다. 빠른 키 반복에서는 React가 다시 렌더링하기 전에 두 번의 화살표 입력이 발생할 수 있었고, 그래서 두 번째 입력이 오래된 보드를 읽어 이동이 누락됐어요. 해결책은 최신 보드와 점수를 미러링하는 ref를 두고, 이동 핸들러가 그 ref를 읽게 하는 것이었습니다. 상태는 보이는 것을 결정하고, ref는 로직을 결정합니다. 그 후로는 화살표를 마구 눌러도 제대로 동작해요.
이어하기와 최고 점수, 전부 로컬
두 가지가 localStorage에 있습니다: 당신의 최고 점수, 그리고 현재 보드. 이동할 때마다 보드를 저장하고, 게임이 끝나면 지웁니다. 로드 시 유효한 미완료 게임이 있으면 복원하고 작은 "이어하기" 안내를 보여줘요 — Sudoku와 Word Search에서 쓰는 것과 같은 패턴입니다. 아무것도 업로드되지 않아요. 당신의 게임은 당신의 것, 당신의 기기 위에 있습니다.
해보기
여기서 2048을 플레이할 수 있어요 — 키보드나 스와이프로, 페이지가 한 번 로드되면 오프라인에서도 동작합니다. 이런 걸 좋아한다면, Sudoku 생성기 뒤에는 더 흥미로운 알고리즘이 있어요.
자주 묻는 질문
2048은 프로그래밍하기 어렵나요? 핵심은 놀랍도록 작습니다 — "한 줄을 슬라이드하고 합치는" 함수 하나를 네 방향 모두에 재사용하고, 거기에 타일 생성과 게임 오버 확인을 더하면 됩니다. 다듬기(애니메이션, 터치 조작, 진행 저장)에 대부분의 시간이 들어가요.
합치기 규칙은 어떻게 동작하나요? 같은 숫자의 타일 둘이 함께 밀리면, 값이 두 배인 한 타일로 결합됩니다 — 그리고 각 타일은 한 이동에서 한 번만 합쳐질 수 있어서, 2 네 개로 된 줄은 4 두 개가 되지 8 하나가 되지 않아요.
네 방향은 어떻게 처리하나요? 한 방향만 구현하면 됩니다. 오른쪽은 행을 뒤집은 왼쪽이고, 위와 아래는 행 대신 열에 같은 로직을 적용한 것입니다.
ToolKoala의 2048이 제 게임을 저장하나요? 네 — 최고 점수와 현재 보드가 브라우저의 로컬 스토리지에 저장되므로, 탭을 닫았다가 나중에 다시 이어갈 수 있어요. 절대 기기를 떠나지 않습니다.
— Milo 🐨