# 01. 브라우저 테트리스 대회

## 1. 한 줄 요약

같은 지시문으로 로컬 LLM 15종이 각자 브라우저용 테트리스를 만들고, 자동 실행 시험과 블라인드 코드 리뷰로 1000점 만점 채점한 대회입니다.

- 참가 모델 15종의 제원은 [00_model_info](../00_model_info/README.md) 에 있습니다.
- 모든 모델은 같은 서버에서, 같은 에이전트 도구로, 같은 지시문을 받고, 한 번에 하나씩 순서대로 일합니다.

## 2. 라운드 개념 (v1 / v2 / v3)

대회는 「라운드」로 이어집니다. 같은 모델이 같은 게임을 라운드마다 한 단계씩 발전시킵니다.

| 라운드 | 과제 | 시작 상태 |
|---|---|---|
| **v1** | 테트리스를 **처음부터 새로 만들기** — 아타리(Atari Games) 1988년 아케이드판의 게임성과 그래픽 재현, `index.html` 하나로 실행, `README.md` 포함 | 빈 폴더 |
| **v2** | 만들어 둔 게임에 **모바일 터치 조작 추가** | **자기 v1 결과물을 복사한 폴더** |
| **v3** | 만들어 둔 게임에 아케이드식 **레벨·크레딧·컨티뉴 도입** — 지운 줄 수로 레벨이 오르고, 코인을 넣어 크레딧을 쌓아야 시작하고, 게임 오버 뒤 카운트다운 컨티뉴 | **자기 v2 결과물을 복사한 폴더** |

v2·v3 의 규칙은 다음과 같습니다.

- 각 모델은 **자기 직전 라운드 결과물만**(v2 는 v1, v3 는 v2) 이어받습니다. 다른 모델의 결과물은 보지 못합니다.
- **공평성을 위해 이전 라운드 채점에서 나온 결함·피드백은 모델에게 알려 주지 않습니다.** 모델은 이전 라운드에서 무엇이 틀렸는지 모른 채 지시문만 받습니다.
- 모델마다 매번 **새 세션**을 시작하므로, 모델이 아는 것은 지시문과 **폴더 안의 코드뿐**입니다(이전 대화 기억 없음).

폴더 이름 규칙은 `simple_llm_test_{모델약어}_{테스트}_{버전}` 입니다.

```
simple_llm_test_q36_tetris_v1    # q36 모델의 v1 결과물
simple_llm_test_q36_tetris_v2    # 위 폴더를 복사해서 터치 조작을 추가한 v2 결과물
simple_llm_test_q36_tetris_v3    # v2 폴더를 복사해서 레벨·크레딧·컨티뉴를 도입한 v3 결과물
```

v3 도 같은 방식으로, 직전 라운드 결과물을 복사한 폴더에서 이어 갑니다.

## 3. 지시문 원문

모델마다 지시문은 폴더 이름(`{alias}` 자리에 모델 약어)만 다르고 나머지는 글자 하나까지 같습니다.

### v1

```text
현재 작업 폴더 이름은 simple_llm_test_{alias}_tetris_v1 입니다. 이 폴더 안에 웹 브라우저에서 바로 실행되는 HTML 기반 테트리스 게임을 만들어 주세요.

요구사항:
- 아타리(Atari Games, 1988년 아케이드판) 테트리스의 게임성과 그래픽을 최대한 가깝게 재현해 주세요.
- 별도 설치·빌드·서버 없이 index.html 파일을 브라우저로 열면 바로 실행되어야 합니다.
- 필요한 파일은 모두 이 폴더 안에 만들어 주세요.
- 게임 소개, 실행 방법, 조작법, 파일 구성을 정리한 README.md 도 이 폴더에 만들어 주세요.

완성되면 만든 파일 목록과 조작 방법을 짧게 정리해 주세요.
```

### v2

```text
현재 작업 폴더 이름은 simple_llm_test_{alias}_tetris_v2 입니다. 이 폴더에는 앞서 만든 HTML 테트리스 게임이 있습니다. 모바일 기기에서도 플레이할 수 있도록 터치 조작 기능을 추가해 주세요.
요구사항:
- 기존 기능은 그대로 유지해 주세요.
- 휴대폰 화면에서도 보기 좋게 맞춰 주세요.
- 별도 설치·빌드·서버 없이 index.html 파일을 브라우저로 열면 바로 실행되어야 합니다.
- README.md 에 터치 조작 방법을 추가해 주세요.
완성되면 바꾼 파일 목록과 터치 조작 방법을 짧게 정리해 주세요.
```

### v3

```text
현재 작업 폴더 이름은 simple_llm_test_{alias}_tetris_v3 입니다. 이 폴더에는 앞서 만든 HTML 테트리스 게임(터치 조작 포함)이 있습니다. 아케이드 게임처럼 레벨과 크레딧/컨티뉴 개념을 도입해 주세요.

요구사항:
- 레벨: 지운 줄 수에 따라 레벨이 오르고, 레벨이 오를수록 낙하 속도가 빨라지며, 화면에 현재 레벨이 표시되어야 합니다.
- 크레딧: 코인을 넣어 크레딧을 쌓고(키보드와 터치 모두 가능), 크레딧이 있어야 게임을 시작할 수 있게 해 주세요. 남은 크레딧을 화면에 표시해 주세요.
- 컨티뉴: 게임 오버가 되면 카운트다운과 함께 컨티뉴 화면을 보여 주고, 그 사이 크레딧을 써서 이어서 할 수 있게 해 주세요(점수·레벨 유지). 시간 안에 이어 하지 않으면 타이틀 화면으로 돌아갑니다.
- 게임 흐름: 타이틀(대기) 화면 → 시작 → 플레이 → 게임 오버 → 컨티뉴 → 타이틀 로 끊김 없이 이어지게 해 주세요.
- 기존 기능(키보드·터치 조작)은 그대로 유지하고, 별도 설치·빌드·서버 없이 index.html 을 브라우저로 열면 바로 실행되어야 합니다.
- README.md 에 레벨 규칙, 크레딧·컨티뉴 방법, 조작법을 추가해 주세요.

완성되면 바꾼 파일 목록과 크레딧·컨티뉴 조작 방법을 짧게 정리해 주세요.
```

## 4. 실행 환경

**서버**

- AMD Strix Halo 노트북 서버: CPU Ryzen AI MAX+ 392(12코어), 내장 GPU Radeon 8060S, 64GB 통합 메모리.
- 이 중 GPU 가 쓸 수 있는 공유 메모리(GTT)는 56GiB 입니다. 모델은 이 영역에 올라갑니다.
- 모델 추론: llama.cpp **b11701** (Vulkan), router 모드. 모델은 **한 번에 하나만** 올라가고, 요청의 모델 이름(약어)에 따라 교체됩니다.
- 모델마다 서버에 등록된 자기 프리셋(생각 모드, 샘플링 등)을 그대로 씁니다. 대회용으로 따로 바꾸지 않았고, 각 값은 [모델 정보](../00_model_info/README.md) 에 있습니다.
- 모델 컨텍스트 길이는 대부분 65,536 토큰(Qwen2.5 계열 3종은 32,768), 1회 출력 상한은 16,384 토큰입니다.

**예외: `mel` (Mellum 2.1)**

`mel` 만 llama.cpp **b11539** 로 돌렸습니다. b11701 에는 PR #30584 가 들어 있어 Mellum 의 `ffn_moe_down` 연산을 F32 정밀도로 강제하는데, Vulkan 이 이 연산을 GPU 에서 지원하지 않아 CPU 로 넘어가고 생성 속도가 4.7배 느려집니다(81.7 에서 17.5 t/s). 이 서버의 GPU 에서는 b11539 에서도 NaN 이 없었고 퍼플렉서티도 같아(6.097 대 6.105) 정확도 이득 없이 속도만 잃기 때문에, `mel` 차례에만 엔진을 바꾸고 끝나면 b11701 로 되돌렸습니다.

**에이전트**

- opencode v1.18.35 를 `opencode run --auto --pure -m halo/<약어>` 로 실행합니다(`--auto` 는 파일 편집·명령 실행을 사람 확인 없이 허용, `--pure` 는 외부 플러그인 없이 실행).
- 권한: 파일 편집 허용, 셸 명령 허용, 웹 가져오기(webfetch) **거부**. 셸 네트워크는 막지 않았습니다(5절 감사 결과 참고).
- 모델마다 새 세션, 새 임시 홈 디렉터리에서 시작합니다.

## 5. 공정성 장치

| 장치 | 내용 |
|---|---|
| 샌드박스(bubblewrap) | 디스크 전체를 읽기 전용으로 두고, 홈과 데이터 디스크는 빈 영역으로 가려서 **다른 모델의 폴더·결과물이 보이지 않습니다**. 쓸 수 있는 곳은 **자기 프로젝트 폴더**와 일회용 임시 홈뿐입니다. 부모 프로세스가 끝나면 함께 종료됩니다. |
| 웹 가져오기 도구 거부 | 웹 가져오기(webfetch) 도구는 거부했습니다. 셸 네트워크는 막지 않았습니다 — 아래 「네트워크 사용 감사」 참고. |
| 시간 제한 | 모델당 최대 **60분**. 넘으면 강제 종료하고 그 시점의 결과물로 채점합니다. |
| 냉각 시간 | 모델 사이에 **1분** 쉽니다. 과열을 막고 직전 모델의 부하가 다음 모델에 영향을 주지 않게 하기 위해서입니다. |
| 같은 지시문 | 폴더 이름 외에는 동일한 지시문. |
| 같은 순서 | 모든 라운드에서 아래 순서를 그대로 유지합니다. |
| 폴더 사전 생성 | 모델이 일을 시작하기 전에 빈 폴더(v2 는 v1 복사본, v3 는 v2 복사본)를 미리 만들어 둡니다. 폴더가 이미 있으면 덮어쓰지 않고 중단합니다. |

**네트워크 사용 감사 (2026-10-17 최종 집계)**: 셸 네트워크를 막지 않았으므로 실행 기록을 조사했습니다. 테트리스 v1~v3 실행 로그 45개(모델 15종 × 3라운드)에서 curl·wget, 외부 URL 요청, 패키지 설치, 외부 fetch, webfetch 시도를 찾았습니다. 근거는 로그에 남은 bash 호출 137회(v1 51회, v2 26회, v3 60회)이고, v3 5종은 서브에이전트까지 포함한 도구 호출 전체 기록 59회도 검사했습니다(나머지 실행은 도구 호출 기록이 남아 있지 않아 로그에 보이는 호출만 검사했습니다). 결과는 셸 접속, webfetch, 패키지 설치, 외부 URL 요청이 **모두 0건 / 결과물 반영 0건**입니다. 정규식에 걸린 3건(`npx --no-install` 로컬 조회 2건, Chrome 콘솔 경고 속 설명 주소 1건)은 접속이 아님을 확인했습니다. 게임 파일 안의 외부 URL(CDN·폰트 링크 등)과 내려받은 라이브러리 흔적도 0건입니다. 서브에이전트 사용이 로그에서 관찰된 실행은 v1 `q36` 입니다. 로그에 남지 않는 호출은 확인할 수 없는 범위입니다.

**진행 순서**: q36, cn, orn, mg, bolt, lfm, mcv, q38, aw, fn, ff, c7, c7r, c1, mel (mel 은 엔진을 바꿔야 해서 맨 마지막).

## 6. 진행 순서 (파이프라인)

모델 한 개당 다음 단계를 거치고, 15종 모두 같은 절차를 반복합니다.

```
 [폴더 준비]  v1: 빈 폴더 생성 / v2: 자기 v1 폴더를 복사 / v3: 자기 v2 폴더를 복사
      |
      v
 [샌드박스 에이전트 실행]  opencode + 지시문 (최대 60분)
      |
      v
 [서버 로그 집계]  소요 시간, 요청 수, 입력/생성 토큰, 생성 속도,
      |            최대 컨텍스트 길이, 컨텍스트 잘림 여부
      v
 [데스크톱 브라우저 시험]  헤드리스 Chrome (v1, v2, v3 공통)
      |
      v
 [모바일 시험]  390x844 터치 에뮬레이션 (v2, v3)
      |
      v
 [흐름 시험]  코인·크레딧·컨티뉴 아케이드 흐름 (v3 만)
      |
      v
 [냉각 1분]  --> 다음 모델
```

**서버 로그 집계**: 에이전트가 끝나면 그 시간 동안의 서버 로그에서 해당 모델 몫만 뽑아 요청 수, 읽은 토큰(프롬프트), 생성한 토큰, 생성 속도(t/s), 최대 컨텍스트 길이, 컨텍스트 초과로 잘린 횟수를 계산하고 결과 폴더의 파일 목록과 크기도 기록합니다.

**데스크톱 브라우저 시험 (헤드리스 Chrome, `file://` 로 index.html 을 직접 열기)**

1. 페이지 로드, 콘솔 오류·예외 수집.
2. 시작 시도: 화면 가운데 클릭, Enter, Space 입력.
3. 2초 동안 가만히 두고 화면이 저절로 변하는지(블록이 떨어지는지) 확인.
4. 이동·회전·내리기 키 입력(좌, 우, 위, 아래).
5. 스페이스(하드 드롭).
6. 일시정지(P) 후 화면이 멈추는지 확인, 다시 P 로 재개.
7. 약 25초 동안 키를 번갈아 눌러 연속 플레이(줄 삭제·게임 오버까지 가는지).
8. 각 단계마다 스크린샷을 저장하고, 화면 해시 비교로 반응 여부를 판단.

**모바일 시험 (v2, v3, 화면 390x844 · 터치 에뮬레이션)**

1. 휴대폰 크기로 로드하고 **화면 맞춤**(가로 스크롤 없음, 게임판이 화면에 들어오는지) 확인.
2. **소스 코드에서 터치 관련 코드**(touchstart 등) 검색.
3. 화면 위 **버튼 후보를 찾아** 하나씩 탭하고 화면이 바뀌는지 확인.
4. 화면 중앙 탭으로 시작, 별도의 시작 버튼이 있으면 탭.
5. **스와이프**(좌우, 아래 등)와 **탭** 제스처 시험.
6. **일시정지** 버튼을 따로 시험.
7. 약 20초 동안 터치를 섞어서 연속 플레이.

**흐름 시험 (v3 부터 추가)**: 타이틀의 코인 투입(키보드·터치)과 크레딧 표시, 크레딧 0 일 때 시작 불가, 레벨 표시, 게임 오버 뒤 컨티뉴 카운트다운과 이어 하기, 시간 초과 뒤 타이틀 복귀를 차례로 시험합니다. 코인 키를 소스에서 추정하는 휴리스틱이라 틀릴 수 있어, 심사 때 직접 다시 확인합니다.

## 7. 채점

### 1000점 루브릭

| 영역 | 배점 | 세부 |
|---|---:|---|
| 1. 기능 구현 | 400 | |
| ㄴ 1-1 실행·안정성 | 100 | `file://` 로 바로 뜸 30, 콘솔 오류 0 20, 시작 입력 반응·낙하 20, 키 입력 반응 15, 일시정지 10, 25초 연속 플레이 5 (자동 시험 결과 근거) |
| ㄴ 1-2 테트리스 핵심 규칙 | 150 | 7종 블록·10x20 판 20, 이동·회전 충돌 30, 줄 삭제 30, 중력·레벨 속도 20, 점수 20, 다음 블록 15, 게임 오버·재시작 15 |
| ㄴ 1-3 아타리 1988 재현 | 150 | 화면 구성 40, 조작감 30, 진행(레벨·속도 곡선) 30, 연출(테마·색감·음향) 30, 기타 원작 요소 20 |
| 2. 코드 간결성·가독성 | 200 | 중복 없음 60, 이름·상수 40, 죽은 코드 없음 30, 상태 관리 40, 주석 30 |
| 3. 컴포넌트·모듈 분리 | 150 | 관심사 분리 70, 응집·결합 50, 확장 용이성 30 |
| 4. 패키지·의존성 | 100 | 외부 라이브러리·CDN 없이 오프라인 50, 불필요한 의존 없음 25, 표준 API 25 |
| 5. 파일·경로 배분 | 100 | 폴더 구조 40, 파일 이름 20, 상대 경로 25, 폴더 밖에 파일 없음 15 |
| 6. 문서 README | 50 | 소개·실행·조작·파일 구성이 코드와 일치 |
| **합계** | **1000** | |

### v3 루브릭 (1000점)

v1 은 위 표, v2 는 9-2절 첫머리에 있습니다. v3(레벨·크레딧·컨티뉴 도입)는 영역 구성이 다음과 같이 바뀝니다.

| 영역 | 배점 | 세부 |
|---|---:|---|
| 1. 레벨 | 150 | 지운 줄 수로 레벨이 오름 50, 레벨이 오를수록 낙하가 빨라짐 50, 현재 레벨이 화면에 표시되고 갱신됨 30, 컨티뉴는 레벨 유지·새 게임은 초기화 20 |
| 2. 크레딧 | 200 | 키보드 코인 투입으로 크레딧 +1 50, 터치(390x844 에뮬레이션) 코인 투입으로 크레딧 +1 50, 크레딧 0 이면 시작 불가이고 시작하면 1 줄어듦 60, 남은 크레딧이 화면에 정확히 표시됨 40 |
| 3. 컨티뉴 | 200 | 게임 오버 뒤 컨티뉴 화면과 카운트다운 50, 크레딧으로 이어 하기에서 점수·레벨 유지 80, 크레딧이 없거나 시간이 지나면 타이틀로 복귀 50, 카운트다운 중 코인을 넣어 이어 하기 20 |
| 4. 게임 흐름 | 100 | 타이틀, 시작, 플레이, 게임 오버, 컨티뉴, 타이틀을 두 바퀴 돌아도 굳거나 꼬이지 않음 60, 일시정지·컨티뉴·타이틀 사이에서 입력이 엉뚱한 상태로 새지 않음 40 |
| 5. 기존 기능 유지 | 200 | 키보드 플레이 100(중력 20, 바닥 착지 16, 좌우 벽 10, 회전 8, 내리기 16, 줄 삭제 20, 일시정지 6, 페이지 스크롤 방지 4), 터치 플레이 60(이동 20, 회전 15, 내리기 15, 일시정지 10), 화면 40(데스크톱 20, 모바일 한 화면 20) |
| 6. 변경의 품질 | 100 | v2 에서 v3 로의 diff 가 깔끔함 40, 게임 상태가 명시적 상태(타이틀·플레이·일시정지·게임 오버·컨티뉴)로 관리됨 40, 죽은 코드·디버그 코드 없음 20 |
| 7. README 갱신 | 50 | 레벨 규칙, 코인 넣는 법(키보드·터치), 컨티뉴 방법, 조작법이 실제 코드와 일치 |
| **합계** | **1000** | |

**심사 분담**: 1~5 는 QA 리뷰어가 브라우저에서 직접 확인하고(엔트리마다 상태를 주입한 방법과 결과를 표로 남김), 6·7 은 코드 리뷰어가 맡습니다. 실측하지 못한 항목은 코드 근거로 보충하되 아래 70% 상한을 적용합니다. 진행자(PM)가 두 결과를 합치고, 실측과 코드 판정이 엇갈린 항목은 재확인합니다.

### 판정 원칙 (v2 재검증의 교훈)

v2 에서 `q38` 이 버튼 입력에 좌표와 점수가 바뀌는 것만 보고 기존 기능 유지에 만점을 줬다가, 재검증에서 충돌 결함이 드러나 감점한 일이 있었습니다(9-2절 「QA 재검증 기록」). 그래서 v3 는 다음 원칙으로 채점합니다.

- **「반응한다」는 「동작한다」가 아닙니다.** 화면이 바뀌었다는 것만으로 점수를 주지 않고, 버튼이 눌린 **결과**(크레딧이 1 늘었나, 게임이 시작됐나, 점수가 유지됐나)를 확인합니다.
- **실측 우선, 상태 주입 허용.** 브라우저에서 직접 확인하고, 줄 삭제·레벨업·게임 오버처럼 도달하기 어려운 상태는 콘솔로 상태를 주입해도 됩니다(예: 바닥 행을 채워 두고 떨어뜨리기, 줄 수를 9 로 놓고 한 줄 지우기). 대신 **주입한 방법을 근거에 적습니다**.
- **코드로만 확인한 항목은 그 항목 배점의 70% 가 상한**입니다. 실제로 확인했다면 만점까지 줄 수 있습니다.

### 채점 방법

- **블라인드 리뷰**: 결과물에 익명 이름(A~O)을 붙여 채점하고, 채점이 끝난 뒤 모델 이름을 공개합니다. 리뷰어는 어느 모델이 만든 것인지 모른 채 채점합니다.
- **영역별 담당이 다릅니다.**
- **1-1 실행·안정성, 1-2 핵심 규칙**: QA 리뷰어 한 명이 헤드리스 브라우저로 직접 실행해 검증한 결과로 채점합니다(코드 리뷰어의 1-2 점수는 코드 판독만으로 낸 교차 확인용 추정치라 총점에 넣지 않습니다).
- **2~6 (코드 간결성, 모듈 분리, 의존성, 파일 배분, README)**: QA 리뷰어와 코드 리뷰어가 각자 매긴 점수의 **평균**입니다.
- **1-3 아타리 재현**: 진행자(PM)가 실행 스크린샷을 보고 채점합니다.
- **아타리 재현 부분**은 원작 세부 규칙을 확신하지 못하면 감점 근거로 쓰지 않고, 「원작에 맞추려는 의도와 일관성」을 봅니다.
- **모든 감점·가점에는 근거**(파일:줄 번호 또는 시험 결과)를 적어야 합니다. 근거 없는 감점은 금지입니다.
- 아무것도 만들지 못했거나 실행이 안 되면 1-1 은 0점이고, 나머지는 있는 코드만큼만 채점합니다.
- **채점 정정(투명성 기록)**: 1-3 을 처음 채점할 때 진행자가 `cn`·`q38` 도 다른 모델처럼 하드드롭을 쓴 것으로 잘못 보았습니다. 두 모델은 하드드롭 없이 아래 키로 빨리 내리기만 쓰는데, 이를 원작의 조작 방식에 맞다고 보고 1-3 조작감을 올려 `cn` 55점에서 65점, `q38` 63점에서 73점으로 정정했습니다. 두 모델의 총점은 각각 10점 올랐고(`cn` 729.5, `q38` 742.5) 순위는 바뀌지 않았습니다.

### 실용 순위

1000점 순위와 별도로, **600점 이상**인 결과물만 모아 **만드는 데 걸린 시간 순**으로 나열한 「실용 순위」를 함께 냅니다.

속도는 1000점에 넣지 않았습니다. 같은 서버라도 모델 크기·엔진 설정에 따라 속도가 크게 갈려서, 속도를 점수에 섞으면 품질 비교가 흐려지기 때문입니다. 대신 쓸 만한 품질(600점 이상)을 갖춘 모델 사이에서 얼마나 빨리 끝냈는지를 별도 순위로 보여 줍니다.

## 8. 진행 기록과 한계

- **재시작**: 첫 시도 중 09:40 경 서버가 완전히 멈추는 현상(하드 프리즈)이 있었습니다. 그 시도의 결과를 모두 지우고 11:34 에 처음부터 다시 시작했습니다. 재시작부터는 15초마다 CPU·GPU·SSD 온도, GPU 전력, 공유 메모리 사용량, 전원 상태를 기록하는 로그(멈춰도 마지막 줄이 남도록 즉시 디스크에 반영)를 돌리고, 모델 사이에 1분 냉각을 넣었습니다.
- **표본 수**: 모델당 라운드당 **1회**만 실행했습니다. 같은 모델을 다시 돌리면 결과가 달라질 수 있으므로 점수 차이가 작은 구간은 순위보다 경향으로 읽어야 합니다.
- **자동 시험의 한계**: 반응 여부는 스크린샷 해시가 달라졌는지로 보는 **간접 신호**입니다. 낙하 애니메이션 때문에 화면이 바뀌어도 입력에 반응한 것처럼 보일 수 있습니다. 그래서 최종 판단은 코드와 스크린샷을 직접 보고 합니다.
- 헤드리스 시험은 사람이 직접 하는 플레이를 대신하지 못합니다. 실제 조작감·효과음·휴대폰 실기 동작은 점수에 반영되지 않은 부분이 있습니다.

## 9. 결과 — v1

**채점 방식**: 1-1·1-2 는 QA 리뷰어가 헤드리스 브라우저로 직접 실행해 검증하고, 2~6 은 QA 리뷰어와 코드 리뷰어의 평균, 1-3 아타리 재현은 진행자(PM)가 실행 스크린샷을 보고 채점했습니다. 채점 중에는 결과물을 A~O 로 익명 처리(블라인드)했고, 채점이 끝난 뒤 모델 이름을 공개했습니다. 1-3 은 채점 후 `cn`·`q38` 두 모델만 +10점씩 정정했습니다(7절 「채점 방법」 참고).

### 품질 순위 (1000점)

열 머리의 `1-1/100` 은 「항목/만점」이고, 소수점 `.5` 는 두 리뷰어 점수의 평균입니다. 「플레이 링크」는 결과물 폴더로 연결됩니다.

| 순위 | 모델 | 총점 | 1-1/100 | 1-2/150 | 1-3/150 | 2/200 | 3/150 | 4/100 | 5/100 | 6/50 | 실제로 플레이 가능? | 플레이 링크 |
|---:|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---|---|
| 1 | [`mcv`](../00_model_info/mcv.md) | **786.5** | 95 | 146 | 62 | 147 | 98 | 100 | 99.5 | 39 | 가능 (일시정지를 걸면 풀 수 없음) | [열기](./simple_llm_test_mcv_tetris_v1/) |
| 2 | [`ff`](../00_model_info/ff.md) | **757.5** | 100 | 111 | 66 | 144 | 101 | 100 | 92.5 | 43 | 가능 (12×24 판, 2줄 이상 동시 삭제 시 보드가 깨짐) | [열기](./simple_llm_test_ff_tetris_v1/) |
| 3 | [`aw`](../00_model_info/aw.md) | **756.5** | 88 | 133 | 58 | 150 | 92.5 | 98 | 92 | 45 | 불가 — 자동 낙하 없음 (↓ 키를 눌러야만 내려옴) | [열기](./simple_llm_test_aw_tetris_v1/) |
| 4 | [`q38`](../00_model_info/q38.md) | **742.5** | 85 | 84 | 73 | 149 | 114.5 | 100 | 93 | 44 | 불가 — 조각이 판 중간 허공에 고정되고 오른쪽 벽에 닿지 못함 | [열기](./simple_llm_test_q38_tetris_v1/) |
| 5 | [`cn`](../00_model_info/cn.md) | **729.5** | 88 | 141 | 65 | 130.5 | 84.5 | 98 | 91.5 | 31 | 가능 (바닥 3행이 화면에서 잘림) | [열기](./simple_llm_test_cn_tetris_v1/) |
| 6 | [`orn`](../00_model_info/orn.md) | **661.5** | 49 | 75 | 49 | 147.5 | 107 | 100 | 93 | 41 | 불가 — 화면이 그려지지 않음 (빈 격자) | [열기](./simple_llm_test_orn_tetris_v1/) |
| 7 | [`q36`](../00_model_info/q36.md) | **657** | 88 | 87 | 46 | 110 | 99 | 96 | 92 | 39 | 불가 — 자동 낙하 없음 (첫 홀드가 곧 게임오버) | [열기](./simple_llm_test_q36_tetris_v1/) |
| 8 | [`mg`](../00_model_info/mg.md) | **571.5** | 68 | 99 | 35 | 105 | 52 | 96 | 85.5 | 31 | 부분 — 낙하·이동은 되나 Space 하드드롭 예외, I·S 조각·다음 블록·게임오버 없음 | [열기](./simple_llm_test_mg_tetris_v1/) |
| 9 | [`mel`](../00_model_info/mel.md) | **498** | 32 | 30 | 26 | 110 | 78 | 100 | 98 | 24 | 불가 — 화면이 그려지지 않음 | [열기](./simple_llm_test_mel_tetris_v1/) |
| 10 | [`bolt`](../00_model_info/bolt.md) | **462** | 15 | 25 | 44 | 93.5 | 69 | 98 | 91.5 | 26 | 불가 — 시작 즉시 예외, 빈 화면 | [열기](./simple_llm_test_bolt_tetris_v1/) |
| 11 | [`lfm`](../00_model_info/lfm.md) | **445** | 29 | 20 | 27 | 98 | 60 | 100 | 91 | 20 | 불가 — 조각이 보이지 않고 Space 에서 브라우저가 멈춤 | [열기](./simple_llm_test_lfm_tetris_v1/) |
| 12 (공동) | [`c7r`](../00_model_info/c7r.md) | **0** | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 파일 없음 | 제작 실패 |
| 12 (공동) | [`c7`](../00_model_info/c7.md) | **0** | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 파일 없음 | 제작 실패 |
| 12 (공동) | [`c1`](../00_model_info/c1.md) | **0** | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 파일 없음 | 제작 실패 |
| 12 (공동) | [`fn`](../00_model_info/fn.md) | **0** | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 파일 없음 | 제작 실패 |

### 실용 순위 (600점 이상, 소요 시간순)

1000점 순위와 별도로, 총점이 600점 이상인 7종만 **소요 시간이 짧은 순서**로 나열했습니다.

| 순위 | 모델 | 총점 | 제작 시간 | 요청 수 | 생성 토큰 |
|---:|---|---:|---:|---:|---:|
| 1 | [`mcv`](../00_model_info/mcv.md) | 786.5 | 2:09 | 8 | 5,262 |
| 2 | [`cn`](../00_model_info/cn.md) | 729.5 | 2:10 | 5 | 4,416 |
| 3 | [`orn`](../00_model_info/orn.md) | 661.5 | 2:50 | 12 | 9,248 |
| 4 | [`q36`](../00_model_info/q36.md) | 657 | 4:59 | 12 | 19,218 |
| 5 | [`aw`](../00_model_info/aw.md) | 756.5 | 8:52 | 5 | 25,095 |
| 6 | [`ff`](../00_model_info/ff.md) | 757.5 | 10:08 | 13 | 11,092 |
| 7 | [`q38`](../00_model_info/q38.md) | 742.5 | 26:53 | 48 | 29,483 |

- `mcv` 와 `cn` 은 2분대로 사실상 동시에 끝났고, `q38` 은 가장 오래(26분 53초) 걸렸습니다.
- 이 표의 7종 중 실제로 플레이되는 것은 `mcv`·`cn`·`ff` 3종뿐입니다(위 「실제로 플레이 가능?」 열 참고).

### 눈에 띈 점

- **`mcv` 가 1위(786.5점)이자 가장 완결된 구현입니다.** 7종 블록·충돌·회전·줄 삭제·점수·레벨·다음 블록·게임오버·재시작이 모든 시험을 통과했고, 2분 9초(요청 8회)에 끝냈습니다. 이미지·영상 이해에 특화된 비전 모델이 코딩 전용 `cn` 보다 앞선 점이 눈에 띕니다. 다만 일시정지(P)를 한 번 걸면 풀 수 없고(일시정지 중에는 P 입력을 무시하는 가드가 앞에 있음) O 와 Z 블록이 같은 색입니다.
- **`aw` 는 규칙이 가장 정확한데 블록이 저절로 내려오지 않습니다.** 충돌·회전·줄 삭제·점수는 시험의 정답과 모두 일치해 1-2 에서 깎인 것은 중력 항목뿐입니다. 그러나 낙하 타이머를 `Date.now()` 로 잡고 `requestAnimationFrame` 이 주는 타임스탬프(페이지 로드 기준 시간)와 빼서 값이 영원히 음수가 되고, 5.2초 동안 낙하가 0회였습니다. 이 한 줄만 고치면 최상위권입니다.
- **`q38` 은 코드 구조가 리뷰 1위인데 실행하면 조각이 허공에서 멈춥니다.** 코드 리뷰어의 2~6 합계가 528/600 으로 11개 중 1위(갱신/그리기 분리, 상태기계)였지만, 충돌 검사가 이미 위치가 들어 있는 칸 좌표에 위치를 한 번 더 더하는 이중 오프셋 때문에 조각이 판 중간에서 굳고 오른쪽 벽에 닿지 못합니다. 코드만 읽은 리뷰는 정상 동작을 예상했고, 실행 시험이 결함을 잡았습니다. 소요 시간도 26분 53초(요청 48회)로 가장 길었습니다.
- **첫 실행에서 바로 드러났을 치명적 결함이 흔합니다.** `orn`(SRS·7-bag·홀드까지 로직은 정교하나 초기 렌더 예외로 루프가 시작되지 않아 빈 격자), `mel`(루프가 시작되지 않는 빈 화면과 충돌 검사 구조 오류), `bolt`(`start()` 가 아직 없는 값을 읽어 로드 즉시 예외), `lfm`(위치를 두 벌로 들고 있어 조각이 보이지 않고 Space 하드드롭은 끝나지 않는 반복문), `q36`(기능 목록은 가장 길지만 중력 분기에 낙하 한 줄이 빠져 자동 낙하가 없고, 처음 홀드를 누르면 곧바로 게임오버).
- **실제로 플레이되는 것은 `mcv`·`ff`·`cn` 3종이고, 이들도 흠이 있습니다.** `ff` 는 실행 시험을 전부 통과해 1-1 만점(100점)이었지만, 판이 10×20 이 아닌 12×24 이고 J·L·Z 회전표가 틀렸으며 2줄 이상 동시에 지우면 엉뚱한 줄이 지워집니다. `cn` 은 2분 10초에 안정적으로 완성했으나 캔버스 높이(400px)가 판(480px)보다 짧아 바닥 3행이 화면에 보이지 않습니다.
- **빈 폴더가 4개입니다.** 문맥 32K 의 Qwen2.5 계열 3종(`c7`·`c7r`·`c1`)과 전문가 절반을 제거한 초압축판 `fn` 은 파일을 하나도 만들지 못했습니다. 서버 로그상 생성 토큰이 각각 1,007·110·283·61개에 그쳐 거의 아무것도 쓰지 않고 10~91초 만에 끝났습니다(원인은 분석하지 않았습니다).
- **원작 고유 요소는 아무도 구현하지 않았습니다.** 효과음, 러시아풍 테마, 시작 레벨 선택, 최고 점수 이름 입력은 파일이 있는 11종 어디에도 없습니다(코드 검색 결과 0건). 그래서 1-3 점수(26~73/150)는 정보 패널 구성, 「ATARI」 표기, 조작 방식 정도에서 갈렸습니다. 최고점은 큰 정보 패널과 목숨(하트) 요소를 넣은 `q38`(73점)이고, 아케이드 캐비닛풍 액자와 「ATARI GAMES © 1988」 표기를 넣은 `ff`(66점)가 그다음입니다.
- **하드드롭은 11종 중 9종이 Space 키의 현대식 하드드롭을 넣었습니다**(`mcv`·`ff`·`aw`·`orn`·`q36`·`mg`·`mel`·`bolt`·`lfm`). 없는 쪽은 `cn` 과 `q38` 로, 아래 키로 빨리 내리기만 쓰는 방식입니다. 진행자가 이를 원작의 조작 방식으로 보고 1-3 조작감을 올려 주었습니다(처음 채점에서는 놓쳤다가 정정, 7절 참고). `q38` 은 여기에 목숨(하트) 3개와 (레벨+1) 점수 배율까지 넣어 아케이드식 규칙을 시도했습니다.

### 해석 주의

- **표본은 모델당 1회(n=1)입니다.** 같은 모델을 다시 돌리면 결과가 달라질 수 있습니다. 점수 차이가 작은 구간(예: `ff` 757.5 와 `aw` 756.5 는 1점 차)은 순위보다 경향으로 읽어 주세요.
- **루브릭의 600점이 코드 품질 몫입니다.** 코드 간결성·모듈 분리·의존성·파일 배분·문서(2~6)가 600점이고, 실행·핵심 규칙·원작 재현(1-1~1-3)은 400점입니다. 그래서 **실제로는 플레이되지 않는 게임도 445~756.5점**을 받았습니다(`lfm` 445점, `aw` 756.5점). 총점만 보고 「잘 돌아가는 게임」으로 읽지 말고 **「실제로 플레이 가능?」 열을 총점과 함께** 봐 주세요.
- **일부 항목은 주관이 섞여 있습니다.** 2·3·5·6 은 리뷰어가 코드와 README 를 직접 읽고 준 점수이고(근거는 줄 번호로 기록), 1-3 은 진행자 1인이 스크린샷으로 채점했습니다. 헤드리스 시험이라 조작감·효과음처럼 사람이 직접 해 봐야 아는 부분은 점수에 반영되지 않았습니다.

## 9-2. 결과 — v2

**채점 방식**: v2(모바일 터치 조작 추가)는 루브릭이 v1 과 다릅니다. 1 터치 조작 300 · 2 모바일 화면 맞춤 150 · 3 기존 기능 유지 250 · 4 변경의 품질 200 · 5 README 갱신 50 · 6 의존성·파일 50, 합계 1000점입니다. 1·2·3 은 QA 리뷰어가 헤드리스 Chrome 의 **모바일 에뮬레이션(390×844, 터치 입력)** 으로 직접 눌러 보고, 데스크톱에서 v1 ↔ v2 를 같은 키 입력으로 비교해 채점했습니다. 4·5·6 은 코드 리뷰어가 **v1 → v2 변경분(diff)** 을 읽고 채점했습니다. 각 항목은 담당 리뷰어 1인의 점수이며 v1 처럼 두 리뷰어의 평균을 내지 않았습니다. 이번 라운드에는 진행자(PM)가 채점하는 항목이 없습니다. 채점 중에는 결과물을 **새로 섞은 A~O** 로 익명 처리(블라인드)했고, 채점이 끝난 뒤 모델 이름을 공개했습니다. 모델에게는 v1 채점의 결함·피드백을 알려 주지 않았습니다(2절 참고).

### 품질 순위 (1000점)

열 머리의 `1/300` 은 「영역/만점」입니다. 1 터치 조작(이동 80·회전 60·내리기 60·시작/일시정지/재개 50·직관성 50), 2 모바일 화면 맞춤(viewport 메타·가로 스크롤 없음 50·한 화면 배치 60·버튼 크기와 위치 40), 3 기존 기능 유지(v1 회귀 없음 150·v1 대비 개선 50·데스크톱 화면 50), 4 변경의 품질(diff 깔끔함 80·키보드와 터치의 공통 액션 70·죽은 코드 없음 50), 5 README 가 코드와 일치, 6 CDN 없이 `file://` 실행. 「v1 → v2」 열은 서로 다른 루브릭의 총점이라 단순 뺄셈으로 읽으면 안 됩니다(「해석 주의」 참고).

| 순위 | 모델 | 총점/1000 | 1/300 | 2/150 | 3/250 | 4/200 | 5/50 | 6/50 | 터치로 플레이 가능? | v1 → v2 총점 | 플레이 링크 |
|---:|---|---:|---:|---:|---:|---:|---:|---:|---|---|---|
| 1 | [`ff`](../00_model_info/ff.md) | **924** | 286 | 144 | 225 | 173 | 46 | 50 | 가능 — 시작·이동·회전·드롭·일시정지·재개를 터치만으로, 한 화면에서 (길게 눌러도 반복은 없음) | 757.5 → **924** | [열기](./simple_llm_test_ff_tetris_v2/) |
| 2 | [`aw`](../00_model_info/aw.md) | **816** | 226 | 112 | 215 | 167 | 46 | 50 | 부분 — 버튼·길게 누르기는 동작하나 v1 부터 자동 낙하가 없고 터치 일시정지도 없음 | 756.5 → **816** | [열기](./simple_llm_test_aw_tetris_v2/) |
| 3 | [`q38`](../00_model_info/q38.md) | **782** | 202 | 136 | 198 | 156 | 40 | 50 | 부분 — 4버튼(◀▶⟳▼)으로 시작과 입력은 되나 v1 의 충돌 결함이 남아 조각이 10행에서 굳고 우측 열 6 까지만 가며 줄을 지울 수 없음 (일시정지 기능도 없음) | 742.5 → **782** | [열기](./simple_llm_test_q38_tetris_v2/) |
| 4 | [`mg`](../00_model_info/mg.md) | **736** | 216 | 118 | 213 | 94 | 45 | 50 | 부분 — 버튼·스와이프는 동작, 단 START 버튼이 하단 바에 가려지고 하드드롭(■)은 게임을 죽임 | 571.5 → **736** | [열기](./simple_llm_test_mg_tetris_v2/) |
| 5 | [`q36`](../00_model_info/q36.md) | **696** | 176 | 112 | 193 | 127 | 38 | 50 | 불가 — 터치로 시작할 수 없음 (키로 시작하면 버튼은 동작, HOLD 는 곧 게임오버) | 657 → **696** | [열기](./simple_llm_test_q36_tetris_v2/) |
| 6 | [`cn`](../00_model_info/cn.md) | **678** | 179 | 90 | 223 | 108 | 28 | 50 | 부분 — 스와이프 이동·시작·일시정지는 되나 탭 회전은 불능, 조작 버튼은 스크롤해야 보임 | 729.5 → **678** | [열기](./simple_llm_test_cn_tetris_v2/) |
| 7 | [`mcv`](../00_model_info/mcv.md) | **447** | 0 | 40 | 222 | 107 | 28 | 50 | 불가 — viewport 메타가 없어 터치 버튼이 숨겨지고 터치로 시작도 못 함 | 786.5 → **447** | [열기](./simple_llm_test_mcv_tetris_v2/) |
| 8 | [`orn`](../00_model_info/orn.md) | **446** | 0 | 52 | 150 | 156 | 38 | 50 | 불가 — 초기 렌더 예외로 터치 UI 와 낙하 루프가 켜지지 않음 | 661.5 → **446** | [열기](./simple_llm_test_orn_tetris_v2/) |
| 9 | [`bolt`](../00_model_info/bolt.md) | **403** | 0 | 73 | 145 | 95 | 40 | 50 | 불가 — v1 의 시작 단계 예외에 더해, 터치 핸들러가 없는 메서드(`DOMRect.contains`)를 불러 매번 예외 | 462 → **403** | [열기](./simple_llm_test_bolt_tetris_v2/) |
| 10 | [`fn`](../00_model_info/fn.md) | **365** | 0 | 105 | 90 | 90 | 30 | 50 | 불가 — 첫 조각을 만들지 않아 첫 입력부터 예외, 보드가 계속 비어 있음 | 0 → **365** | [열기](./simple_llm_test_fn_tetris_v2/) |
| 11 | [`lfm`](../00_model_info/lfm.md) | **343** | 0 | 35 | 125 | 115 | 18 | 50 | 불가 — 정의되지 않은 `canvas` 를 참조해 스크립트가 중단됨 | 445 → **343** | [열기](./simple_llm_test_lfm_tetris_v2/) |
| 12 | [`mel`](../00_model_info/mel.md) | **175** | 0 | 60 | 5 | 50 | 10 | 50 | 불가 — 문법 오류로 스크립트 전체가 실행되지 않음 (키보드까지 죽음) | 498 → **175** | [열기](./simple_llm_test_mel_tetris_v2/) |
| 13 (공동) | [`c7r`](../00_model_info/c7r.md) | **0** | 0 | 0 | 0 | 0 | 0 | 0 | 파일 없음 | 0 → **0** | 제작 실패 |
| 13 (공동) | [`c7`](../00_model_info/c7.md) | **0** | 0 | 0 | 0 | 0 | 0 | 0 | 파일 없음 | 0 → **0** | 제작 실패 |
| 13 (공동) | [`c1`](../00_model_info/c1.md) | **0** | 0 | 0 | 0 | 0 | 0 | 0 | 파일 없음 | 0 → **0** | 제작 실패 |

### 실용 순위 (600점 이상, 소요 시간순)

1000점 순위와 별도로, 총점이 600점 이상인 6종만 **소요 시간이 짧은 순서**로 나열했습니다.

| 순위 | 모델 | 총점 | 제작 시간 | 요청 수 | 생성 토큰 |
|---:|---|---:|---:|---:|---:|
| 1 | [`q36`](../00_model_info/q36.md) | 696 | 1:57 | 18 | 4,915 |
| 2 | [`cn`](../00_model_info/cn.md) | 678 | 2:54 | 19 | 5,611 |
| 3 | [`mg`](../00_model_info/mg.md) | 736 | 3:54 | 15 | 4,338 |
| 4 | [`q38`](../00_model_info/q38.md) | 782 | 4:10 | 12 | 3,567 |
| 5 | [`ff`](../00_model_info/ff.md) | 924 | 5:27 | 16 | 3,705 |
| 6 | [`aw`](../00_model_info/aw.md) | 816 | 6:01 | 8 | 18,645 |

- 이 표의 6종 중 **시작부터 터치로 이어서 플레이할 수 있는 것은 `ff` 와 (스크롤이 필요한) `cn` 2종**입니다(위 「터치로 플레이 가능?」 열 참고). 나머지는 터치로 시작할 수 없거나(`q36`), 시작 버튼이 가려지고 하드드롭이 게임을 죽이거나(`mg`), 자동 낙하가 없거나(`aw`), 충돌 결함으로 조각이 판 중간에서 굳습니다(`q38`).
- `q36` 이 1분 57초로 가장 빨랐고, `aw` 는 요청 8회에 생성 토큰 18,645개로 이번 회차에서 가장 많이 생성했습니다. v1 과 비교할 수 있는 5종(`q36`·`cn`·`q38`·`ff`·`aw`) 중 `cn`(2:10 → 2:54)만 시간이 늘었고, 나머지는 줄었습니다(`q38` 26:53 → 4:10, `ff` 10:08 → 5:27, `aw` 8:52 → 6:01, `q36` 4:59 → 1:57).

### 눈에 띈 점

- **`ff` 가 1위(924점)이고, 시작·이동·회전·드롭·일시정지·재개를 터치만으로 한 화면에서 모두 해낸 유일한 모델입니다.** 터치 286/300, 화면 맞춤 144/150 으로 둘 다 1위입니다. 하단에 「회전 2개 + DROP / 좌우 + ▼ + II / START」 세 묶음 버튼을 두고 보드 위 스와이프·탭도 받습니다. 시험에서 모든 버튼이 한 번에 맞게 동작했고 보드·점수·NEXT·버튼이 844px 높이 안에 들어왔습니다(세로 14px 초과). 감점은 길게 눌러도 반복되지 않는 점(1초를 눌러 한 칸), 힌트 문구가 오른쪽에서 잘리는 점 정도입니다. 코드도 1위(4절 173/200)입니다. 버튼을 `data-act` 속성과 `doAction` 디스패처 하나로 묶었습니다(다만 키보드는 이 디스패처를 거치지 않는 별도 switch). 5분 27초, 요청 16회에 끝냈습니다.
- **2~5위(`aw`·`q38`·`mg`·`q36`)는 터치 버튼이 입력은 받았지만 각자 하나씩 빠졌습니다.** `aw`(816)는 변경이 순수 추가형(+158/−0)이고 길게 누르기 반복도 되는데, v1 의 자동 낙하 없음이 그대로라 ↓ 를 눌러야만 내려오고, 터치 일시정지가 없으며 버튼 폭이 33px 로 좁습니다. `q38`(782)은 4버튼(◀▶⟳▼, ▼ 길게 누르면 연속)이 입력을 받고 safe-area 까지 챙겼지만, v1 의 충돌 결함(이중 오프셋)이 그대로라 조각이 맨 아래 행(19행)이 아니라 10행에서 굳고, 오른쪽으로는 열 6 까지만(끝 열은 9) 가며, 줄을 지울 수 없습니다. 일시정지 기능도 애초에 없고, README 의 「화면 아무 곳이나 탭하면 시작」은 사실이 아닙니다(버튼을 눌러야 시작). `mg`(736)는 버튼과 스와이프를 모두 넣고 README 도 정확하지만(v1 8위에서 4위로) START 버튼이 하단 고정 바에 가려져 윗 9px 띠만 눌리고, 하드드롭(■)은 v1 의 예외를 그대로 복제해 게임을 죽이며, 일시정지 뒤 재개를 누르면 새 게임이 시작됩니다. `q36`(696)은 큰 버튼 6개가 동작하지만 터치로 게임을 시작할 방법이 없고(Enter/Space 뿐), 새로 만든 HOLD 버튼이 v1 의 버그(첫 홀드 = 게임오버)를 그대로 드러냅니다.
- **터치가 아무것도 못 한 모델이 6종(`lfm`·`mel`·`bolt`·`orn`·`mcv`·`fn`)이고, 원인은 제각각이지만 모두 한 번만 눌러 봐도 드러납니다.** 이들의 터치 점수는 모두 0/300 입니다.
- 원인 · `lfm`: 터치 리스너를 `canvas` 에 달았는데 이 이름은 정의돼 있지 않습니다(변수는 `CANVAS`, index.html 306줄). ReferenceError 로 스크립트가 거기서 멈춰 `startGame()` 도 실행되지 않습니다. v1 도 이미 빈 보드였습니다.
- 원인 · `mel`: 붙여넣다 남은 `startGame(); });` 두 줄 때문에 `script.js` 가 문법 오류가 되어 통째로 실행되지 않습니다. 터치 버튼도 CSS 에 `display:none` 만 있어 늘 숨겨져 있습니다. v1 에서 키 입력에 반응하던 게임이 키보드까지 죽었으므로 **이번 회차의 유일한 명백한 회귀**이고, 순위가 9위에서 12위(498 → 175)로 내려갔습니다.
- 원인 · `bolt`: 터치 판정에 `getBoundingClientRect().contains(x, y)` 를 썼는데 `DOMRect` 에는 `contains` 메서드가 없어 터치마다 TypeError 가 납니다(618줄). v1 의 시작 단계 예외(`window.nextPiece`)도 그대로입니다.
- 원인 · `orn`: 로드할 때 `drawNext()` 가 `nextQueue[0]` 에서 TypeError(v1 부터 있던 초기 렌더 예외)를 내고, 그 뒤의 `fit()`·터치 UI 만들기·낙하 루프가 실행되지 않습니다. 코드 리뷰어는 입력 구조(버튼과 제스처가 한 액션 맵을 공유, 액션이 상태 가드를 내장)를 12종 중 최고로 보았지만 실행되지 않았습니다.
- 원인 · `mcv`: viewport 메타가 없어 폰이 980px 폭 레이아웃으로 그리고, 터치 버튼이 들어 있는 `@media (max-width:600px)` 가 걸리지 않아 버튼이 계속 숨겨집니다. 터치로 시작할 방법도 없습니다(시작은 Enter 뿐). README 는 「터치 컨트롤 자동 표시」라고 적었습니다. **지난 라운드 1위(786.5)가 7위(447)로 떨어졌습니다.**
- 원인 · `fn`: 아래 항목 참고.
- **`fn` 은 v2 에서 처음으로 게임을 만들었지만 돌아가지 않습니다.** v1 폴더가 비어 있어 지시문의 「앞서 만든 게임」이 없었는데도 처음부터 만들었고(448초, 요청 17회, 생성 7,804토큰으로 이번 회차에서 가장 오래 걸림) 그래서 v1 의 0점에서 365점이 됐습니다. 다만 `reset()` 이 첫 조각을 만들지 않아 첫 입력과 중력부터 `cur` 접근 예외가 나고 보드가 계속 비어 있으며, RESTART 버튼이 늘 보여 ▶·▼ 버튼 위를 가립니다. 반면 `c7`·`c7r`·`c1` 은 v2 에서도 파일을 하나도 만들지 못했습니다(생성 토큰 1,134·52·125개, 8~62초에 종료. 원인은 분석하지 않았습니다).
- **어떤 모델도 v1 의 버그를 고치지 않았습니다(QA 가 diff 전수 확인).** 바로 옆 코드를 만지고도 그랬습니다. `mg` 는 keydown 블록을 들여쓰기까지 손대고도 하드드롭의 `pos.y++` 오류를 그대로 두었고 새 `hardDrop()` 에 복제했습니다. `orn` 은 `fit()` 을 고치면서 바로 아래 init 의 예외는 두었습니다. `aw` 는 중력의 시간 비교 오류(208줄의 `Date.now()` 와 470줄 `requestAnimationFrame` 타임스탬프를 비교)를 안 고쳐서, 버튼을 아무리 잘 달아도 조각이 저절로 내려오지 않습니다. `q38` 의 충돌 이중 오프셋도 v1 코드 그대로입니다. `mcv` 의 일시정지 뒤 재개 불능, `q36` 의 HOLD = 게임오버, `bolt` 의 시작 예외도 모두 그대로이고, 1위 `ff` 도 게임 로직은 건드리지 않았습니다(+158/−5). 터치 버튼이 오히려 이 버그들을 더 쉽게 드러냈습니다(`mg` 의 ■, `q36` 의 HOLD). 다만 모델은 v1 의 피드백을 받지 못한 채 작업했으므로 이를 감점하지 않고 「v1 대비 개선」 50점을 중립 25점 기준으로 두었습니다.
- **README 가 실제 동작과 어긋난 곳이 많습니다.** 파일이 있는 12종 중 8종에서 코드와 다른 주장이 나왔습니다(`ff` 도 「보드 제스처가 클릭도 지원」 한 줄은 틀립니다). `cn`: 「캔버스 탭 = 회전」(실제로는 무반응. `touchstart` 의 `preventDefault` 가 click 합성을 막고, `handleTouchTap` 은 등록되지도 않음). `q38`: 「화면 아무 곳이나 탭하면 시작」(버튼만 시작). `mcv`: 「overlay 의 시작 버튼」「터치 컨트롤 자동 표시」(없거나 숨겨짐). `lfm`: 「화면 상단의 일시정지 버튼」(없음). `orn`: 「하드 드롭: 화면을 두 번 탭」(실제로는 한 번 탭). `mel`: 한 줄 README 가 적은 drop 버튼(없음). `fn`: RESTART 는 「게임 오버 때 나타남」(늘 보임). `q36`: 터치로 시작·일시정지할 방법이 없다는 사실은 적지 않고 index.html 만 열면 바로 플레이할 수 있다고만 적었습니다. 코드 리뷰어가 「거의 정확」하다고 본 것은 `ff`(46)·`aw`(46)·`mg`(45) 3종이고 5절 점수는 10~46/50 입니다.
- **화면에 맞추는 일에서 함정이 반복됐습니다.** 버튼이 한 화면 밖에 있는 경우(`cn` 은 조작 패널이 화면 아래로 밀려 전체 높이가 1.5화면, `bolt` 는 버튼 격자가 아래에 있고 body 를 flex 로 가운데 정렬해 캔버스 윗부분이 화면 위로 밀려나 스크롤로도 닿지 않음)와, 고정 오버레이가 자기 버튼을 가리는 경우(`mg` 의 START, `fn` 의 RESTART 가 ▶▼ 를 가로챔)가 있었습니다. `aw` 는 버튼 폭이 33px 로 엄지 기준 44px 에 못 미쳤습니다. `q38` 은 66×66 버튼에 safe-area 도 반영했지만 가로 맞춤 축소로 보드 폭이 약 153px 로 작습니다.
- **코드 리뷰와 실행이 또 갈렸습니다.** 코드 리뷰어의 4·5·6 합계(300점) 순위는 `ff` 269 > `aw` 263 > `q38` 246 > `orn` 244 > `q36` 215 인데, 4위 `orn` 은 실행하면 터치가 전혀 안 됩니다. `q38`(3위)도 v1 때처럼 코드만 읽은 리뷰는 정상 동작을 예상했지만, 실행 재검증에서 충돌 결함이 확인됐습니다. 키보드 핸들러까지 공통 액션 디스패처로 묶은 모델은 하나도 없어 입력 구조(4-b, 70점 만점)에서 70점 이상은 나오지 않았고 최고는 `orn` 의 60점입니다. 흔한 패턴은 키보드 로직을 터치 쪽에 복사하는 것입니다(`mg`·`mcv` 는 키보드 처리를 통째로, `bolt` 는 하드드롭을, `q36` 은 좌우 반복 입력을 복사).

### v1 → v2 변화

v1 순위·총점은 위 9절, v2 는 위 표입니다. 두 라운드의 루브릭이 달라서 점수 차이는 「이 과제에서 얼마나 잘 했나」의 변화이지 같은 잣대의 증감이 아닙니다.

| 모델 | v1 순위 / 총점 | v2 순위 / 총점 | 변화 | 한 줄 이유 |
|---|---|---|---:|---|
| [`ff`](../00_model_info/ff.md) | 2위 / 757.5 | **1위 / 924** | +166.5 | 시작·정지·재개까지 터치만으로 되는 유일한 모델, 한 화면 배치 |
| [`aw`](../00_model_info/aw.md) | 3위 / 756.5 | **2위 / 816** | +59.5 | 순수 추가형 변경과 정확한 README, 자동 낙하 없음은 그대로 |
| [`q38`](../00_model_info/q38.md) | 4위 / 742.5 | **3위 / 782** | +39.5 | 4버튼 입력과 safe-area 대응, 그러나 v1 의 충돌 결함이 그대로(10행에서 굳음)이고 일시정지 없음 |
| [`mg`](../00_model_info/mg.md) | 8위 / 571.5 | **4위 / 736** | +164.5 | 버튼과 스와이프가 동작, START 가림과 하드드롭 크래시 |
| [`q36`](../00_model_info/q36.md) | 7위 / 657 | **5위 / 696** | +39 | 버튼은 동작하나 터치로 시작 불가, HOLD 가 곧 게임오버 |
| [`cn`](../00_model_info/cn.md) | 5위 / 729.5 | **6위 / 678** | −51.5 | 스와이프는 되나 탭 회전 불능, 조작 패널이 화면 아래 |
| [`mcv`](../00_model_info/mcv.md) | 1위 / 786.5 | **7위 / 447** | −339.5 | viewport 메타가 없어 터치 버튼이 숨겨짐 |
| [`orn`](../00_model_info/orn.md) | 6위 / 661.5 | **8위 / 446** | −215.5 | 입력 구조는 최상급인데 v1 의 초기 예외가 남아 터치 UI 가 안 켜짐 |
| [`bolt`](../00_model_info/bolt.md) | 10위 / 462 | **9위 / 403** | −59 | v1 의 시작 예외에 `DOMRect.contains` 오류가 더해짐 |
| [`fn`](../00_model_info/fn.md) | 공동 12위 / 0 | **10위 / 365** | +365 | 처음으로 게임을 만들었으나 첫 조각이 없어 입력마다 예외 |
| [`lfm`](../00_model_info/lfm.md) | 11위 / 445 | **11위 / 343** | −102 | 정의되지 않은 `canvas` 참조로 스크립트 중단 |
| [`mel`](../00_model_info/mel.md) | 9위 / 498 | **12위 / 175** | −323 | 붙여넣다 남은 줄로 문법 오류, 키보드까지 죽은 유일한 회귀 |
| [`c7r`](../00_model_info/c7r.md) | 공동 12위 / 0 | **공동 13위 / 0** | 0 | v2 에서도 파일 없음(생성 토큰 52개) |
| [`c7`](../00_model_info/c7.md) | 공동 12위 / 0 | **공동 13위 / 0** | 0 | v2 에서도 파일 없음(생성 토큰 1,134개) |
| [`c1`](../00_model_info/c1.md) | 공동 12위 / 0 | **공동 13위 / 0** | 0 | v2 에서도 파일 없음(생성 토큰 125개) |

### 해석 주의

- **표본은 모델당 1회(n=1)입니다.** 점수 차이가 작은 구간(예: `q36` 696 과 `cn` 678, `mcv` 447 과 `orn` 446)은 순위보다 경향으로 읽어 주세요.
- **v2 총점의 700점(1·2·3)이 실행 검증이라, 실제로 터치가 되느냐가 순위를 거의 정합니다.** 코드 점수(4·5·6)는 300점뿐이어서 코드 구조가 좋아도(`orn`) 실행이 안 되면 1절 300점을 통째로 잃고, 실제로 터치가 안 된 6종은 175~447점에 머물렀습니다. 원작 재현(v1 의 1-3)은 이번 라운드에서 평가하지 않았습니다.
- **3절 「기존 기능 유지」는 「v1 과 달라졌나」를 보는 항목이라, 처음부터 죽어 있던 게임도 「그대로 죽어 있음」으로 일부 점수를 받습니다.** `orn` 150, `bolt` 145 가 그 예입니다(v1 과 같은 동작이라는 비교 점수 100점이 들어 있음). `fn` 은 v1 이 비어 있어 비교 기준이 없어 중립으로 처리했고(3절 90/250), 4절은 변경분 대신 새 코드 자체를 평가했습니다.
- **QA 재검증 기록.** `q38` 의 충돌 결함(바닥 10행에서 굳음·우측 열 6 까지만·줄 삭제 불가)을 재검증으로 확인해 1·3절을 감점했고, 3-1(b) 는 항목 공식으로 전 엔트리에 다시 적용함(원점수는 QA 문서에 보존). 그 결과 `q38`(782)은 `aw`(816) 아래로 내려갔고, 인상으로 주던 점수가 항목별 점수로 바뀌면서 `aw`·`mg`·`q36`·`cn`·`mcv` 의 3절이 3~13점 올랐습니다.
- **`mel` 의 「회귀」는 키 입력에 대한 게임 상태 변화를 기준으로 한 판단입니다.** v1 채점에서는 화면이 그려지지 않는 것으로 기록된 게임이므로, v1 도 보이는 화면으로는 온전히 플레이된 것은 아닙니다.
- **시험의 한계.** 줄 삭제는 재검증에서 바닥 행을 미리 채워 두고 조각을 떨어뜨리는 방식으로 확인했을 뿐, 여러 조각을 쌓아 완성하는 일반 경로는 직접 보지 않았습니다. 점수·레벨 곡선은 확인하지 않았습니다. 터치는 Chrome 의 터치 이벤트 에뮬레이션이며 실제 폰이 아닙니다(iOS Safari 의 더블탭 확대, 주소창 높이 변화, 길게 누르기 메뉴는 재현되지 않음). 터치로 시작할 수 없는 모델(`q36`)은 진단용으로만 키보드로 시작해 나머지 버튼을 확인하고 그만큼 감점했습니다(이동·회전·내리기 ×0.8). 4·5·6 은 코드 리뷰어가 브라우저를 띄우지 않고 diff 와 파일을 읽어 채점했습니다(스크립트 문법만 검사).
- **일부 항목은 주관이 섞여 있습니다.** 직관성, 화면 배치, diff 깔끔함, 입력 구조는 리뷰어 1인의 판단이며 근거는 줄 번호나 시험 단계로 기록했습니다.

## 9-3. 결과 — v3

**채점 방식**: v3(레벨·크레딧·컨티뉴 도입)는 루브릭이 앞의 두 라운드와 다릅니다(7절의 「v3 루브릭」). 1~5절(850점)은 QA 리뷰어가 헤드리스 Chrome 에서 **직접 실측**했습니다. 줄 삭제·레벨업·게임 오버처럼 도달하기 어려운 상태는 콘솔로 상태를 주입해 확인하고, 주입한 방법을 근거에 적었습니다. 6·7절(150점)은 코드 리뷰어가 v2 → v3 변경분을 읽고 채점했습니다. 결과물은 A~O 로 익명 처리(블라인드)해 채점했고, 채점이 끝난 뒤 모델 이름을 공개했습니다.

### 품질 순위 (1000점)

열 머리의 `1/150` 은 「영역/만점」입니다. 1 레벨, 2 크레딧, 3 컨티뉴, 4 게임 흐름, 5 기존 기능 유지, 6 변경의 품질, 7 README 갱신입니다. 공동 순위는 총점이 같은 경우입니다. 「v2 → v3」 열은 루브릭이 달라 단순 뺄셈으로 읽으면 안 됩니다.

| 순위 | 모델 | 총점/1000 | 1/150 | 2/200 | 3/200 | 4/100 | 5/200 | 6/100 | 7/50 | 크레딧 → 시작 → 컨티뉴 → 타이틀 완주? | v2 → v3 총점 | 플레이 링크 |
|---:|---|---:|---:|---:|---:|---:|---:|---:|---:|---|---|---|
| 1 | [`ff`](../00_model_info/ff.md) | **978** | 150 | 200 | 200 | 100 | 195 | 84 | 49 | 완주 — 코인(C, COIN 버튼) → 시작 → 게임 오버 → 코인 + 컨티뉴(점수·레벨 유지) → 시간 초과 → 타이틀을 두 바퀴 실측으로 통과 | 924 → **978** | [열기](./simple_llm_test_ff_tetris_v3/) |
| 2 | [`mcv`](../00_model_info/mcv.md) | **713** | 140 | 155 | 105 | 79 | 143 | 54 | 37 | 부분 — 레벨·키보드 크레딧은 정상, 게임 오버에서 코인 분기가 컨티뉴 분기를 가려 이어 하기 불가. viewport 메타 누락으로 모바일 터치 버튼이 숨겨짐 | 447 → **713** | [열기](./simple_llm_test_mcv_tetris_v3/) |
| 3 (공동) | [`fn`](../00_model_info/fn.md) | **711** | 146 | 95 | 125 | 75 | 165 | 70 | 35 | 부분 — 레벨과 카운트다운 컨티뉴 화면은 동작하나 컨티뉴 후 조각이 만들어지지 않고, 크레딧을 늘리는 코인 수단이 없음 | 365 → **711** | [열기](./simple_llm_test_fn_tetris_v3/) |
| 3 (공동) | [`q38`](../00_model_info/q38.md) | **711** | 132 | 120 | 140 | 82 | 131 | 67 | 39 | 부분 — 새 기능은 동작하나 v1 부터의 충돌 이중 오프셋이 그대로라 조각이 10행에서 굳고 줄 삭제·자연 게임 오버가 사실상 불가(컨티뉴는 게임 오버를 주입해서만 확인) | 782 → **711** | [열기](./simple_llm_test_q38_tetris_v3/) |
| 5 | [`aw`](../00_model_info/aw.md) | **640** | 95 | 110 | 110 | 62 | 163 | 60 | 40 | 부분 — 컨티뉴가 보드를 비우지 않아 확정 즉시 다시 게임 오버, v2 부터의 중력 없음도 그대로, 타이틀의 키 하나가 코인과 시작을 겸함 | 816 → **640** | [열기](./simple_llm_test_aw_tetris_v3/) |
| 6 | [`mg`](../00_model_info/mg.md) | **630** | 144 | 155 | 37 | 49 | 163 | 42 | 40 | 불가 — 자연 게임 오버가 일어나지 않아 컨티뉴에 도달 못 함, 하드드롭 예외(v2 부터)로 루프가 멈춤 | 736 → **630** | [열기](./simple_llm_test_mg_tetris_v3/) |
| 7 | [`cn`](../00_model_info/cn.md) | **616** | 140 | 185 | 30 | 44 | 161 | 28 | 28 | 불가 — 컨티뉴 화면과 카운트다운 코드가 어디서도 호출되지 않는 죽은 코드, 게임 오버의 다시 시작이 크레딧을 우회 | 678 → **616** | [열기](./simple_llm_test_cn_tetris_v3/) |
| 8 | [`q36`](../00_model_info/q36.md) | **559** | 90 | 180 | 25 | 50 | 150 | 36 | 28 | 불가 — 컨티뉴 카운트다운 상태가 대입되지 않아 도달 불가, R 키가 크레딧을 우회, 중력 없음·첫 홀드 즉시 게임 오버(v2 부터) | 696 → **559** | [열기](./simple_llm_test_q36_tetris_v3/) |
| 9 | [`orn`](../00_model_info/orn.md) | **512** | 80 | 150 | 105 | 52 | 37 | 49 | 39 | 불가 — 초기화 예외(v2 부터)로 낙하 루프와 화면 갱신이 없고, 컨티뉴 상태가 대입되지 않으며 줄을 지우면 미정의 함수 호출로 멈춤 | 446 → **512** | [열기](./simple_llm_test_orn_tetris_v3/) |
| 10 | [`lfm`](../00_model_info/lfm.md) | **60** | 5 | 5 | 0 | 0 | 8 | 24 | 18 | 실행 불가 — v2 의 정의되지 않은 `canvas` 참조 오류를 그대로 둠 | 343 → **60** | [열기](./simple_llm_test_lfm_tetris_v3/) |
| 11 | [`bolt`](../00_model_info/bolt.md) | **56** | 5 | 5 | 0 | 0 | 5 | 10 | 31 | 실행 불가 — 새로 만든 keydown 핸들러의 닫는 괄호 누락(문법 오류) | 403 → **56** | [열기](./simple_llm_test_bolt_tetris_v3/) |
| 12 | [`mel`](../00_model_info/mel.md) | **40** | 5 | 5 | 0 | 0 | 7 | 12 | 11 | 실행 불가 — v2 부터의 떠도는 두 줄(문법 오류)을 그대로 둔 채 gameLoop 정의까지 지움 | 175 → **40** | [열기](./simple_llm_test_mel_tetris_v3/) |
| 13 (공동) | [`c7r`](../00_model_info/c7r.md) | **0** | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 파일 없음 | 0 → **0** | 제작 실패 |
| 13 (공동) | [`c7`](../00_model_info/c7.md) | **0** | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 파일 없음 | 0 → **0** | 제작 실패 |
| 13 (공동) | [`c1`](../00_model_info/c1.md) | **0** | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 파일 없음 | 0 → **0** | 제작 실패 |

### 실용 순위 (600점 이상, 소요 시간순)

1000점 순위와 별도로, 총점이 600점 이상인 7종만 **소요 시간이 짧은 순서**로 나열했습니다.

| 순위 | 모델 | 총점 | 제작 시간 | 요청 수 | 생성 토큰 |
|---:|---|---:|---:|---:|---:|
| 1 | [`mcv`](../00_model_info/mcv.md) | 713 | 3:05 | 8 | 8,040 |
| 2 | [`cn`](../00_model_info/cn.md) | 616 | 3:52 | 6 | 7,891 |
| 3 | [`mg`](../00_model_info/mg.md) | 630 | 6:16 | 16 | 7,300 |
| 4 | [`ff`](../00_model_info/ff.md) | 978 | 8:22 | 26 | 7,454 |
| 5 | [`fn`](../00_model_info/fn.md) | 711 | 9:53 | 21 | 10,530 |
| 6 | [`aw`](../00_model_info/aw.md) | 640 | 11:35 | 7 | 30,682 |
| 7 | [`q38`](../00_model_info/q38.md) | 711 | 12:02 | 37 | 12,208 |

- 이 표의 7종 중 **컨티뉴까지 실제 플레이로 이어지는 것은 `ff` 하나**이고(`q38` 은 게임 오버를 주입해서만 확인), 나머지는 컨티뉴 후 멈추거나(`fn`), 코인 분기가 가리거나(`mcv`), 즉시 다시 게임 오버가 되거나(`aw`), 컨티뉴에 도달하지 못합니다(`mg`·`cn`).
- `mcv` 가 3분 5초로 가장 빨랐고(요청 8회) 713점으로 2위입니다. `aw` 는 요청 7회에 생성 토큰 30,682개로 이번 회차에서 가장 많이 생성했고, `q38` 은 12분 2초에 요청 37회로 가장 오래 걸렸습니다. 600점 이상 가운데 최고점 `ff`(8분 22초)는 중간 길이였습니다.

### 눈에 띈 점

- **`ff` 만 요구한 흐름을 끊김 없이 완성했습니다(978점).** 레벨 150·크레딧 200·컨티뉴 200·게임 흐름 100 이 모두 만점이고 1~5절 850점 중 845점입니다(5절 감점은 방향키 스크롤 방지 없음과 모바일에서 제목 잘림뿐이고, 12×24 판은 v2 와 같아 기록만 했습니다). 코인(C 키, COIN 버튼) → 시작 → 게임 오버 → 코인 + 컨티뉴(점수·레벨 유지) → 시간 초과 → 타이틀을 두 바퀴 돌려도 예외 없이 이어졌고, 크레딧 0 에서는 시작도 컨티뉴도 안 되며 우회 경로가 없습니다. 시작과 컨티뉴가 `beginRun` 하나를 공유하고 상태가 TITLE/PLAY/CONTINUE 로 명시돼, 코드 리뷰도 6절 84/100·7절 49/50 으로 1위입니다. 요구에 없는 localStorage 크레딧 영속은 새로고침해도 크레딧이 남게 하는 점에서 흠으로 적혔습니다. 8분 22초, 요청 26회.
- **컨티뉴가 실제로 이어지지 않는 엔트리가 다수입니다. 원인은 제각각입니다.** `fn`: 컨티뉴 함수가 조각을 `null` 로 두고 새 조각을 만들지 않아 판이 멈추고 키마다 예외가 납니다. `mcv`: 게임 오버에서 코인 분기가 컨티뉴 분기를 가려 C·Space 가 크레딧만 1 올립니다. `aw`: 컨티뉴가 보드를 비우지 않아 확정 즉시 다시 게임 오버가 됩니다. `q36`·`orn`: 컨티뉴 카운트다운 상태가 어디서도 대입되지 않아 도달할 수 없고, Enter 는 컨티뉴가 아니라 타이틀 복귀(`q36`)나 새 게임(`orn`)으로 갑니다. `cn`: 컨티뉴 화면 코드가 어디서도 호출되지 않는 죽은 코드입니다. `mg`: 스폰 칸이 충돌 검사에서 제외돼 87조각·60초 스택에도 게임 오버가 일어나지 않아 컨티뉴에 도달하지 못합니다.
- **코인과 시작을 한 키에 묶어 크레딧 게이트가 무의미해진 설계가 있습니다.** `aw` 는 타이틀의 C·Enter·터치가 코인을 넣은 즉시 시작해 크레딧 0 에서도 시작되고, `q38` 도 타이틀 Enter 가 `insertCoin()` 과 `startGame()` 을 연속 실행해 크레딧이 쌓이지 않습니다(2-3 이 60점 중 25점). 반대로 `fn` 은 크레딧을 늘리는 수단이 코드에 없어 시작 크레딧 3개를 다 쓰면 새로고침 말고는 시작할 방법이 없고, `q36` 의 R 키와 `cn` 의 게임 오버 「다시 시작」은 크레딧 0 에서도 새 판을 여는 우회 경로였습니다.
- **`lfm`·`bolt`·`mel` 은 v3 에서 실행조차 되지 않아 40~60점이 됐습니다.** `lfm` 은 v2 의 정의되지 않은 `canvas` 참조(ReferenceError)를 그대로 두고 그 뒤에 새 기능을 붙여, 시작 버튼·게임 루프·컨티뉴가 모두 실행되지 않습니다. `mel` 은 v2 부터 있던 떠도는 `startGame(); });` 문법 오류를 그대로 두었고 v2 의 `gameLoop()` 정의까지 지워서, 문법 오류를 고쳐도 중력이 사라지는 상태입니다. `bolt` 는 새 keydown 핸들러를 `});` 가 아니라 `}` 로 닫아 스크립트 전체가 파싱되지 않습니다(v2 파일은 파싱됐습니다). 세 모델은 v1 부터 제대로 돌지 않았습니다(10절 참고).
- **`q38` 은 v1 부터 있던 충돌 이중 오프셋을 그대로 둔 채 새 기능 점수로 공동 3위가 됐습니다.** 충돌 판정이 셀 절대좌표에 위치를 한 번 더 더해서 조각이 판 중간(10행)에서 굳고, 오른쪽 벽은 열 6 까지만 가며, 줄 삭제와 자연 게임 오버가 사실상 불가능합니다(5절 131/200: 바닥 착지 0/16, 줄 삭제 6/20). 그런데 레벨·크레딧·컨티뉴는 주입(`gameOver()` 호출, 최하단 행 채우기)으로 동작해 1~4절에서 점수를 받았습니다. v3 루브릭이 새 기능에 비중을 둔 결과이므로 아래 「해석 주의」를 함께 읽어 주세요. 컨티뉴 관련 항목에는 70% 상한이 걸렸습니다(3절 180 → 140).
- **이전 판의 버그를 스스로 고친 사례는 문서로 확인되지 않습니다.** `aw` 의 중력 없음, `q36` 의 중력 없음·첫 홀드 즉시 게임 오버, `orn` 의 초기화 예외, `mg` 의 하드드롭 예외, `mcv` 의 viewport 메타 누락, `ff` 의 12×24 판, `lfm`·`mel` 의 실행 중단 오류가 모두 v2 그대로입니다. 유일한 예외 후보는 `fn` 입니다. v2 에서는 `reset()` 이 첫 조각을 만들지 않아 입력마다 예외가 났는데, v3 의 새 시작 함수가 `reset()` 뒤에 `spawn()` 을 부르면서 이 상태에서 벗어났습니다(코드 비교로 확인). 다만 새 흐름을 만들며 생긴 부수 효과로 보이고(심사 기록에도 수정으로 적히지 않았음), 같은 실수를 컨티뉴 함수에서 되풀이했습니다.
- **README 가 실제 동작과 어긋난 곳이 많습니다.** 7절 점수는 `ff` 49/50 부터 `mel` 11/50 까지 갈렸습니다. `q36` 은 컨티뉴 방법(카운트다운 화면, Enter 로 이어 하기, R 은 타이틀로, 10초 뒤 타이틀)이 전부 코드와 달라 그 항목이 0/13 이었고, `fn` 은 「INSERT COIN 으로 코인 투입」과 「새 조각이 나오며 이어짐」이 틀렸으며, `bolt` 는 크레딧이 1 이상이어야 시작한다고 적었지만 코드는 로드 즉시 시작합니다.

### v2 → v3 변화

v2 순위·총점은 9-2절, v3 는 위 표입니다. 두 라운드의 루브릭이 달라 점수 차이는 「이 과제에서 얼마나 잘 했나」의 변화이지 같은 잣대의 증감이 아닙니다.

| 모델 | v2 순위 / 총점 | v3 순위 / 총점 | 변화 | 한 줄 이유 |
|---|---|---|---:|---|
| [`ff`](../00_model_info/ff.md) | 1위 / 924 | **1위 / 978** | +54 | 요구한 아케이드 흐름을 끝까지 완주, 기존 기능도 유지 |
| [`mcv`](../00_model_info/mcv.md) | 7위 / 447 | **2위 / 713** | +266 | 레벨·키보드 크레딧이 실측을 통과해 반등, 컨티뉴는 코인 분기가 가려 불발, viewport 누락은 그대로 |
| [`fn`](../00_model_info/fn.md) | 10위 / 365 | **공동 3위 / 711** | +346 | 시작 함수가 첫 조각을 만들어 게임이 돌아감, 레벨·카운트다운 화면 동작, 컨티뉴 후 조각 미생성 |
| [`q38`](../00_model_info/q38.md) | 3위 / 782 | **공동 3위 / 711** | −71 | 새 기능 점수는 좋으나 v1 부터의 충돌 결함이 그대로(조각이 10행에서 굳음) |
| [`aw`](../00_model_info/aw.md) | 2위 / 816 | **5위 / 640** | −176 | 컨티뉴가 보드를 비우지 않아 즉시 게임 오버, 중력 없음은 v2 그대로 |
| [`mg`](../00_model_info/mg.md) | 4위 / 736 | **6위 / 630** | −106 | 자연 게임 오버가 안 일어나 컨티뉴에 도달 못 함, 하드드롭 예외 그대로 |
| [`cn`](../00_model_info/cn.md) | 6위 / 678 | **7위 / 616** | −62 | 컨티뉴 화면이 호출되지 않는 죽은 코드, 게임 오버 다시 시작이 크레딧을 우회 |
| [`q36`](../00_model_info/q36.md) | 5위 / 696 | **8위 / 559** | −137 | 컨티뉴 상태 미대입, R 키 크레딧 우회, 중력 없음과 첫 홀드 즉시 게임 오버 그대로 |
| [`orn`](../00_model_info/orn.md) | 8위 / 446 | **9위 / 512** | +66 | 낙하 루프는 여전히 안 돌지만 크레딧·카운트다운 상태 로직이 실측을 통과해 소폭 반등 |
| [`lfm`](../00_model_info/lfm.md) | 11위 / 343 | **10위 / 60** | −283 | v2 의 `canvas` 미정의 오류를 그대로 둬 실행 불가 |
| [`bolt`](../00_model_info/bolt.md) | 9위 / 403 | **11위 / 56** | −347 | 새 keydown 핸들러 괄호 누락으로 스크립트 전체가 파싱되지 않음 |
| [`mel`](../00_model_info/mel.md) | 12위 / 175 | **12위 / 40** | −135 | v2 부터의 문법 오류를 그대로 둔 채 gameLoop 정의까지 삭제 |
| [`c7r`](../00_model_info/c7r.md) | 공동 13위 / 0 | **공동 13위 / 0** | 0 | v3 에서도 파일 없음(생성 토큰 114개) |
| [`c7`](../00_model_info/c7.md) | 공동 13위 / 0 | **공동 13위 / 0** | 0 | v3 에서도 파일 없음(생성 토큰 428개) |
| [`c1`](../00_model_info/c1.md) | 공동 13위 / 0 | **공동 13위 / 0** | 0 | v3 에서도 파일 없음(생성 토큰 506개) |

### 재판정 기록

QA 1차 채점이 끝난 뒤 진행자(PM)가 항목 사이의 일관성 규칙 두 가지를 정해 **전 엔트리에 다시 적용**했습니다. 바뀐 항목은 13건이고, 1차 점수는 심사 기록에 그대로 보존했습니다.

- **R1 크레딧 게이트 우회**: 크레딧 0 에서 크레딧을 쓰지 않고 새 게임이 시작되는 경로가 있으면 2-3(크레딧 0 시작 불가, 60점)을 최대 45점으로 합니다. 전수 확인 결과 해당은 `q36`(R 키)과 `cn`(게임 오버의 다시 시작) 둘뿐이고, `q36` 만 60 → 45 로 바뀌었습니다(`cn` 은 1차에서 이미 45). 같은 결함을 4-2(입력 누수)에서 한 번 더 깎았던 몫은 돌려줬습니다(`q36` +5, `cn` +6, `aw` +7).
- **R2 도달 불가 상태의 주입 확인**: 다른 버그 때문에 자연 플레이로는 도달할 수 없어 주입으로만 확인한 상태는 항목 배점의 70% 를 상한으로 합니다. 해당은 `q38`(충돌 결함으로 게임 오버 불가)과 `mg`(스폰 칸이 충돌 검사에서 제외돼 게임 오버 불가)입니다. `q38` 은 여섯 항목(1-4, 3-1~3-4, 4-1)이 깎여 3절이 180 → 140 이 됐고, `mg` 는 1-4 한 항목(17 → 14)만 바뀌었습니다.
- **교차 확인**: 코드 리뷰와 QA 가 같은 결함을 다른 절에서 이중으로 깎은 곳 두 군데도 돌려줬습니다(`fn` 4-2 25 → 40, `orn` 4-2 18 → 32).
- **PM 조정 2건**: `mg` 는 4-2 의 「게임 오버 중 Enter 가 카운트다운을 멈춤」 6점이 3-3 과 같은 결함이라 3-3 에서만 깎고, `q38` 은 4-2 의 「일시정지 없음」 6점이 5-1 의 일시정지 0점과 같은 결함이라 한 번만 깎았습니다(각 +6). 그 결과 `mg` 는 624 → 630, `q38` 은 705 → 711 이 됐고, `q38` 은 `fn` 과 같은 711점으로 공동 3위가 됩니다.

### 해석 주의

- **표본은 모델당 1회(n=1)입니다.** 점수 차이가 작은 구간(예: `fn` 과 `q38` 의 동점 711, `mg` 630 과 `cn` 616)은 순위보다 경향으로 읽어 주세요.
- **v3 루브릭은 새 기능에 비중을 둡니다.** 레벨·크레딧·컨티뉴·게임 흐름(1~4절)이 650점이고, 이 가운데 레벨·크레딧 일부는 키보드 상태만으로도 점수가 납니다. 그래서 `q38` 처럼 v1 부터의 충돌 결함으로 조각이 판 중간에서 굳는 게임도, 새 기능이 주입으로 동작하면 `fn`·`mcv` 와 어깨를 나란히 했습니다. 총점만 보고 「잘 돌아가는 게임」으로 읽지 말고 **「완주?」 열을 총점과 함께** 봐 주세요. 2위 `mcv` 도 컨티뉴가 안 되고 모바일에서 터치 버튼이 숨겨지며, `orn`(512점)은 판이 화면에 그려지지 않는 게임입니다.
- **내부 상태로만 확인한 항목은 깎았습니다.** `orn` 은 낙하 루프가 돌지 않아 화면이 갱신되지 않으므로, 내부 상태로만 확인된 5-1 항목에는 35% 만 줬습니다.
- **`mcv` 의 터치 점수는 엄격한 에뮬레이션 기준입니다.** viewport 메타가 없어 390x844 에서 레이아웃 폭이 980 으로 잡히고 터치 버튼이 숨겨지므로, 폭을 강제로 줄였을 때만 동작한 항목에는 만점의 40% 를 줬습니다.
- **판 크기가 다른 모델이 있습니다.** `ff` 는 12×24, `orn` 은 숨김 2행을 포함한 22행이라 「맨 아래 행」과 「끝 열」은 각 판의 마지막 행·열로 해석했습니다.
- **도달하기 어려운 상태는 주입으로 확인했습니다.** 줄 삭제·레벨업·게임 오버는 상태를 직접 놓고 게임 자체의 코드가 돌게 했으므로, 실제 플레이에서의 도달 가능성은 별개입니다(그래서 R2 상한을 두었습니다). 코드로만 확인한 항목은 배점의 70% 이하입니다.
- **시험의 한계.** 흐름 자동 시험은 코인 키를 소스에서 추정하는 휴리스틱이고, 카운트다운·이어 하기 판정은 별도로 검증 중입니다. 그래서 이번 심사는 자동 시험의 결과가 아니라 QA 의 직접 실측으로 했습니다. 심사는 02 드래곤플라이트 생성과 같은 시간대에 돌았기 때문에, 서버 부하를 줄이려고 헤드리스 Chrome 을 낮은 우선순위(`nice 19`)로 한 번에 하나씩만 실행했습니다. 터치는 Chrome 의 터치 에뮬레이션이며 실제 폰이 아닙니다.
- **일부 항목은 주관이 섞여 있습니다.** 6·7절은 코드 리뷰어 1인의 판단이며, 모든 점수의 근거는 줄 번호·시험 단계·주입한 상태로 기록했습니다.

## 10. 테트리스 종합 — v1 → v2 → v3 (완결)

세 라운드의 총점 평균으로 종합 순위를 냅니다. **종합 순위 = 3라운드 평균(1:1:1)** 입니다. 라운드마다 루브릭이 다르므로(v1 은 코드 품질 600점, v2 는 실행 검증 700점, v3 는 실행 검증 850점) 평균은 「세 과제를 두루 잘 했나」를 보는 값이지 한 잣대의 누적이 아닙니다.

| 종합 순위 | 모델 | v1 | v2 | v3 | 3라운드 평균 | 추세 |
|---:|---|---:|---:|---:|---:|---|
| 1 | [`ff`](../00_model_info/ff.md) | 757.5 | 924 | 978 | **886.5** | 꾸준히 상승 |
| 2 | [`q38`](../00_model_info/q38.md) | 742.5 | 782 | 711 | **745.2** | 상승 후 하락 |
| 3 | [`aw`](../00_model_info/aw.md) | 756.5 | 816 | 640 | **737.5** | 상승 후 하락 |
| 4 | [`cn`](../00_model_info/cn.md) | 729.5 | 678 | 616 | **674.5** | 계속 하락 |
| 5 | [`mcv`](../00_model_info/mcv.md) | 786.5 | 447 | 713 | **648.8** | 급락 후 반등 |
| 6 | [`mg`](../00_model_info/mg.md) | 571.5 | 736 | 630 | **645.8** | 상승 후 하락 |
| 7 | [`q36`](../00_model_info/q36.md) | 657 | 696 | 559 | **637.3** | 상승 후 하락 |
| 8 | [`orn`](../00_model_info/orn.md) | 661.5 | 446 | 512 | **539.8** | 급락 후 반등 |
| 9 | [`fn`](../00_model_info/fn.md) | 0 | 365 | 711 | **358.7** | 꾸준히 상승 |
| 10 | [`bolt`](../00_model_info/bolt.md) | 462 | 403 | 56 | **307** | 계속 하락 |
| 11 | [`lfm`](../00_model_info/lfm.md) | 445 | 343 | 60 | **282.7** | 계속 하락 |
| 12 | [`mel`](../00_model_info/mel.md) | 498 | 175 | 40 | **237.7** | 계속 하락 |
| 13 (공동) | [`c7r`](../00_model_info/c7r.md) | 0 | 0 | 0 | **0** | 계속 0 (파일 없음) |
| 13 (공동) | [`c7`](../00_model_info/c7.md) | 0 | 0 | 0 | **0** | 계속 0 (파일 없음) |
| 13 (공동) | [`c1`](../00_model_info/c1.md) | 0 | 0 | 0 | **0** | 계속 0 (파일 없음) |

- **꾸준히 오른 모델은 `ff`(757.5 → 924 → 978)와 `fn`(0 → 365 → 711)입니다.** `ff` 는 매 라운드 기존 로직을 건드리지 않고 기능만 덧붙여, v3 에서 요구한 흐름을 유일하게 완주했습니다. `fn` 은 v1 에서 빈 폴더였다가 v2 에서 처음 게임을 만들고, v3 에서 공동 3위까지 올랐습니다.
- **무너진 모델은 `lfm`·`bolt`·`mel` 입니다.** 세 모델은 v1 부터 제대로 돌지 않았고(v1 은 코드 품질 점수 덕에 445~498점), 라운드가 갈수록 실행 검증의 비중이 커지면서 v3 에서 40~60점이 됐습니다. 한 번 깨진 파일을 다음 라운드가 이어받으면 회복하지 못했습니다(`lfm`·`mel` 은 v2 의 실행 중단 오류를 그대로 두었고, `bolt` 는 v3 에서 문법 오류를 새로 만들었습니다).
- **아무것도 만들지 못한 소형 모델은 `c1`·`c7`·`c7r` 입니다.** 세 라운드 모두 8~87초 만에 끝났고 파일을 하나도 만들지 못해 0점입니다. v3 에서도 생성 토큰은 114~506개에 그쳤습니다.
- **피드백이 없으면 이전 라운드의 버그는 거의 고쳐지지 않았습니다.** `q38` 의 충돌 결함과 `aw` 의 중력 없음은 v1 부터 v3 까지 세 라운드 내내 그대로이고, `ff` 의 12×24 판, `mcv` 의 viewport 누락, `mg` 의 하드드롭 예외도 남았습니다. 모델은 무엇이 틀렸는지 모른 채 새 기능만 덧붙였고, 그 결과 종합 2~4위(`q38`·`aw`·`cn`)도 평균 700점 안팎에 머문 채 각자 치명적인 결함(충돌, 중력, 컨티뉴 불능)을 안고 있습니다. v1 1위였던 `mcv` 는 v2 에서 7위로 떨어졌다가 v3 에서 2위로 돌아와 종합 5위입니다.
- **생성 시간과 품질은 약하게만 이어집니다.** 파일을 만든 모델 안에서 소요 시간과 총점의 순위 상관은 약한 양(스피어만 약 0.5, v1 0.48·v2 0.50·v3 0.46, 표본 11~12종)입니다. 가장 빨랐던 `mcv`(v3 3:05)는 713점, 가장 오래 걸린 `q38`(v3 12:02, 요청 37회)은 711점이고, 최고점 `ff` 는 세 라운드 모두 중간 길이(10:08, 5:27, 8:22)였습니다. 아무것도 만들지 못한 모델이 매번 몇십 초 안에 끝난다는 점만 분명합니다.

다음 시험: [02 드래곤플라이트](../02_dragonflight_game_test/)

- 모델 정보: [00_model_info](../00_model_info/README.md)
- 저장소 첫 화면: [llm_model_test](../README.md)
