"고쳤어요"라는 말을 세 번이나 들었다
퐁 게임을 브라우저에 옮긴 이야기를 적으면서 마지막에 살짝 흘렸지. 사실 그 게임, 완성되고 나서도 한참을 더 고쳤어. AI 조카가 "이제 됐습니다"라고 말한 게 세 번인데, 그중 진짜로 됐던 건 마지막 한 번뿐이었지. 오늘은 그 세 번의 재판 기록이야.

1차 재판 — 패들 구석에 공을 두면 시간이 멈춘다
내가 직접 게임을 해보다가 이상한 걸 발견했어. 패들을 특정 자리에 딱 붙여놓으면 공이 위아래로만 왔다리 갔다리 할 뿐, 끝나지 않는 게임 지옥에 빠지는 거지. 수명 다 한 형광등처럼 깜빡거리기만 하는 공을 한참 지켜보다가 조카를 불렀지.
사실 예전에 처음 결과를 받았을땐 그대로도 좋았어. 처음이기도 하고 신기했으니까. 그런데 이제 조금 욕심이 생긴다고 할까나. 그래서,
"이게 뭐야? 이게 게임이야? 어? 이게 게임이냐고?"
조카도 처음엔 애를 먹었어. 실시간으로 재현하려니 화면이 눈 깜짝할 새 지나가버려서 정확한 순간을 못 잡겠다는 거야. 그래서 방법을 바꿔서, 게임을 한 프레임씩 강제로 넘겨가며 정지 화면을 들여다봤대. 그랬더니 공이 딱 같은 두 자리를 영원히 왔다 갔다 하는 게 잡혔다더라고.
원인은 이거였어. 공이 패들에 부딪히는 상황은 사실 두 가지야. "정면으로 딱 맞았을 때"랑 "모서리에 살짝 스쳤을 때". 정면으로 맞았을 때는 공이 패들 속으로 파고든 것처럼 보이면 이상하니까, "공 위치를 패들 바로 앞으로 확 끌어다 놓는" 걸로 그걸 막아준다고 하더라고. 반면 모서리에 스쳤을 때는 그런 것 없이 그냥 방향만 살짝 틀어주면 충분하고.
근데 코드가 이 둘을 구분 안 하고, 모서리에 스쳤을 때도 정면용 위치 보정을 똑같이 적용했다는거지. 그러니까 공은 방향이 안 바뀌는데(모서리라서 살짝만 틀어져야 하는데), 위치는 자꾸 같은 자리로 끌려오는(정면용 보정이 실행되니까) 상황이 반복된거야. 공 입장에서는 제자리걸음만 하는 셈이니 영영 못 빠져나갈 수 없는 무한 회귀 지옥에 빠질 수 밖에.(유중혁이 이런 기분이었을까?) 녀석은 당당하게 말했지.
"다 됐어!"
2차 재판 — "여전히 안 끝나는데?"
다 됐다고? 이젠 알아. 이 녀석이 거짓말도 꽤 할 줄 안다는 걸. ai가 자동으로 확인했다는 것과 내가 직접 만져본 결과가 다르다니...
"솔직히 말해. 너 모르지?"
"아니, 나 아는데?"
이건 발끈한 척일까? 아니면 진짜 발끈한걸까? 나는 나비인가? 나비가 나인가? 아무튼 이번엔 패들을 아예 화면 맨 끝에 딱 붙여놓고 가만히 뒀대. 그랬더니 공은 계속 움직이는데 점수는 20초가 넘도록 단 한 번도 안 나는 걸 확인했다는 거야.(내가 말한 걸 이제 확인하다니.)
진짜 원인은 이거였어. 이 게임은 공이 튕길 때 늘 똑같은 각도로만 반사되고 속도도 절대 안 바뀌게 짜여 있었대. 그러니 패들을 안 움직이고 가만히 두면 공과 AI 사이에서 똑같은 패턴이 영원히 반복되면서 득점이 안 나는 상황이 생기더라는 거야. 조카가 이런 걸 "무한루프"라고 부른다고 알려주더라고.(문제나 해결해.)
벽에 딱 붙은 자리가 제일 쉽게 이 함정에 빠졌고. 조카는 이참에 실제 탁구처럼 "패들 어디에 맞았는지"에 따라 반사 각도가 달라지도록 물리 자체를 다시 짰어. 중앙에 맞으면 똑바로, 가장자리에 맞으면 비스듬히.

덕분에 예전의 복잡했던 예외 처리도 걷어낼 수 있었대. 근데 이건 인간 입장에선 상식인데 ai는 아닌가봐.
3차 재판 — 버그는 아닌데, 이번엔 너무 쉬웠다
각도까지 고치고 나니 이번엔 전혀 다른 종류의 불만이 생겼어. AI가 공을 받을 때마다 어찌나 정확하게 정중앙으로만 받아내는지, 결국 늘 공이 일자로만 튕기더라고. 애써 고친 각도 기능이 AI 앞에서는 무용지물이었던 거지.
이러면 게임이 안 되니 조정할 필요가 있었고 AI가 매번 공의 정확한 위치가 아니라 "살짝 빗나간 목표 지점"을 조준하게 바꾼 거야. 그 빗나가는 정도는 공을 되받아칠 때마다 새로 랜덤하게 정해지고. 그러니까 일부러 조금씩 실수하는 척을 시킨 셈이야. 물론 ai입장에서 말이야.
돌이켜보면 2차와 3차는 결국 같은 자리를 고친 거였어. 아래 코드에서 각도를 정하는 줄(hitOffset)이 무한루프를 끊어준 부분이고, 바로 다음 줄(aiAimOffset)이 AI를 살짝 허술하게 만들어준 부분이야.

오늘의 에러노트 요약
| 증상 | 정체 | 처방 |
|---|---|---|
| 패들 모서리에서 공이 안 빠짐 | 모서리 반사에 정면용 위치 보정이 같이 적용됨 | 정면/모서리 케이스를 분리 |
| 가만히 둬도 무한루프에 빠짐 | 반사 각도·속도가 항상 고정 | 맞은 위치에 따라 반사 각도가 달라지게 물리 수정 |
| AI가 너무 완벽해서 재미없음 | 버그 아님, AI 조준이 지나치게 정확 | 매번 랜덤하게 살짝 빗나간 지점을 조준하게 변경 |
세 번을 고치고 나서 든 생각은 하나야. 자동으로 확인했다는 말과 사람이 직접 써봤다는 말은 다르다는 것. 그리고 그 틈을 메우려고 다시 파고들면, 처음 고쳤던 것보다 한 뼘 더 튼튼한 해법이 나오기도 한다는 것. 다음엔 또 어떤 녀석을 데려다 이 오락기 진열장에 세워볼지 벌써 기대가 돼.