프로젝트/레트로 테트리스

Claude Code로 테트리스 만들기 2부 - 줄 삭제와 점수 시스템 구현

ksc-dev 2026. 4. 19. 20:30

1. 배경
1부에서 충돌 감지를 구현했다. 2부는 꽉 찬 줄을 삭제하고 점수를 계산하는 로직이다.
 
2. 줄 삭제 구현

function clearLines() {
  const remainingLines = board.value.filter(row =>
    !row.every(cell => cell !== 0)
  )

  const deletingLines = BOARD_ROWS - remainingLines.length

  const emptyLines = Array.from(
    { length: deletingLines },
    () => Array(BOARD_COLS).fill(0)
  )

  board.value = [...emptyLines, ...remainingLines]
  return deletingLines
}

 
3. 배운 개념 — 참조 vs 값
처음에 Array(3).fill([0,0,0])으로 빈 줄을 만들었는데 버그가 생겼다. 배열은 값이 아니라 주소를 저장해서 fill로 복사하면 같은 배열을 가리키게 된다. 하나를 바꾸면 전부 바뀌는 문제가 생긴다.
Array.from + 콜백을 쓰면 매번 새 배열을 만들어서 독립적이다.

// 위험 — 같은 배열 공유
Array(3).fill([0,0,0])

// 안전 — 독립된 배열 생성
Array.from({ length: 3 }, () => [0,0,0])

 
4. 점수 시스템 구현

function addScore(clearedLines) {
  const earned = LINE_SCORES[clearedLines] * level.value

  score.value += earned
  lines.value += clearedLines
  level.value = Math.floor(lines.value / 10) + 1

  if (score.value > bestScore.value) {
    bestScore.value = score.value
    localStorage.setItem('tetris_best_score', score.value)
  }

  return earned
}

 
5. 배운 개념 — localStorage
localStorage는 브라우저에 데이터를 영구 저장하는 공간이다. 게임을 껐다 켜도 최고 점수가 남아있는 이유가 이것이다.
주의할 점은 localStorage에만 저장하면 Vue가 변경을 감지하지 못해서 화면이 안 바뀐다. bestScore.value도 같이 갱신해줘야 한다.
 
6. 마무리
filter + every 조합은 비슷한 케이스가 오면 이해할 수 있는 정도가 됐다. 참조 공유 문제는 코드 분석하면서 이해가 됐다.