웹 기반 게임 개발은 단순히 로직을 짜는 것을 넘어, 브라우저의 특성과 사용자 경험(UX)을 모두 고려해야 하는 정밀한 작업입니다. 2048 게임의 실제 코드를 통해 핵심 알고리즘을 분석해 보겠습니다.
1. 효율적인 타일 이동 로직: 방향의 일반화
2048 게임에서 가장 복잡한 부분은 상하좌우 네 방향으로의 이동과 숫자 병합입니다. 이를 각각 구현하면 코드가 비대해지고 유지보수가 힘들어집니다.
// 핵심 아이디어: 모든 이동을 '왼쪽 이동'으로 치환하여 처리
function processMove(direction) {
let moved = false;
for (let i = 0; i !== 4; i++) {
let line = [];
for (let j = 0; j !== 4; j++) {
// 방향에 따라 r, c 인덱스를 계산하여 라인 추출
let r = (direction === 'L' || direction === 'R') ? i : (direction === 'U' ? j : 3 - j);
let c = (direction === 'U' || direction === 'D') ? i : (direction === 'L' ? j : 3 - j);
if (g2048_board[r][c]) line.push(g2048_board[r][c]);
}
// 추출된 line을 왼쪽으로 미는 로직(slideAndMerge) 하나로 통일
// ... 후속 처리
}
}
- 알고리즘 분석: 위 코드는 방향에 상관없이 4×4 행렬에서 특정 방향의 ‘한 줄’을 뽑아내는 추상화가 핵심입니다.
- 엔지니어링 의도: 중복 코드를 제거(DRY 원칙)하고, 이동 로직의 버그를 한 곳에서만 수정하면 모든 방향에 적용되도록 설계되었습니다.
2. Slide & Merge 알고리즘: 2단계 처리
타일이 합쳐질 때는 두 가지를 고려해야 합니다. 중간에 빈칸이 없어야 하고, 같은 숫자는 한 번의 이동에서 한 번만 합쳐져야 합니다.
function slideAndMerge(line) {
let result = [];
let moved = false;
for (let i = 0; i !== line.length; i++) {
// 인접한 두 타일의 값이 같고, 아직 합쳐지지 않았다면 병합
if (i !== line.length - 1 && line[i].val === line[i + 1].val && !line[i].merged) {
let t1 = line[i];
t1.val *= 2; // 값 업데이트
result.push(t1);
i++; // 다음 타일은 건너뜀
moved = true;
} else {
result.push(line[i]);
}
}
return { newLine: result, moved: moved };
}
- 알고리즘 분석: 탐욕 알고리즘(Greedy Algorithm)적 접근을 사용합니다. 앞에서부터 순차적으로 검사하며 최선의 병합을 즉시 수행합니다.
- 엔지니어링 의도:
merged플래그를 사용하여2-2-2-2가 한 번에8이 되는 현상을 방지하고, 게임의 오리지널 규칙을 정확히 구현합니다.
3. 확률 기반의 난수 생성 (Spawn Logic)
게임의 밸런스를 결정하는 새로운 타일 생성 로직입니다.
function addRandomTile() {
var empty = [];
for (var r = 0; r !== 4; r++) {
for (var c = 0; c !== 4; c++) {
if (!g2048_board[r][c]) empty.push({r: r, c: c});
}
}
if (empty.length !== 0) {
var pos = empty[Math.floor(Math.random() * empty.length)];
// 90% 확률로 2, 10% 확률로 4 생성
var val = Math.random() < 0.9 ? 2 : 4;
// ... 타일 생성 및 DOM 추가
}
}
- 알고리즘 분석: 빈 공간(null)을 먼저 전수조사한 뒤, 그중 하나를 무작위로 선택하는 샘플링(Sampling) 기법을 사용합니다.
- 엔지니어링 의도: 단순 랜덤 좌표 생성이 아니라 ‘빈칸 중 하나’를 보장함으로써 연산 횟수를 줄이고 무한 루프를 방지합니다.
4. 워드프레스 호환성 최적화 (Environment Adaption)
이 게임의 가장 독특한 점은 배포 환경에 따른 코드 수정입니다.
// 표준 방식: for (let i = 0; i < 4; i++)
// 수정 방식: for (var r = 0; r !== 4; r++)
- 문제 해결: 워드프레스의 HTML 파서가
<기호를 태그로 인식해 코드를 파괴하는 현상을 막기 위해 모든 비교 연산자를!==(Not Equal)로 교체했습니다. - 엔지니어링 의도: 프론트엔드 개발자는 코드가 돌아가는 Runtime 환경을 이해해야 합니다. 플랫폼의 제약 사항을 우회하기 위해 표준 문법을 변형하는 것도 중요한 실무 능력입니다.
📝 마치며
2048 게임 구현은 배열(Array) 조작, 조건부 렌더링, 그리고 브라우저 이벤트 처리에 대한 프론트엔드 실무 능력을 기르기에 매우 좋은 프로젝트입니다. studyformyself에 적용된 이 코드들은 실제 배포 과정에서의 트러블슈팅 경험까지 녹아 있습니다.
전체 소스 코드와 알고리즘의 동작 과정을 직접 확인해 보고 싶으시다면 아래 링크를 참조해 주세요.
1. 다른 게임 로직도 궁금하신가요? 이전에 분석했던 스도쿠 게임의 백트래킹(Backtracking) 알고리즘과 비교해 보면 더욱 흥미롭습니다. 👉 studyformyself 스도쿠 알고리즘 보러 가기
2. 코드 리팩토링 제안 현재 코드에서 성능을 더 높이거나 가독성을 높일 수 있는 함수형 프로그래밍 방식의 도입이 궁금하시다면 의견 남겨주세요!
2 thoughts on “2048 게임 스크립트 심층 분석: 프론트엔드 알고리즘과 구현 전략”