ToolActToolAct

랜덤 선택 도구

추첨, 선택, 뽑기를 위한 공정한 랜덤 선택 도구

추첨 설정
중복 허용
활성화하면 같은 항목이 여러 번 선택될 수 있습니다
총 항목 수: 0
당첨됨: 0
남은 항목: 0
?

랜덤 추첨이란?

랜덤 선택기는 사람이 직접 고르지 않고 후보 목록에서 하나를 무작위로 선택하는 도구입니다. 수업 지명, 회의 발표 순서, 가벼운 추첨, 업무 배정, 점심 메뉴 선택, 팀 워밍업처럼 중립적인 선택 방식이 필요한 상황에 유용합니다. 이 페이지는 한 줄에 하나씩 입력한 후보 목록, 추첨 애니메이션, 로컬 추첨 기록, 중복 없는 선택을 지원하며 선택된 항목을 남은 목록에서 제거할 수 있습니다. 무작위성은 통계적으로 편향을 줄이는 데 도움이 되지만, 신원 확인, 입력 안의 중복 이름 검출, 감사 증거 제공을 대신하지 않습니다. 공식 추첨, 자격 확인, 상품 지급에는 기록과 규칙이 있는 별도 절차를 사용해야 합니다.

사용 방법

조작 단계

  1. 텍스트 상자에 옵션을 한 줄에 하나씩 입력하세요
  2. 선택할 항목 수를 설정하세요
  3. 중복 허용 여부를 선택하세요
  4. '추첨 시작' 버튼을 클릭하세요
  5. 오른쪽에서 결과를 확인하세요

공정한 추첨 팁

  • 한 줄에 후보 하나씩 입력하고, 중복이 의도적으로 허용되지 않는 경우 실수로 들어간 빈 줄이나 중복을 제거하세요.
  • 공개 추첨의 경우, 시작하기 전에 시드, 중복 규칙, 재추첨 규칙을 정해 두면 결과를 더 쉽게 설명할 수 있습니다.

활용 사례

붙여넣은 목록에서 이름 또는 항목 추첨한 줄에 하나씩 항목을 입력하고 브라우저 암호화 난수를 사용하는 롤링 추첨 애니메이션을 시작합니다. 가장 최근에 뽑힌 항목이 크게 표시되고, 모든 추첨 항목이 순서대로 기록됩니다. 각 추첨은 정수 범위 [0, n)에서 crypto.getRandomValues()를 호출하므로 남은 모든 이름의 선택 확률은 정확히 1/n이며, 선택된 인덱스는 애니메이션 시작 전에 고정됩니다.
중복 허용/비허용 선택 실행항목을 여러 번 선택할 수 있는지 토글합니다. 중복 비허용 모드에서는 추첨된 항목이 사용 가능한 풀에서 제거되고 남은 개수가 표시되어 추첨, 수업 순번, 잡일, 팀 배정에 유용합니다. 두 모드는 서로 다른 공정성 속성을 갖습니다: 중복 비허용은 커버리지를 보장하고, 중복 허용은 매번 동일한 확률을 유지하여 같은 이름이 연속으로 뽑힐 수도 있습니다. 참가자에게 발표한 규칙에 맞는 모드를 선택하세요.
새로고침 간 선택기 상태 유지입력 목록과 추첨 기록은 localStorage에 저장되어 실수로 새로고침해도 세션이 유지됩니다. 결과는 순서 목록으로 복사하거나 원본 목록과 별도로 지울 수 있습니다. 새 라운드를 시작할 때 전용 '기록 지우기' 버튼으로 후보 목록은 유지한 채 기록만 삭제할 수 있습니다. 두 데이터는 서로 다른 키에 저장되어 하나를 지워도 다른 하나에 영향을 주지 않습니다.
카운터로 순서 있는 수업 진행중복 비허용 모드로 전환하고 추첨 기록을 확인하여 어떤 학생이 이미 답변했는지 파악하면, 다음 추첨은 항상 아직 말하지 않은 사람에게 돌아갑니다. 결과 아래의 남은 개수 표시로 라운드가 거의 끝나가는 시점을 파악할 수 있어 교사가 마지막 몇 문제의 속도를 조절할 수 있습니다. 반복이 허용되는 워밍업 빠른 선택 드릴에는 중복 허용 모드로 초기화하세요.
소규모 추첨을 위한 감사 가능한 당첨자 목록 내보내기추첨 기록을 순서 목록으로 복사하면 소규모 팀 경품 행사에 모든 선택의 타임스탬프 기록이 남습니다. 원본 목록, 추첨 규칙, 추첨 화면 스크린샷을 추가하세요. localStorage는 브라우저와 기기별이므로 내구성 있는 기록 시스템이 아닙니다. 유료 추첨, 규제 대상 추첨, 컴플라이언스가 중요한 행사는 브라우저 페이지 단독이 아닌 감사와 증인을 위한 시스템에서 추첨을 진행하세요.

기술 원리

랜덤 선택기는 Web Crypto API(W3C, WHATWG), 특히 crypto.getRandomValues(typedArray)를 기반으로 하며, 이는 브라우저에서 제공되는 유일한 암호학적 보안 난수 소스입니다. 내부적으로 브라우저는 운영 체제의 CSPRNG를 호출합니다. Windows에서는 CryptGenRandom(Windows 10 이후 AES-256 CTR-DRBG 모드), Linux에서는 getrandom(2)(커널의 /dev/urandom과 동일한 ChaCha20 기반 풀에서 읽음), macOS에서는 SecRandomCopyBytes, iOS, Android, BSD에서도 동등한 함수를 사용합니다. 이 출력은 키 생성, 논스, 솔트, IV, 그리고 예측 가능성이 보안 문제를 일으키는 모든 곳에 적합합니다. '암호학적 등급'의 구분이 중요합니다. V8의 Math.random()은 xorshift128+를 사용하며(빠르지만 엔트로피가 낮은 알고리즘), [0, 1) 범위의 64비트 부동소수점을 반환합니다. 적대적 행위자가 출력을 몇 번 관찰하면 원칙적으로 128비트 상태를 재구성하여 향후 모든 값을 예측할 수 있습니다. SpiderMonkey와 JavaScriptCore도 마찬가지입니다. 따라서 Math.random()은 결과가 추측 불가능해야 하는 모든 용도에 부적합합니다. 공정한 당첨자 선택, 토큰, 일회용 비밀번호, 카드 게임의 거래, 감사 샘플 등이 이에 해당합니다. crypto.getRandomValues(typedArray)만이 이러한 경우에 적합합니다. 균일한 32비트 정수를 [0, N) 범위의 균일한 인덱스로 변환할 때 모듈로 바이어스를 제거하는 것이 올바른 구현과 잘못된 구현을 가르는 두 번째 공학적 세부사항입니다. 단순히 idx = randomUint32 % N을 사용하면 잘못됩니다. N이 2^32로 나누어떨어지지 않으면 처음 2^32 mod N개의 값이 약간 더 높은 확률을 갖게 됩니다. 올바른 알고리즘은 리젝션 샘플링입니다. limit = 2^32 - (2^32 mod N)을 계산하고, 32비트 값 r을 추출하며, r >= limit이면 다시 추출하고, 그렇지 않으면 r % N을 반환합니다. 바이어스는 O(N / 2^32)에서 0으로 줄어듭니다. N = 2이거나 N이 2의 거듭제곱이면 모듈로가 정확하지만, 리젝션 샘플링이 안전한 기본값이며 평균 최대 한 번의 재추출만 발생합니다(항상 종료됨). 선택기는 결과를 버전화된 키로 localStorage에 저장하므로 세션이 페이지 새로고침을 견딜 수 있고 사용자가 추첨 기록을 확인할 수 있습니다. 기록은 암호화되거나 서명되지 않습니다. 로컬이고 민감하지 않으며 쉽게 지울 수 있습니다. 중복 없는 모드에서는 Fisher-Yates 부분 셔플을 사용하여 복원 없이 추출합니다. N개 중 k번째 단계에서 요소 k를 [k, N) 범위에서 균일하게 선택된 요소와 교환하고, 요소 k를 추출된 것으로 고정합니다. 이는 O(N) 시간, O(1) 추가 공간이며 모든 순열에 동일한 확률을 부여하는 올바른 조합론적 보장을 제공합니다.('N번 추출하고 반복을 거부하는' 단순한 방법도 정확하지만 O(N^2)이며 긴 세션에서 지연될 수 있습니다.) 가중치 선택(각 옵션에 고유한 확률이 있는 경우)의 표준 알고리즘은 접두사 합 배열을 사용하는 역CDF 샘플링입니다. 가중치의 접두사 합을 구축하고, [0, total) 범위의 균일 실수를 추출한 뒤, prefix[i] >= u인 가장 작은 i를 이진 탐색합니다. 추출당 O(log N)이며 접두사 합은 변경당 한 번만 구축됩니다. Alias 방법(Walker-Vose)은 O(N) 설정 비용으로 추출당 O(1)을 제공하며, N이 크고 분포가 고정된 경우에만 가치가 있습니다.

  • 난수 소스: crypto.getRandomValues(typedArray) — 브라우저에서 유일한 암호학적 보안 RNG로, OS 수준 CSPRNG(Windows 10+의 AES-256 CTR-DRBG, Linux/macOS/iOS/Android의 ChaCha20)로 지원됨
  • Math.random()은 V8에서 xorshift128+(다른 엔진에서는 변형): 빠르지만 예측 가능. 공정한 선택, 토큰, OTP, 감사 샘플에는 절대 사용하지 말 것. 시각적 노이즈, 애니메이션, 비보안 샘플링에만 사용
  • 편향 없는 인덱스 매핑: 모듈로가 아닌 리젝션 샘플링. limit = 2^32 - (2^32 mod N) 계산; 난수 uint32 >= limit이면 재추출, 그렇지 않으면 r % N 반환. 짧은 범위 인덱스가 더 자주 나타나는 '모듈로 바이어스' 방지
  • 중복 없는 추출은 O(N) 시간, O(1) 공간의 Fisher-Yates 부분 셔플 사용: k단계에서 요소 k를 [k, N)의 균일 요소와 교환 후 k 고정. 모든 순열이 동일한 확률을 가짐
  • 가중치 선택은 역CDF 샘플링 사용: 가중치의 접두사 합을 한 번 구축하고, [0, total) 범위의 균일 실수를 추출한 뒤, 가장 작은 prefix[i] >= u를 이진 탐색. 추출당 O(log N)
  • 추첨 기록은 버전화된 키로 localStorage에 저장되어 페이지 새로고침 후에도 세션 유지. 기록은 로컬 전용이며 보안 민감 사항이 아님 — 완료 후 UI에서 삭제
  • Fisher-Yates vs '반복 거부하며 N번 추출': 분포상 모두 정확하지만, Fisher-Yates는 총 O(N), 메모리 O(1)이고 단순 거부는 최악의 경우 O(N^2)(긴 목록 끝에서 반복이 많을 때)
  • 출력 범위 및 타입: getRandomValues는 Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, BigInt64Array, BigUint64Array를 허용 — 이 페이지는 항상 Uint32Array를 사용하여 인덱스 매핑 단계에 전달

예시

후보 목록에서 중복 없이 추첨

입력 목록 (한 줄에 하나):
  Alice
  Bob
  Charlie
  David
  Eve
  Frank

중복 허용: OFF    추첨 수: 3
결과:
  #1: Charlie
  #2: Alice
  #3: Frank
  (Bob, David, Eve는 풀에 남아 있음)

페이지는 Uint32Array에 crypto.getRandomValues()를 호출해 매 추첨마다
남은 후보 수 n에 대해 [0, n) 범위의 균일한 정수를 생성합니다. 각
이름은 매 추첨에서 동일한 1/n 확률을 가지며, 선택된 인덱스는
애니메이션이 시작되기 전에 이미 정해집니다.

중복 허용 추첨과 타임스탬프 기록

입력 목록 (한 줄에 하나):
  Head
  Tails

중복 허용: ON    추첨 수: 5
결과:
  #1 (14:23:01): Head
  #2 (14:23:01): Tails
  #3 (14:23:01): Head
  #4 (14:23:01): Head
  #5 (14:23:01): Tails

중복 모드에서는 같은 항목이 연속으로 뽑힐 수 있고, 풀이 줄어들지
않습니다. 각 기록에 추첨 타임스탬프가 추가되어 동일한 후보 목록을
여러 라운드에 걸쳐 재사용하면서도 각 추첨이 정확히 언제 일어났는지
확인할 수 있습니다. 기록은 후보 목록과 별도로 삭제하세요 - 서로
다른 localStorage 키에 저장됩니다.

선택 로직의 JavaScript 스니펫

// Web Crypto (CSPRNG)로 [0, n)에서 인덱스 하나 선택
function pickIndex(n) {
  // crypto.getRandomValues는 균일한 32비트 값을 제공합니다. 목록 추첨에서
  // n은 최대 수천 개 정도이므로 모듈로 n 연산은 안전하며, 모듈로 편향은
  // 무시할 수 있을 정도로 작습니다 (2^32 / n이 큰 값이기 때문).
  const buf = new Uint32Array(1);
  crypto.getRandomValues(buf);
  return buf[0] % n;
}

// pickIndex(6) -> 예: 4   (위 예시의 Charlie)
// pickIndex(2) -> 0 또는 1   (Head 또는 Tails)
//
// 참고: n이 2^32에 가까운 거대한 풀에서는 모듈로 편향을 제거하기 위해
// 거부 샘플링(rejection sampling)을 사용하세요. 예:
//   const limit = Math.floor(0xFFFFFFFF / n) * n;
//   let r; do { crypto.getRandomValues(buf); r = buf[0]; } while (r >= limit);

1,000회 추첨에 대한 공정성 검증

목록:     ['A', 'B', 'C', 'D']    (4개 항목, 기대 비율 25.0%)
추첨 수:  1,000    중복 허용: ON
관측치:
  A: 247    (24.7%)
  B: 256    (25.6%)
  C: 248    (24.8%)
  D: 249    (24.9%)

crypto.getRandomValues로 1,000회 추첨하면 각 항목의 기대 비율에서
약 ±3 퍼센트 포인트 이내로 떨어져야 합니다. 더 큰 편차(예: 한 항목이
35%)는 보통 구현에서 Math.random()을 호출했거나 모듈로 연산을 잘못
적용했다는 신호입니다. 규제가 적용되는 추첨이라면 원본 목록, 난수
시드 출처(브라우저/OS 엔트로피), 추첨 타임스탬프, 입회 서명을
저장하세요 - localStorage는 영구적인 기록 시스템이 아닙니다.

자주 묻는 질문

정말 무작위로 선택되나요?

네. 선택에는 Web Crypto API의 crypto.getRandomValues를 사용하며, 이는 암호학적으로 안전한 난수입니다. 가중치를 따로 설정하지 않으면 모든 옵션은 동일한 확률로 선택됩니다.

같은 옵션이 연속으로 두 번 뽑힐 수 있나요?

네, 독립적인 무작위 선택의 본질이 그렇습니다. 옵션이 5개라면 같은 항목이 연속으로 뽑힐 확률은 1/5 = 20%입니다. 중복을 원하지 않는다면 '뽑은 후 제거' 옵션을 켜세요. 그러면 비복원 추출 방식으로 목록이 빌 때까지 진행됩니다.

'N개 항목 뽑기'는 어떻게 처리되나요?

기본적으로 비복원 추출이라 한 번 N개를 뽑을 때 같은 항목이 두 번 선택되지 않습니다. 중복을 허용하고 싶다면(예: 한 사람에게 N개 작업 배정) '복원 추출'로 전환하세요. 비복원 모드에서는 N이 옵션 개수를 초과할 수 없습니다.

선택 확률에 가중치를 줄 수 있나요?

일부 빌드는 옵션별 가중치를 지원합니다(예: A 가중치 3, B 가중치 1이면 A가 3배 더 잘 뽑힘). 페이지가 가중치를 확률로 정규화합니다. 가중치를 두지 않으면 모든 옵션이 동일한 확률을 가집니다.

직감으로 고르는 것보다 왜 더 공정한가요?

사람은 무작위에 약합니다. 최근에 뽑은 항목을 피하려 하고, 눈에 띄는 옵션을 과도하게 고르며, 자기도 모르게 익숙한 이름에 끌립니다. 컴퓨터가 뽑으면 이런 편향이 사라져 추첨류 결정이 참가자에게 더 깔끔하게 느껴집니다.

입력한 목록이 저장되나요?

일부 빌드는 같은 브라우저에서 목록이 유지되도록 localStorage에 저장합니다. 탭을 닫거나 다른 브라우저로 바꾸면 내보내기 하지 않은 한 사라집니다. 서버로 업로드되는 정보는 없습니다.

법적 효력이 있는 추첨에 사용해도 되나요?

안 됩니다. 법적 추첨, 복권, 도박 추첨은 감사 가능한 무작위 절차가 필요하며 보통 물리적 장치나 인증된 RNG 하드웨어를 사용합니다. 일반 웹 도구는 문서화·감사가 되어 있지 않으니, 사내 추첨이나 비공식 뽑기에만 사용하세요.