H
ryuhaon.dev
/Blog/로또 번호 뽑기에 별자리와 MBTI를 붙여봤다 — 미스틱 로또 개발기
개발게임Next.js회고

로또 번호 뽑기에 별자리와 MBTI를 붙여봤다 — 미스틱 로또 개발기

번호 생성기 하나가 별자리, MBTI, 기분 선택 3단계 소환 의식이 되기까지.

로또 번호 생성기는 사실 코드 몇 줄이면 된다.

1부터 45 사이 숫자 6개를 랜덤으로 뽑으면 끝이다. 근데 그걸 그냥 보여주면 아무 재미가 없다. "왜 이 번호야?"라는 질문에 아무 답도 없는 숫자들.

그래서 생각했다. 이 번호가 나한테서 나온 것처럼 만들면 어떨까.


아이디어 — 번호에 이유를 붙이기

사람들이 로또를 살 때 그냥 QR 긁는 사람도 있지만, 생일이나 기념일로 번호를 직접 고르는 사람도 많다. 번호에 의미를 붙이고 싶어하는 심리가 있다는 거다.

여기서 출발했다. 별자리, MBTI, 오늘의 기분 — 세 가지 중 하나를 고르면, 그 선택에 기반한 번호가 나온다. 같은 별자리라면 항상 같은 번호. 오늘 기분이 달라지면 번호도 달라진다.

그냥 번호 뽑기가 아니라 "나의 기운으로 번호를 소환한다" 는 컨셉.


번호 생성 — 같은 입력이면 항상 같은 번호가 나와야 한다

일반적인 랜덤 함수는 쓸 수 없었다. Math.random()은 호출할 때마다 다른 값이 나오기 때문에, 같은 별자리인데 번호가 매번 바뀌면 "나의 운명 번호"라는 느낌이 사라진다.

그래서 시드 기반 난수(PRNG) 를 직접 구현했다. 선택한 테마 값(aries, INFP, happy 같은 문자열)을 해시해서 시드로 만들고, 그 시드로 항상 동일한 번호 시퀀스를 생성하는 방식이다.

// 문자열을 숫자 시드로 변환
function stringToSeed(str: string): number {
  let hash = 5381;
  for (let i = 0; i < str.length; i++) {
    hash = ((hash << 5) + hash) ^ str.charCodeAt(i);
  }
  return Math.abs(hash) || 1;
}

난수 생성기는 Mulberry32 알고리즘을 썼다. 시드가 같으면 항상 같은 숫자 시퀀스를 만들어준다. 덕분에 양자리는 항상 같은 번호가 나오고, 재시도를 누르면 _retry_1, _retry_2를 시드에 붙여서 다른 번호가 나오도록 했다.


화면 흐름 — 단순 뽑기가 아니라 "의식"으로

8개 화면이 순서대로 이어진다.

인트로 → 테마 선택 → (별자리 / MBTI / 기분) → 소환 → 결과 → 공유

각 화면이 독립적인 컴포넌트다. Game.tsxscreen 상태 하나로 어떤 화면을 보여줄지 결정하고, 각 화면은 선택 결과를 위로 올려보내는 구조.

소환 화면(SummonScreen)이 핵심이었다. 번호가 즉시 나오는 게 아니라, 에너지가 모이는 연출 → 번호볼이 하나씩 등장하는 애니메이션 → 결과 화면으로 전환. 이 흐름이 "뽑기"가 아니라 "소환"처럼 느껴지게 만드는 부분이다.

별자리 선택 화면에서는 12개 별자리를 그리드로 나열하고 각자의 색상 그라디언트를 줬다. 양자리는 빨간 계열, 물병자리는 하늘색 계열 이런 식으로. MBTI는 16개를 4열 그리드로, 기분은 10가지를 이모지와 함께 배치했다.


UI 테마 — 신비로운 분위기를 코드로

게임 전체가 다크 배경에 보라/violet 계열 색상이다. 배경에는 별이 떠있는 StarBackground 컴포넌트가 깔려있다.

별 하나하나가 캔버스에 그려진 랜덤 위치의 원이고, 반짝이는 애니메이션이 붙어있다. 처음엔 CSS로 만들려다가 별 수십 개를 각각 다른 타이밍으로 깜박이게 하려면 캔버스가 훨씬 자연스럽겠다 싶어서 Canvas로 구현했다.

메인 포털 페이지의 게임 카드도 미스틱 로또는 다른 게임과 다르게 보라색 테마로 구분했다. 헤더도 게임 진행 중엔 별자리 느낌의 다크 테마로 바뀐다.


DB 연동 — 로그인하면 기록이 남는다

결과가 나왔을 때 로그인된 사용자라면 DB에 저장된다. 어떤 테마로 어떤 번호를 뽑았는지, 언제 뽑았는지.

허브 페이지(게임 입장 전 소개 페이지)에서 이번 주 기록을 보여준다. 로그인 상태면 DB에서 가져오고, 미로그인이면 localStorage에서 가져온다. 같은 화면인데 인증 상태에 따라 데이터 소스가 달라지는 구조.

중복 저장 방지도 서버에서 처리했다. 5초 안에 같은 번호가 다시 저장 요청이 오면 무시한다. 클라이언트에서 두 번 호출되는 경우를 방어하기 위해서다.


공유 카드

결과 화면 다음에 공유 카드 화면이 있다. 내 번호와 테마, 운세 메시지가 담긴 카드를 이미지처럼 보여주는 화면이다.

처음엔 캡처해서 공유하는 방식을 생각했는데, 결국 카드 디자인을 그냥 화면에 예쁘게 보여주는 수준으로 마무리했다. 스크린샷 찍어서 올리면 된다.


테트리스와 달랐던 점

테트리스는 기능을 하나씩 붙이면서 오래 발전시킨 프로젝트였다. 커밋이 30개 넘게 쌓였다.

미스틱 로또는 반대였다. 처음 설계할 때 전체 구조를 다 잡고 한 번에 만들었다. 화면 흐름, 데이터 구조, 테마 목록, 운세 메시지 전부. 그래서 핵심 기능 구현 커밋이 단 두 개다. 하나는 게임 전체, 하나는 DB 연동.

빠르게 만들 수 있었던 이유는 테트리스를 먼저 만들면서 이 프로젝트의 구조(Next.js App Router, Prisma, Railway 배포 흐름)에 익숙해졌기 때문이다. 같은 실수를 두 번 하지 않았다.


결국 이 프로젝트가 말하는 것

미스틱 로또는 "로또 당첨 번호 예측기"가 아니다. 그냥 재미로 하는 거다.

별자리로 뽑은 번호가 당첨될 리 없다는 걸 다들 안다. 그런데도 "나의 별자리 번호"라는 말에 왠지 모르게 의미를 부여하게 된다. 그 감정이 재밌다고 생각해서 만들었다.

지금 소환해보러 가기 →

🛒 이 글과 관련된 추천 상품

쿠팡 파트너스

ⓘ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.