A roleta já sabe
Por que o vencedor é sorteado antes de a animação começar e o que você ganha com isso.
Pressione Girar e a roleta gira por dez segundos. Parece que o resultado está sendo decidido em algum momento desses dez segundos — na desaceleração, na última meia-volta, em o ponteiro passar ou não por mais uma divisória.
Mas não é assim. O vencedor é sorteado primeiro, em poucos microssegundos, e a animação é então direcionada até ele.
Por que essa ordem
A alternativa óbvia seria girar a roleta e ver onde ela para. Parece mais justo — ninguém escolheu, foi a física —, mas é muito mais difícil de defender, porque transforma qualquer dúvida sobre justiça em uma dúvida sobre a animação.
Você consegue dar um impulso mais forte e mudar o resultado? Clicar no meio do giro para
encurtá-lo altera as chances? O que acontece com quem navega com a opção
prefers-reduced-motion ativada e nunca chega a ver a animação?
Sorteando primeiro, as três perguntas têm a mesma resposta: não, porque o sorteio já aconteceu. O impulso extra adiciona mais voltas. O clique antecipado encurta o percurso. A redução de movimento pula o percurso por completo e anuncia o resultado na hora. Três caminhos diferentes pelo mesmo trecho de código, em vez de três ramificações que precisariam ser justificadas individualmente.
O que faz o sorteio
A entropia vem de crypto.getRandomValues — o próprio gerador criptográfico do
navegador — e nunca de Math.random.
Obter um número uniforme a partir dele exige um passo a mais do que parece
necessário. O cálculo óbvio draw % count é enviesado sempre que count não divide
2³² de forma exata: os primeiros itens ganham uma chance extra a cada quatro bilhões.
É pouco, mas pesa na balança, e uma roleta que se propõe a ser justa não
pode ter isso. Por isso, sorteios que caem nessa sobra são descartados e
outro sorteio é realizado.
const limit = Math.floor(2 ** 32 / max) * max;
let draw = crypto.getRandomValues(new Uint32Array(1))[0];
while (draw >= limit) {
draw = crypto.getRandomValues(new Uint32Array(1))[0];
}
return draw % max;
Isso custa um sorteio extra ocasional e garante um resultado perfeitamente uniforme. O mesmo código está na página de integridade, onde ele é a própria explicação, e não apenas uma ilustração.
Pesos são probabilidades, não favoritismo
Defina o peso de um item como 3 e ele terá três cotas do sorteio em vez de uma. A roleta o exibe como um setor mais largo, e a lista mostra a porcentagem real que esse peso representa, para ninguém ter que fazer contas de cabeça.
Duas entradas com o mesmo texto continuam sendo duas entradas. Cada uma mantém a sua própria chance, e a lista indica quantas repetições encontrou em vez de mesclá-las em silêncio — reduzir as chances de alguém pela metade sem avisar é o tipo de ajuda que ninguém pediu.
Para que serve a animação, afinal
Uma animação direcionada não é uma animação falsa. A roleta realmente se desloca até o setor onde para, os estalidos são sincronizados exatamente com as divisórias que ela ultrapassa e a hesitação de quase-acerto — quando ativada — paira sobre um vizinho do vencedor em vez de um setor aleatório, seguindo em seguida para a entrada sorteada antes de tudo começar.
O suspense é real. O resultado só é decidido antes do que parece.