O jogo nunca cria um quebra-cabeça à mão. Ele faz um crescer a partir de um único número e, em seguida, joga esse quebra-cabeça contra si mesmo para garantir que ele não seja nem trivial nem impossível antes que você o veja.
Escrito e editado em inglês. Esta versão em português foi produzida por tradução automática; quando a precisão importa, o original em inglês é a referência. Ler o original em inglês →
Um nível de Contraption não fica armazenado em lugar nenhum. Não existe um arquivo que liste onde fica o gol ou como as plataformas estão dispostas. Em vez disso, o nível inteiro, o ponto de partida da bola, a posição do gol, o número e a colocação das paredes fixas, o inventário de peças que você recebe, é calculado a partir de um único número inicial chamado seed (semente). Alimente o gerador com o mesmo seed e você obtém, byte por byte, o mesmo quebra-cabeça. 1
Isso é possível porque a única fonte de "aleatoriedade" do gerador é um pequeno gerador determinístico de números pseudoaleatórios. O que Contraption usa é o mulberry32, um gerador compacto de 32 bits criado por Tommy Ettinger, que você reconhece pela sua constante característica, 0x6d2b79f5, somada ao estado a cada sorteio. 2 Ele é rápido, cabe em poucas linhas e, o que é crucial, não é nada aleatório: é uma sequência matemática fixa que apenas parece embaralhada. Dê a ele um ponto de partida e ele produz o mesmo fluxo de números para sempre. O gerador então lê esse fluxo para decidir onde colocar cada coisa.
O modo Daily (o desafio diário) se apoia nesse determinismo para fazer algo social. Seu seed não é aleatório, ele é fabricado a partir do calendário. O jogo pega a data de hoje em tempo universal, escreve-a em uma string curta como "contraption:2026-7-28" e passa esse texto por uma função de hash para reduzi-lo a um único número de 32 bits. 1
O hash é o FNV-1a, um misturador não criptográfico bem conhecido: ele parte de um deslocamento fixo, o decimal 2166136261, ou 0x811c9dc5, e, para cada caractere, incorpora a letra com um ou-exclusivo e depois multiplica pelo primo FNV 16777619. 3 Isso deixa um número que é estável para um dado dia e radicalmente diferente de um dia para o outro, de modo que a mudança de um único caractere na data espalha o seed por completo. Como o calendário é o mesmo para todos, o seed também é, e o quebra-cabeça também. Dois desconhecidos em lados opostos do mundo abrem o Daily e encontram o campo idêntico, que é exatamente o que torna significativa a comparação de uma pontuação.
O desafio diário é justo não porque um servidor envia o mesmo nível a todos, mas porque a cópia de cada pessoa recalcula, de forma independente, o mesmo nível a partir da mesma data.
Geometria aleatória é fácil; boa geometria aleatória não é. Um gerador que simplesmente espalha um gol e algumas plataformas às vezes produzirá um nível em que a bola, solta do topo, cai direto no gol por conta própria. Isso não é um quebra-cabeça, é uma cena de transição. Então, antes de Contraption aceitar um mundo candidato, ele executa um teste discreto que o código chama de preSolved: ele simula o nível com zero peças colocadas e verifica se a bola, sozinha, chega ao gol só pela gravidade. Se chegar, o nível é descartado e o gerador sorteia de novo. 1
Essa é uma inversão sutil da maneira como você normalmente pensa em um motor de física. A mesma função simulate() que executa a sua máquina está sendo voltada para dentro, no momento da geração, para auditar a dificuldade do próprio nível. O motor é ao mesmo tempo o árbitro da sua solução e o inspetor de qualidade do quebra-cabeça.
Rejeitar o nível fácil demais é só metade do trabalho. O outro perigo é o nível impossível, um gol escondido em algum lugar que nenhum arranjo de peças consegue alcançar. Contraption se protege disso com um pequeno solucionador de força bruta chamado plausiblySolvable. Ele não pensa com esperteza. Ele apenas tenta. 1
Especificamente, ele varre uma única rampa por uma grade de posições sobre o campo e, em cada ponto, experimenta-a inclinada de quatro maneiras diferentes. Para cada uma dessas colocações de teste, ele executa a simulação completa e pergunta: essa única rampa levou a bola para casa? No momento em que qualquer colocação dá certo, o nível é declarado solucionável e entregue a você. Se nenhuma delas funcionar depois da varredura inteira, o gerador prefere descartar o nível e tentar um seed novo.
| Parâmetro de varredura | Intervalo | Significado |
|---|---|---|
| Rampa X | 15 → 85, passo 14 | colunas ao longo do campo |
| Rampa Y | 30 → 120, passo 18 | linhas descendo o campo |
| Ângulos experimentados | 4 | ±0.45 e ±0.8 radianos |
| Teste por colocação | 1 simulação completa | a bola chega ao gol? |
Vale a pena ser honesto sobre o que isso prova, porque o código também é honesto a esse respeito: o comentário o chama de "verificação barata de plausibilidade … não exaustiva". Um nível que passa tem, com certeza, pelo menos uma solução rudimentar com uma única rampa. Um nível que falha ainda pode ter solução com um ventilador, uma engrenagem ou uma rampa mais engenhosa que a grade nunca experimentou, então o gerador não trata a falha como prova de impossibilidade. Ele guarda o primeiro mundo não trivial que encontrou como reserva e, se quarenta tentativas se passarem sem uma solução limpa de uma só peça, entrega essa reserva em vez de ficar em loop para sempre. O resultado é uma garantia pragmática: nunca uma vitória de graça, quase sempre um caminho genuíno para dentro e nunca uma espera infinita pelo nível "perfeito". 1
Dê um passo atrás e o criador de níveis de Contraption é um exemplo límpido de um padrão de resolução de problemas muito antigo e muito geral: gerar e testar. Proponha um candidato ao acaso; confira-o em relação aos seus requisitos; mantenha-o se passar, descarte-o e proponha outro se falhar. É o laço por trás do conteúdo procedural de incontáveis jogos, por trás de boa parte da computação evolutiva e, com um pouco de boa vontade, por trás da própria seleção natural: a mutação propõe, o ambiente testa, os sobreviventes persistem. 4
O que torna a versão de Contraption elegante é que o teste não é um substituto barato para a jogabilidade, ele é a jogabilidade. O gerador não estima se um nível é justo contando plataformas ou medindo distâncias. Ele literalmente joga o nível, duas vezes: uma vez vazio, para garantir que não é um presente, e uma vez com uma rampa de sondagem, para garantir que existe um caminho. A mesma física determinística que vai julgar a sua solução é a física que avaliou o quebra-cabeça. Não existe um "validador de níveis" separado que pudesse sair de sincronia com as regras reais, porque só existe um conjunto de regras, usado para tudo.
E como tudo é determinístico, a auditoria está livre de sorte nas duas direções. O seed diário não pode conspirar para entregar a um jogador um campo mais fácil do que a outro, e não pode entregar a ninguém um campo injusto, porque, antes de o nível ser um desafio, ele já sobreviveu a ser jogado, pelo jogo, contra si mesmo.