← 프로젝트 회고 · Algorithm
RETROSPECTIVE · 회고

'이거 아까 나온 패턴인데?': 자동 채보의 반복을 숫자로 잡기

Algorithm

이 사이트의 리듬게임은 mp3를 넣으면 채보를 자동으로 만든다. 드럼·박자를 분석해 노트 시각을 고르고, 레인은 계단(D F J K), 트릴(D F K J), 연타 같은 익숙한 패턴으로 깐다. 패턴을 넣고 나서 '너무 랜덤하다'는 불만은 사라졌는데, 새 불만이 생겼다. 치다 보면 아까도 있었던 패턴인데? 싶은 게 꽤 많다.

흥미로운 건 같은 알고리즘으로 만든 곡 중 '질주주의보 매우 어려움'은 반복 느낌이 없다는 피드백이었다. 같은 코드인데 왜 곡마다 다를까.

먼저 다른 사람들은 어떻게 하나

  1. TaikoNation(태고의 달인 채보 생성 논문)은 좋은 채보의 핵심을 patterning, 즉 '곡의 사건에 맞춰 노트끼리 일관된 패턴을 이루는 것'으로 정의한다. 그런데 사람이 만든 채보에서 패턴 조합의 92.5%가 서로 달랐다. 패턴은 있되 같은 패턴은 거의 다시 안 쓴다.
  2. osu!mania 매퍼 가이드들은 기본 패턴(스트림·점프·잭·앵커)을 알고 나면 그걸 비틀어 쓰라고 한다. 계단 대신 S자 계단, 롤 대신 갈라진 롤처럼. '음악이 반복되면 패턴도 반복'이 원칙이지만, 반복 구간도 변주하는 매퍼가 많다.
  3. 리듬게임 채보 강좌들은 '반복하되 변주하라'를 강조한다. 똑같이 치게 하지 말고 관련 있지만 다른 변형을 쓰라는 것.

느낌을 숫자로

'반복되는 느낌'을 재려고 지표를 하나 만들었다. 채보를 레인 문자열(D, F, DK…)로 바꾸고, 연속 8노트의 레인 배열이 곡 앞쪽에 이미 나온 적 있는 비율을 센다.

function repeatRate(seq: string[], n = 8) {
const seen = new Set<string>();
let hit = 0, total = 0;
for (let i = 0; i + n <= seq.length; i++) {
const key = seq.slice(i, i + n).join(" ");
total++;
if (seen.has(key)) hit++;
seen.add(key);
}
return hit / total;
}

결과가 피드백과 딱 맞았다. 반복 느낌이 없다던 질주주의보 매우 어려움은 25%, 나머지 곡의 매우 어려움은 54~62%였다. 느낌이 아니라 실제로 두 배 넘게 반복되고 있었다.

원인 세 가지

  1. 어휘가 적었다. 패턴이 15개쯤이고, 그중 계단·트릴처럼 4칸짜리가 대부분이었다. 16분으로 꽉 찬 마디(16칸)는 같은 4칸 모양이 네 바퀴 돈다.
  2. 이력이 없었다. 패턴을 고를 때 '직전과 다른 것'만 봤다. 곡 전체에서 계단을 몇 번 썼는지는 신경 쓰지 않았다.
  3. '프레이즈 반복'이 오히려 반복을 만들었다. 마디 안 리듬이 같으면 앞 마디 레인을 그대로 복사하는 기능이 있었다. 음악이 반복될 때 손 모양도 반복하려는 의도였는데, 8분·16분으로 고르게 찬 마디는 리듬이 전부 같아 보여서 코러스 8마디가 통째로 같은 손 모양이 됐다. 질주주의보가 덜 반복된 건, 그 곡은 리듬이 들쭉날쭉해서 이 복사에 덜 걸렸기 때문이었다.

고친 것

  1. 어휘 늘리기: 기본 모양을 25가지로 늘리고(W, 사다리, 바운스, 앵커, 점프스트림…), 각각 좌우 반전·역방향을 자동으로 만들었다. 회전하면 같아지는 모양은 하나로 합쳐 48개가 됐다.
  2. 이력 패널티: 곡 전체에서 쓴 횟수 n만큼 가중치를 1/(1+0.8n)로, 최근 4조각 안에 나온 모양은 ×0.12, 같은 계열(계단끼리, 트릴끼리)이 연달아 나오면 ×0.4.
  3. 반복은 변주로: 같은 모양을 그대로 잇는 건 한 번만, 그다음은 반전·역방향 변형으로만, 최대 2마디. 그 뒤엔 다른 모양.
  4. 꽉 찬 마디는 반 마디씩: 12칸 이상 조각은 둘로 나눠 뒷 반은 변주나 다른 모양.
  5. 프레이즈 복사 제한: 간격이 고른 마디는 복사하지 않고, 원본 하나당 3번까지, 홀수 번째 반복은 좌우 반전.

결과: 8노트 재등장률이 54~62%였던 곡들이 12~24%로, 질주주의보는 11%로 내려갔다. 노트 시각은 건드리지 않았으니 레벨은 그대로였고, 어려움 이상에서 노트의 83~97%가 여전히 알아볼 수 있는 패턴 안에 있었다. 직접 쳐 본 반응은 '드디어 찾아냈구나'였다.

배운 점

  1. '재미없다'는 피드백은 숫자로 바꿀 수 있을 때 고칠 수 있다. 좋은 예(질주주의보)와 나쁜 예를 같은 지표로 비교하니 원인이 바로 보였다.
  2. 좋은 의도의 규칙(음악이 반복되면 손도 반복)도 입력이 특정 모양일 때 정반대 결과를 낸다. 규칙의 전제(리듬이 같다 = 같은 프레이즈)가 언제 깨지는지 봐야 한다.
  3. 다양성은 후보를 늘리는 것만으로는 안 생긴다. '무엇을 이미 썼는지' 기억해야 생긴다.
Gunmo Lee
'이거 아까 나온 패턴인데?': 자동 채보의 반복을 숫자로 잡기 | Gunmo's Dev Life