Sobre a série
Primeiro, você pode tratar isso como qualquer outro desafio de código de golfe e respondê-lo sem se preocupar com a série. No entanto, existe uma tabela de classificação em todos os desafios. Você pode encontrar a tabela de classificação junto com mais informações sobre a série no primeiro post .
Embora eu tenha várias idéias alinhadas para a série, os desafios futuros ainda não estão definidos. Se você tiver alguma sugestão, informe-me na postagem da sandbox relevante .
Buraco 6: Rolar um d20
Um dado muito comum nos RPGs de mesa é o dado de vinte lados (um icosaedro , conhecido como d20 ). É sua tarefa rolar tal dado. No entanto, se você estivesse retornando um número aleatório entre 1 e 20, isso seria um pouco trivial. Portanto, sua tarefa é gerar uma rede aleatória para um dado dado.
Usaremos a seguinte rede:
É uma faixa triangular, portanto pode ser facilmente representada como uma lista de números inteiros. Por exemplo, se você receber a entrada:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
Isso corresponderia ao seguinte dado (fato interessante: essa é a rede usada pelo Magic: the Gathering life counters / spin-down data).
No entanto, essa não é a única rede que representa esse dado. Dependendo de como desenrolamos os rostos, existem 60 redes diferentes. Aqui estão mais dois:
[1, 8, 9, 10, 2, 3, 4, 5, 6, 7, 17, 18, 19, 11, 12, 13, 14, 15, 16, 20]
[10, 9, 18, 19, 11, 12, 3, 2, 1, 8, 7, 17, 16, 20, 13, 14, 4, 5, 6, 15]
Ou graficamente (não girei os rótulos dos rostos por simplicidade):
O desafio
Dada uma lista de números inteiros representando um dado (como descrito acima) e um número inteiro N
, produz N
independentemente, redes d20 uniformemente aleatórias correspondentes ao dado dado. (Ou seja, cada uma das 60 redes possíveis deve ter a mesma probabilidade de ser gerada.)
Obviamente, devido às limitações técnicas dos PRNGs, a uniformidade perfeita será impossível. Com o objetivo de avaliar a uniformidade de seu envio, as seguintes operações serão consideradas como produzindo distribuições perfeitamente uniformes:
- Obtenção de um número de um PRNG (acima de qualquer intervalo), que está documentado para ser (aproximadamente) uniforme.
- Mapear uma distribuição uniforme sobre um conjunto maior de números para um conjunto menor via módulo ou multiplicação (ou alguma outra operação que distribua valores uniformemente). O conjunto maior deve conter pelo menos 1024 vezes o maior número possível de valores que o conjunto menor.
Dadas essas suposições, seu algoritmo deve produzir uma distribuição perfeitamente uniforme.
Seu programa deve ser capaz de gerar 100 redes em menos de um segundo (portanto, não tente gerar redes aleatórias até que uma corresponda ao dado dado acima).
Você pode escrever um programa ou função, recebendo entrada via STDIN (ou alternativa mais próxima), argumento da linha de comando ou argumento da função e emitindo o resultado via STDOUT (ou alternativa mais próxima), valor de retorno da função ou parâmetro da função (saída).
A entrada e a saída podem estar em qualquer formato de lista simples, conveniente e inequívoco. Você pode supor que os valores de face do d20 são números inteiros positivos e distintos, que se encaixam no tipo inteiro natural do seu idioma.
Isso é código de golfe, então a submissão mais curta (em bytes) vence. E, é claro, o menor envio por usuário também entrará na tabela geral de líderes da série.
Saídas de amostra
Para a entrada
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
As 60 redes possíveis (desde que eu não tenha cometido um erro), em nenhuma ordem específica, são:
[11, 10, 9, 18, 19, 20, 13, 12, 3, 2, 1, 8, 7, 17, 16, 15, 14, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
[8, 7, 17, 18, 9, 10, 2, 1, 5, 6, 15, 16, 20, 19, 11, 12, 3, 4, 14, 13]
[3, 12, 13, 14, 4, 5, 1, 2, 10, 11, 19, 20, 16, 15, 6, 7, 8, 9, 18, 17]
[3, 4, 5, 1, 2, 10, 11, 12, 13, 14, 15, 6, 7, 8, 9, 18, 19, 20, 16, 17]
[11, 19, 20, 13, 12, 3, 2, 10, 9, 18, 17, 16, 15, 14, 4, 5, 1, 8, 7, 6]
[4, 14, 15, 6, 5, 1, 2, 3, 12, 13, 20, 16, 17, 7, 8, 9, 10, 11, 19, 18]
[2, 10, 11, 12, 3, 4, 5, 1, 8, 9, 18, 19, 20, 13, 14, 15, 6, 7, 17, 16]
[4, 5, 1, 2, 3, 12, 13, 14, 15, 6, 7, 8, 9, 10, 11, 19, 20, 16, 17, 18]
[10, 2, 1, 8, 9, 18, 19, 11, 12, 3, 4, 5, 6, 7, 17, 16, 20, 13, 14, 15]
[3, 2, 10, 11, 12, 13, 14, 4, 5, 1, 8, 9, 18, 19, 20, 16, 15, 6, 7, 17]
[7, 8, 1, 5, 6, 15, 16, 17, 18, 9, 10, 2, 3, 4, 14, 13, 20, 19, 11, 12]
[13, 12, 11, 19, 20, 16, 15, 14, 4, 3, 2, 10, 9, 18, 17, 7, 6, 5, 1, 8]
[16, 15, 14, 13, 20, 19, 18, 17, 7, 6, 5, 4, 3, 12, 11, 10, 9, 8, 1, 2]
[15, 16, 17, 7, 6, 5, 4, 14, 13, 20, 19, 18, 9, 8, 1, 2, 3, 12, 11, 10]
[20, 13, 12, 11, 19, 18, 17, 16, 15, 14, 4, 3, 2, 10, 9, 8, 7, 6, 5, 1]
[5, 4, 14, 15, 6, 7, 8, 1, 2, 3, 12, 13, 20, 16, 17, 18, 9, 10, 11, 19]
[10, 11, 12, 3, 2, 1, 8, 9, 18, 19, 20, 13, 14, 4, 5, 6, 7, 17, 16, 15]
[4, 3, 12, 13, 14, 15, 6, 5, 1, 2, 10, 11, 19, 20, 16, 17, 7, 8, 9, 18]
[19, 20, 13, 12, 11, 10, 9, 18, 17, 16, 15, 14, 4, 3, 2, 1, 8, 7, 6, 5]
[1, 8, 9, 10, 2, 3, 4, 5, 6, 7, 17, 18, 19, 11, 12, 13, 14, 15, 16, 20]
[8, 1, 5, 6, 7, 17, 18, 9, 10, 2, 3, 4, 14, 15, 16, 20, 19, 11, 12, 13]
[18, 9, 8, 7, 17, 16, 20, 19, 11, 10, 2, 1, 5, 6, 15, 14, 13, 12, 3, 4]
[12, 3, 2, 10, 11, 19, 20, 13, 14, 4, 5, 1, 8, 9, 18, 17, 16, 15, 6, 7]
[2, 3, 4, 5, 1, 8, 9, 10, 11, 12, 13, 14, 15, 6, 7, 17, 18, 19, 20, 16]
[10, 9, 18, 19, 11, 12, 3, 2, 1, 8, 7, 17, 16, 20, 13, 14, 4, 5, 6, 15]
[9, 8, 7, 17, 18, 19, 11, 10, 2, 1, 5, 6, 15, 16, 20, 13, 12, 3, 4, 14]
[16, 17, 7, 6, 15, 14, 13, 20, 19, 18, 9, 8, 1, 5, 4, 3, 12, 11, 10, 2]
[17, 7, 6, 15, 16, 20, 19, 18, 9, 8, 1, 5, 4, 14, 13, 12, 11, 10, 2, 3]
[1, 5, 6, 7, 8, 9, 10, 2, 3, 4, 14, 15, 16, 17, 18, 19, 11, 12, 13, 20]
[9, 18, 19, 11, 10, 2, 1, 8, 7, 17, 16, 20, 13, 12, 3, 4, 5, 6, 15, 14]
[16, 20, 19, 18, 17, 7, 6, 15, 14, 13, 12, 11, 10, 9, 8, 1, 5, 4, 3, 2]
[5, 1, 2, 3, 4, 14, 15, 6, 7, 8, 9, 10, 11, 12, 13, 20, 16, 17, 18, 19]
[8, 9, 10, 2, 1, 5, 6, 7, 17, 18, 19, 11, 12, 3, 4, 14, 15, 16, 20, 13]
[13, 20, 16, 15, 14, 4, 3, 12, 11, 19, 18, 17, 7, 6, 5, 1, 2, 10, 9, 8]
[6, 15, 16, 17, 7, 8, 1, 5, 4, 14, 13, 20, 19, 18, 9, 10, 2, 3, 12, 11]
[6, 5, 4, 14, 15, 16, 17, 7, 8, 1, 2, 3, 12, 13, 20, 19, 18, 9, 10, 11]
[7, 6, 15, 16, 17, 18, 9, 8, 1, 5, 4, 14, 13, 20, 19, 11, 10, 2, 3, 12]
[19, 18, 17, 16, 20, 13, 12, 11, 10, 9, 8, 7, 6, 15, 14, 4, 3, 2, 1, 5]
[14, 15, 6, 5, 4, 3, 12, 13, 20, 16, 17, 7, 8, 1, 2, 10, 11, 19, 18, 9]
[17, 18, 9, 8, 7, 6, 15, 16, 20, 19, 11, 10, 2, 1, 5, 4, 14, 13, 12, 3]
[6, 7, 8, 1, 5, 4, 14, 15, 16, 17, 18, 9, 10, 2, 3, 12, 13, 20, 19, 11]
[14, 13, 20, 16, 15, 6, 5, 4, 3, 12, 11, 19, 18, 17, 7, 8, 1, 2, 10, 9]
[20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[7, 17, 18, 9, 8, 1, 5, 6, 15, 16, 20, 19, 11, 10, 2, 3, 4, 14, 13, 12]
[15, 6, 5, 4, 14, 13, 20, 16, 17, 7, 8, 1, 2, 3, 12, 11, 19, 18, 9, 10]
[9, 10, 2, 1, 8, 7, 17, 18, 19, 11, 12, 3, 4, 5, 6, 15, 16, 20, 13, 14]
[2, 1, 8, 9, 10, 11, 12, 3, 4, 5, 6, 7, 17, 18, 19, 20, 13, 14, 15, 16]
[12, 13, 14, 4, 3, 2, 10, 11, 19, 20, 16, 15, 6, 5, 1, 8, 9, 18, 17, 7]
[17, 16, 20, 19, 18, 9, 8, 7, 6, 15, 14, 13, 12, 11, 10, 2, 1, 5, 4, 3]
[18, 17, 16, 20, 19, 11, 10, 9, 8, 7, 6, 15, 14, 13, 12, 3, 2, 1, 5, 4]
[18, 19, 11, 10, 9, 8, 7, 17, 16, 20, 13, 12, 3, 2, 1, 5, 6, 15, 14, 4]
[11, 12, 3, 2, 10, 9, 18, 19, 20, 13, 14, 4, 5, 1, 8, 7, 17, 16, 15, 6]
[15, 14, 13, 20, 16, 17, 7, 6, 5, 4, 3, 12, 11, 19, 18, 9, 8, 1, 2, 10]
[19, 11, 10, 9, 18, 17, 16, 20, 13, 12, 3, 2, 1, 8, 7, 6, 15, 14, 4, 5]
[12, 11, 19, 20, 13, 14, 4, 3, 2, 10, 9, 18, 17, 16, 15, 6, 5, 1, 8, 7]
[20, 16, 15, 14, 13, 12, 11, 19, 18, 17, 7, 6, 5, 4, 3, 2, 10, 9, 8, 1]
[13, 14, 4, 3, 12, 11, 19, 20, 16, 15, 6, 5, 1, 2, 10, 9, 18, 17, 7, 8]
[5, 6, 7, 8, 1, 2, 3, 4, 14, 15, 16, 17, 18, 9, 10, 11, 12, 13, 20, 19]
[14, 4, 3, 12, 13, 20, 16, 15, 6, 5, 1, 2, 10, 11, 19, 18, 17, 7, 8, 9]
Para qualquer outra rede, basta substituir todas as ocorrências de i
com o i
número th na entrada (onde i
é baseado em 1).
Desafios relacionados
Entre os melhores
O primeiro post da série gera uma tabela de classificação.
Para garantir que suas respostas sejam exibidas, inicie todas as respostas com um título, usando o seguinte modelo de remarcação:
## Language Name, N bytes
onde N
está o tamanho do seu envio. Se você melhorar sua pontuação, poderá manter as pontuações antigas no título, identificando-as. Por exemplo:
## Ruby, <s>104</s> <s>101</s> 96 bytes
(O idioma não é mostrado no momento, mas o snippet exige e o analisa, e eu posso adicionar um cabeçalho por idioma no futuro.)
fonte
Respostas:
Ruby, 160 bytes (rev. B)
17 bytes salvos graças a sugestões de Martin Büttner.
Ruby, 177 bytes (rev A)
Explicação
É possível gerar todas as orientações possíveis por rotações em torno de uma face (3 vezes), um vértice (5 vezes) e duas arestas (2 vezes). Mas não apenas qualquer rosto e arestas. Os eixos devem ter o relacionamento correto e as rotações devem ser feitas na ordem correta, ou coisas estranhas podem acontecer.
Foi assim que eu fiz (embora eu entenda que Martin fez diferente).
Todas as orientações de um tetraedro podem ser geradas por combinações das três operações de simetria a seguir:
a) Rotação em torno de dois eixos de duas dobras à direita através dos pontos médios das arestas (estes estão em ângulos retos entre si. Se os multiplicamos juntos, descobrimos um terceiro eixo de duas dobras através do par de arestas restante).
b) Rotação em torno de um eixo de 3 dobras na diagonal para os eixos de 2 dobras, passando por um vértice e uma face.
A simetria do icosaedro é um superconjunto da do tetraedro. Na imagem abaixo em https://en.wikipedia.org/wiki/Icosahedron , as faces amarelas e vermelhas definem dois tetraedros diferentes (ou alternativamente um único octaedro), enquanto as arestas comuns a duas faces azuis estão em três pares de ângulos retos (e estão nas faces de um cubo.)
Todas as orientações do icosaedro podem ser geradas pelas operações de simetria mencionadas acima, além de uma operação adicional de 5 vezes.
As rotações em torno de três dos quatro eixos mencionados acima são representadas pelas cordas mágicas entre as
''
marcas. A rotação em torno do segundo eixo de 2 vezes é diferente e pode ser feita apenas invertendo a matriza[]
.Sem jogar no programa de teste:
Solução alternativa 131 bytes (inválido devido à abordagem de passeio aleatório binário, fornece apenas uma distribuição aproximadamente correta).
Esta é uma disputa (bem como os programas usados para embaralhar o cubo de rubik.)
As rotações específicas que utilizo são duas das mais óbvias:
-Uma rotação de 120 graus (sobre as faces 1 e 20 conforme o primeiro diagrama)
-Uma rotação de 72 graus (sobre os vértices comuns a 1,2,3,4,5 e 16,17,18,19,20 pelo primeiro diagrama.)
jogamos uma moeda 99 vezes, e cada vez que executamos uma dessas duas rotações, dependendo se é cara ou coroa.
Observe que alternar esses deterministicamente leva a seqüências razoavelmente curtas. Por exemplo, com os sentidos de rotação corretos, uma rotação de 180 graus pode ser produzida com um período de apenas 2.
fonte
b.map
não funciona diretamente, precisob.chars.map
fazê-lo funcionar (BTW que não funciona na minha máquina como eu tenho o Ruby 1.9.3, mas funciona com o Ideone.) É uma economia justa. Eu não acho que alterar as seqüências de caracteres mágicas para caracteres não imprimíveis para salvar o-64
funcionará:%w{}
interpreta\n
(assim como espaço) como um separador entre as seqüências de caracteres na matriz gerada. Não tenho idéia do que fará com outros caracteres ASCII não imprimíveis.Código de máquina IA-32, 118 bytes
Hexdump:
É um pouco longo, então algumas explicações vão primeiro. Eu usei quase o mesmo algoritmo como o existente resposta pelo nível do rio St . Para tornar minha resposta diferente, tomei outras permutações básicas, que não necessariamente têm um significado geométrico intuitivo, mas são de alguma forma mais convenientes.
O código basicamente precisa gerar uma permutação, que é uma aplicação seqüencial do seguinte:
p3
, aplicada 0 ... 2 vezesq2
, aplicada 0 ou 1 vezesp5
, aplicada 0 ... 4 vezesp2
, aplicada 0 ou 1 vezesExistem muitas opções possíveis para essas permutações. Um deles é o seguinte:
Essa escolha é melhor que outras, porque as permutações aqui têm longas execuções de índices seqüenciais, que podem ser compactadas pela codificação de duração da execução - apenas 29 bytes para as 4 permutações.
Para simplificar a geração de números aleatórios, escolhi os poderes (quantas vezes cada permutação é aplicada) no intervalo de 1 a 30 para todos eles. Isso leva a muito trabalho extra no código, porque, por exemplo,
p3
se torna uma permutação de identidade cada vez que é multiplicado por ele mesmo 3 vezes. No entanto, o código é menor dessa maneira e, desde que o intervalo seja divisível por 30, a saída terá distribuição uniforme.Além disso, as potências devem ser positivas para que a operação de decodificação de execução seja executada pelo menos uma vez.
O código possui 4 loops aninhados; o esboço é assim:
Espero que esse pseudo-código seja mais claro que o código de montagem em linha abaixo.
Alguns detalhes divertidos de implementação:
call
e subseqüentementepop
para acessar dados (permutações codificadas) armazenados no códigojecxz
instrução convenientemente me permite usar um byte zero como finalização para o processo de decodificação de duraçãoPor sorte, o número 30 (2 * 3 * 5) é quase uma potência de 2. Isso me permite usar um código curto para gerar um número no intervalo de 1 ... 30:
Eu uso uma instrução "divisão de uso geral" (
aam
) para separar um byte em campos de bits (comprimento de 3 bits e índice de 5 bits); por sorte, nessa posição no códigocl = 0
, então me beneficio dos dois "lados" dexchg
fonte