생성기의 목표를 먼저 제한합니다
번호 생성기의 목표는 미래 번호를 알아내는 것이 아니라 사용자가 정한 조건 안에서 1~45 중 서로 다른 6개를 무작위로 선택하는 것입니다. 과거 빈도, 꿈, 생일, AI 점수는 다음 독립 추첨의 정답을 제공하지 않습니다. 따라서 감사할 대상은 예측 정확도가 아니라 범위, 중복, 분포 편향, 실패 처리입니다.
BALLPICK의 기본 난수 함수는 브라우저의 crypto.getRandomValues로 32비트 부호 없는 정수를 얻습니다. Math.random에 사이트 고유의 예측 의미를 붙이지 않고, 운영체제와 브라우저가 제공하는 난수원에 선택을 맡깁니다.
나머지 연산 편향을 거절 표본추출로 피합니다
32비트 정수의 가능한 값 수 4,294,967,296은 45로 정확히 나누어떨어지지 않습니다. 모든 값을 단순히 45로 나눈 나머지로 바꾸면 일부 나머지가 한 번 더 나타나는 아주 작은 편향이 생깁니다. 이를 피하기 위해 45의 배수인 가장 큰 경계값 이상은 버리고 새 난수를 받습니다.
| 단계 | 처리 | 감사 질문 |
|---|---|---|
| 1 | 0 이상 2³² 미만 정수 생성 | crypto.getRandomValues를 쓰는가? |
| 2 | 2³² - (2³² mod 범위) 계산 | 범위의 정확한 배수인가? |
| 3 | 경계 이상 값 거절 | 버린 뒤 새 값을 받는가? |
| 4 | 범위로 나눈 나머지 사용 | 결과가 0~범위-1인가? |
거절될 확률은 매우 작지만 코드에 이 단계가 있으면 45뿐 아니라 다른 크기의 후보 배열에도 같은 원칙을 적용할 수 있습니다.
Fisher–Yates 셔플로 중복 없이 고릅니다
1부터 45까지 배열을 만든 뒤 뒤에서 앞으로 이동하며 현재 위치와 0부터 현재 위치 사이의 무작위 위치를 바꿉니다. 올바른 Fisher–Yates 셔플은 각 순열을 같은 확률로 만들도록 설계됩니다. 셔플한 배열의 앞 6개를 고르면 중복 검사를 반복하는 방식보다 구조가 명확합니다.
- 원본 후보 배열을 복사해 사용자 설정을 훼손하지 않습니다.
- 마지막 인덱스부터 1까지 한 번씩 이동합니다.
- 교환 위치는 현재 인덱스를 포함한 균등 범위에서 고릅니다.
- 결과 6개를 화면 표시용으로 정렬해도 선택된 집합은 바뀌지 않습니다.
- 포함·제외 번호가 있으면 셔플 전에 후보집합과 필요한 개수를 검증합니다.
필터는 후보 공간을 줄일 뿐입니다
홀짝, 합계, 연속번호, 포함·제외 조건을 걸면 허용되는 조합 수가 줄어듭니다. 이때 생성기는 허용 공간 안에서 조합을 찾지만, 필터를 통과한 한 장이 추첨기에서 더 자주 뽑히는 것은 아닙니다. 사용자가 보기 싫은 모양을 제외하는 취향 설정과 확률 우위를 구분해야 합니다.
| 조건 오류 | 안전한 처리 | 피해야 할 처리 |
| 포함번호가 7개 | 즉시 입력 오류 표시 | 임의로 하나 삭제 |
| 포함·제외가 겹침 | 충돌 항목 표시 | 조용히 한쪽 우선 |
| 후보가 6개 미만 | 생성 중단 | 중복 번호 허용 |
| 필터 조합이 불가능 | 조건 완화 안내 | 무한 재시도 |
재시도 상한을 두지 않으면 지나치게 좁은 조건에서 화면이 멈출 수 있습니다. 상한에 도달하면 기본 조합을 몰래 반환하지 말고 어떤 조건을 완화해야 하는지 알려야 합니다.
단위 테스트와 분포 테스트를 구분합니다
단위 테스트는 난수 인덱스가 요청 범위 안에 있는지, 셔플 뒤 원소가 사라지거나 중복되지 않는지, 잘못된 범위가 오류를 내는지 확인합니다. 이 검사는 매 빌드에서 결정적으로 실행할 수 있습니다.
분포 테스트는 충분히 많은 표본에서 각 번호와 위치의 빈도가 지나치게 치우치지 않는지 관찰합니다. 그러나 무작위 표본은 원래 흔들리므로 한 번의 테스트에서 1/45와 정확히 같아야 한다고 요구하면 정상 코드도 실패합니다. 허용오차와 표본 수를 사전에 정하고 반복 결과를 봅니다.
사용자가 직접 할 수 있는 감사
- 조건을 모두 끄고 1,000회 생성해 모든 결과가 1~45의 서로 다른 6개인지 확인합니다.
- 특정 번호를 포함·제외했을 때 규칙 위반이 한 번이라도 있는지 검사합니다.
- 같은 조합이 다시 나오는 것을 버그로 단정하지 않습니다. 무작위 추출에서도 반복은 가능합니다.
- 개발자 도구에서 crypto.getRandomValues를 사용할 수 없는 환경의 실패 메시지를 확인합니다.
- 코드 버전과 테스트 실행일을 기록해 알고리즘 변경 전후를 비교합니다.
결과를 재현하지 못하는 것이 정상인 부분도 있습니다
보안 난수는 같은 버튼을 눌렀을 때 같은 결과를 만들기 위한 시드 기능이 아닙니다. 테스트에서 특정 번호 조합을 고정해야 한다면 난수 함수를 테스트용 의존성으로 교체하고 운영 코드의 난수원은 그대로 둡니다. 운영 화면에 숨은 고정 시드를 넣으면 사용자가 보는 분포와 테스트가 달라질 수 있습니다.
생성 결과를 서버에 개인별 예측 이력으로 저장하지 않는지도 개인정보 관점에서 확인합니다. 공유 기능을 사용할 때만 사용자가 선택한 내용을 명시적으로 전달하고, 기본 생성 버튼은 계정이나 연락처와 결합하지 않는 것이 원칙입니다.
암호학적 난수라는 말은 해킹이 불가능하거나 복권 추첨과 연결된다는 뜻이 아닙니다. 브라우저 안에서 후보를 공정하게 섞기 위한 구현 선택이며, 실제 당첨 판정은 동행복권의 공식 추첨 결과만 따릅니다.