
스무고개의 핵심은 "확률을 갱신하는 것"
이 엔진은 베이지안 추론으로 돌아갑니다. 어렵게 들리지만 아이디어는 단순합니다. 처음엔 모든 메뉴가 후보이고, 사용자가 질문에 답할 때마다 각 메뉴가 정답일 확률을 조금씩 조정합니다. "매운가요? → 예"라고 답하면 매운 메뉴들의 확률은 올라가고, 안 매운 메뉴들은 내려가는 식이죠.
각 메뉴가 어떤 질문에 "예"라고 답할 확률은 라플라스 스무딩을 얹어 계산합니다.
const pYesOf = (m, q) => (m.yes[q] + 1) / (m.yes[q] + m.no[q] + 2);
+1, +2가 라플라스 스무딩입니다. 데이터가 적은 초반에 확률이 0이나 1로 튀어버리는 걸 막아주는 안전장치예요.
답은 예/아니오만 있는 게 아닙니다
사람 마음이 늘 딱 떨어지진 않죠. 그래서 답변을 5단계로 받습니다. 각 단계엔 가중치가 붙습니다.
const ANSWER_W = [.9, .7, .5, .3, .1]; // 예 / 아마도 / 글쎄 / 아닌듯 / 아니오
"예"는 0.9, "아니오"는 0.1, 확신 없는 "글쎄"는 정중앙 0.5입니다. 이 가중치로 각 메뉴의 확률을 갱신합니다.
const applyAnswer = (post, q, w) => {
const next = post.map((p, i) => {
const py = pYesOf(MENUS[i], q);
return p * (w * py + (1 - w) * (1 - py)); // 사후 ∝ 사전 × 우도
});
const z = next.reduce((s, v) => s + v, 0);
return next.map(v => v / z); // 정규화
};
기존 확률(사전)에 이번 답이 주는 정보(우도)를 곱하고, 전체 합이 1이 되도록 정규화합니다. 이게 한 번의 답변마다 반복됩니다.
다음 질문은 "가장 많이 갈라주는" 질문
여기가 제일 재밌는 부분입니다. 40개의 질문 축 중에서 다음 질문을 뭘 던질까요? 답은 "물어봤을 때 후보를 가장 확 갈라주는 질문" 입니다.
각 질문에 대해 "예/아니오 두 결과가 나올 때 예상되는 불확실성(엔트로피)"을 계산하고, 이걸 가장 크게 줄여주는 질문 — 즉 정보 이득이 가장 큰 질문을 고릅니다. 절반은 예, 절반은 아니오로 갈릴 질문이 정보량이 가장 크니까요. "생물인가요?" 같은 질문이 "왼발잡이인가요?"보다 훨씬 강력한 이유와 같습니다.
비슷한 질문을 두 번 묻지 않도록
그런데 정보 이득만 보면 함정이 있습니다. "면 요리인가요?"와 "밥 요리인가요?"는 사실상 같은 걸 두 번 묻는 셈이거든요. 이런 중복을 막기 위해 두 장치를 넣었습니다.
하나는 소프트 상관 패널티입니다. 부팅할 때 40개 질문의 예-확률에 대한 피어슨 상관 행렬을 미리 계산해두고, 이미 답한 질문과 강하게 상관된 질문은 점수를 깎습니다(패널티 강도 λ=0.5). 다른 하나는 하드 배타입니다. "면=예"로 강하게 답했으면 "밥인가요?"는 아예 후보에서 빼버립니다. 면이라고 했는데 밥이냐고 다시 묻는 건 바보 같으니까요.
재밌는 건, 이 상관 행렬이 학습으로 데이터가 바뀌면 자동으로 다시 계산된다는 점입니다. 서비스가 똑똑해지면 "무엇이 중복 질문인가"에 대한 판단도 같이 갱신됩니다.

첫 질문만은 살짝 랜덤하게
한 가지 디테일. 매번 똑같은 질문으로 게임이 시작되면 지루하겠죠. 그래서 첫 질문만은 정보 이득 상위 3개 중에서 무작위로 고릅니다.
"첫 질문만 상위 후보 중 무작위로 골라 매 판 시작을 다양화한다(아직 답이 없어 패널티 무영향). 둘째 턴부터는 결정론적으로 정보 이득이 가장 큰 질문을 고른다."
아직 답이 하나도 없는 첫 턴이라 무작위로 골라도 정보 손실이 없다는 게 근거입니다. 둘째 질문부터는 다시 냉정하게 "가장 잘 가르는" 질문으로 돌아갑니다.
언제 멈추고 "이거죠?" 하나
무한정 물어볼 순 없으니 종료 조건도 정해뒀습니다.
| CONF | 0.55 | 1등 후보 확률이 이 이상이면 짐작 |
| SOFT_CAP | 18 | 질문이 이만큼 쌓이면 짐작으로 전환 |
| HARD_CAP | 24 | 절대 상한 |
| MAX_GUESSES | 3 | 틀린 짐작 최대 횟수 |
| TB_MAX / TB_GAP | 2 / 0.45 | 종반 1·2등을 가르는 질문 최대 2개 추가 |
1등 후보의 확률이 55%를 넘으면 "이거 아닌가요?"라고 짐작하고, 그게 아니면 질문을 계속하되 18개쯤에서 슬슬 짐작으로 전환합니다. 1·2등이 막상막하일 땐 종반에 둘을 확실히 가를 질문을 최대 2개 더 던지는 tie-breaker도 넣었습니다.
직접 사용해보세요. 👇
👉 https://amugeona.up.railway.app/
다음 편에서는
이 엔진의 진짜 매력은 "틀렸을 때"입니다. 못 맞히면 사용자가 정답을 직접 알려주고, 그 답이 다음 사람을 위한 데이터가 됩니다. 틀릴수록 똑똑해지는 학습 구조와, 그 과정에서 잡은 버그 하나를 이야기하겠습니다.