O objetivo deste quebra-cabeça é pegar um baralho de 52 cartas e embaralhá-lo para que cada carta esteja em uma posição aleatória.
Dado:
- Uma matriz
deck
de 52 números inteiros distintos representando os cartões. Quando você inicia,deck
contém exatamente um de cada cartão em alguma ordem desconhecida. - Uma função
int rand(min, max)
,, que retorna um número inteiro aleatório entre intsmin
emax
, inclusive. Você pode assumir que esta função é verdadeiramente aleatória. - Uma função
void swap(x, y)
que troca duas cartas no baralho. Se você ligarswap(x, y)
, os cartões nas posiçõesx
ey
trocarão de lugar.
Quando:
- O programa chama
shuffle()
(oushuffle(deck)
oudeck.shuffle()
ou como sua implementação gosta de executar),
Então:
deck
deve conter exatamente um de cada cartão em ordem perfeitamente aleatória.
A pegada:
Você não pode declarar nenhuma variável. Ligue swap
e rand
quantas vezes quiser, mas você não pode declarar nenhuma variável sua. Isso inclui for
contadores de loop - mesmo implícitos, como em a foreach
.
Esclarecimentos:
- Você pode alterar detalhes menores para se adequar ao idioma escolhido. Por exemplo, você pode escrever
swap
para alternar dois números inteiros por referência. As alterações devem ser para facilitar o trabalho no seu idioma, não para facilitar o quebra-cabeça. deck
pode ser uma variável global ou você pode aceitá-la como um parâmetro.- Você pode fazer o que quiser com o conteúdo
deck
, mas não pode alterar o comprimento. - Seus cartões podem ser numerados de 0 a 51, 1-52 ou qualquer coisa que você desejar.
- Você pode escrever isso em qualquer idioma, mas sem trapacear com a função interna do seu idioma
shuffle
. - Sim, você pode escrever a mesma linha 52 vezes. Ninguém ficará impressionado.
- O tempo de execução não importa, mas a verdadeira aleatoriedade importa.
- Isso não é realmente um código de golfe, mas fique à vontade para minimizar / ofuscar seu código.
Edit: Visualizador de código e visualizador
Se você usou .NET ou JavaScript, aqui estão alguns códigos de teste que podem ser úteis:
JavaScript:
- Visualizador de JavaScript rápido e sujo, com fonte do CoffeeScript: https://gist.github.com/JustinMorgan/3989752bdfd579291cca
- Versão executável (basta colar na sua
shuffle()
função): http://jsfiddle.net/4zxjmy42/
C #:
- Visualizador do ASP.NET com código C #; por trás: https://gist.github.com/JustinMorgan/4b630446a43f28eb5559
- Stub apenas com os métodos utilitários
swap
erand
: https://gist.github.com/JustinMorgan/3bb4e6b058d70cc07d41
Esse código classifica e embaralha o baralho milhares de vezes e realiza alguns testes básicos de sanidade: Para cada baralhamento, verifica se há exatamente 52 cartas no baralho sem repetições. Em seguida, o visualizador plota a frequência de cada cartão que termina em cada local do baralho, exibindo um mapa de calor em escala de cinza.
A saída do visualizador deve parecer neve sem padrão aparente. Obviamente, não pode provar a verdadeira aleatoriedade, mas é uma maneira rápida e fácil de verificar. Eu recomendo usá-lo ou algo parecido, porque certos erros no algoritmo de reprodução aleatória levam a padrões muito reconhecíveis na saída. Aqui está um exemplo da saída de duas implementações, uma com uma falha comum:
A versão defeituosa embaralha parcialmente o baralho, portanto, pode parecer bem se você examinar a matriz manualmente. O visualizador facilita a observação de um padrão.
fonte
deck
ele próprio.swap
desejar, desde que cumpra seu objetivo básico. Parte da minha razão de darswap
um certo foi para que as pessoas pudessem tratá-lo como 'mágico' e se concentrar no problema principal sem ter que se preocupar com o fato de ele funcionar no idioma de sua escolha. Você pode fazer isso ou escrever o seu próprioswap
, é com você.Respostas:
Javascript
Eu acredito que esta é a forma pretendida de solução, eu uso o cartão na posição 0 para acompanhar o progresso, apenas embaralhando os cartões que já foram usados como contador, isso atinge o padrão 52! permutações com uma distribuição igual perfeita. O procedimento é complicado pela troca de XOR, não permitindo que um elemento seja trocado por si só.
Edit: Eu construí uma classificação que classifica cada elemento no lugar imediatamente antes de ser usado, permitindo que isso funcione com uma matriz não classificada. Também abandonei as chamadas recursivas em favor de um loop while.
fonte
Haskell
Aqui está uma implementação sem pontos. Sem variáveis, parâmetros formais ou recursão explícita. Eu costumava lambdabot 's
@pl
( 'inútil') recurso de refatoração um pouco.Aqui está o meu procedimento de teste para garantir que os números foram distribuídos uniformemente:
Aqui está o algoritmo original:
fonte
((.) .) . (. (++))
e este(((.) . (,)) .)
são os meus favoritos. Uau lambdabot. Apenas Uau.J
Ignorar esse baralho é uma variável, há o óbvio ...
Obviamente, se você realmente deseja uma função, existe isso, que funcionará mesmo se você esquecer de remover os curingas (ou tentar embaralhar algo diferente de cartões).
De modo a...
Provavelmente, isso está fora da intenção da pergunta, que seria implementar o embaralhamento de rand (
?
). Eu poderia fazer isso mais tarde, quando não deveria estar trabalhando.Explicação
Explicação de
52 ? 52
:x ? y
é x itens únicos aleatórios de y.A explicação de
{~ (# ? #)
é mais difícil por causa de garfos e ganchos . Basicamente, é o mesmo queshuffle =: 3 : '((# y) ? (# y)) { y'
, que possui um argumento implícito (y
).# y
dá o comprimento de yx { y
é o item de y no índice x, ou (nesse caso) itens nos índices em x.Consulte J Vocabulary para obter detalhes dos operadores, embora a sintaxe e a semântica sejam um pouco complicadas devido à programação tácita e de classificação.
fonte
{52?⍵}
é uma função anônima que leva 52 itens aleatórios de seu argumento, que aqui seria uma lista de 52 números inteiros)Pitão
fonte
[1:]
significa isso? Isso ocorre em uma sub-matriz dedeck
?a, b = b, a
truque.Usando representação fatorádica
Na representação fatorádica de uma permutação, um elemento i leva valores de 0 a Ni. Portanto, uma permutação aleatória é apenas
rand(0,i)
para todo Ni.Em J:
onde
? x
érand(0,x-1)
e|.>:i.52
é52 51 ... 1
Então, se
a
é o valor do om factoradic, nós fazemos o swap:swap(deck[i], deck[i+a])
. A lista de pares a serem trocados são:A troca que usaremos funciona assim:
Não é realmente "por referência", mas não há funções reais em J.
Usaremos o comprimento do deck (
#deck
) para evitar o uso de uma constante.Programa completo em J:
fonte
C #
Aqui está minha própria resposta baseada no algoritmo de Fisher-Yates . Você deve embaralhar perfeitamente se o gerador de números aleatórios for bom o suficiente.
Versão em inglês:
deck[0]
pelodeck[v]
quev
está em , onde está o valor nominal do cartão emdeck[0]
. Repita atév == 0
. Isso classificará parcialmente o baralho, mas isso não importa. Agora você sabe que o cartão 0 está na frente do baralho, o que significa que você pode roubar esse espaço na matriz e usá-lo como um contador de loop. Esta é a chave "trapaça" para o problema de variáveis locais.i
com a que está emrand(i, 51)
. Note que você precisarand(i, 51)
, NÃOrand(1, 51)
. Isso não garante que cada cartão seja randomizado.deck[0]
de volta a 0. Agora, todo o baralho é embaralhado exceto para o primeiro cartão, então trocadeck[0]
comdeck[rand(0, 51)]
e está feito.Versão c #:
Versão Javascript:
... onde
swap(a, b)
swapsdeck[a]
comdeck[b]
.fonte
Ruby, uma linha
Isso é considerado trapaça? Deve ser o mais aleatório possível.
(O
rand
método Ruby usa apenas um argumento e gera um número n tal que 0 <= número <argumento.)Além disso - semelhante à solução Perl da sogart, mas até onde eu sei, ela não sofre com o problema:
O sort_by de Ruby é diferente de sort - ele primeiro gera a lista de valores para classificar a matriz e somente depois a classifica por eles. É mais rápido quando é caro descobrir a propriedade pela qual estamos classificando, um pouco mais lento em todos os outros casos. Também é útil no código de golfe: P
fonte
deck[0..51]
evita um pouco a regra "sem variáveis" usando um recurso do idioma. É justo, acho que perde um pouco do desafio. :) Eu não conheço Ruby; você pode explicar a(0..51).map{deck.delete_at(rand deck.length)}
parte? Isso exclui os cartõesdeck
?deck
e o adiciona à lista interna de resultados quemap
está acumulando. Então, quando não há mais nadadeck
nomap
resultado é copiado paradeck
. Basicamente há um temporária, mas é um recurso de linguagem, em vez de uma variável explícita :)deck.sort_by!{rand}
é mais curto.Javascript
NOTA: Esta solução tecnicamente não está correta porque usa um segundo parâmetro
i
, na chamada parashuffle
, que conta como uma variável externa.Ligue com
shuffle(deck,52)
Um exemplo de trabalho completo (teve que ser modificado
swap
um pouco porque não há passagem por referência de ints no JavaScript):fonte
shuffle
como variáveis, mas não especifiquei isso com +1. Bom uso de recursão também.deck[rand(0,i-1)]
vez dedeck[rand(0,i-2)]
. Troque também todo o caminho emi=0
vez de parar emi=1
. Isso ajuda?C ++
Evita a troca de elementos entre si, portanto, é necessário chamar duas vezes para ser aleatório.
fonte
swap(deck[rand(1, 51)], (deck[0] - 51) / 100);
Comoswap
saberá onde colocar o segundo valor? Você também está faltando)
.deck[0]
, mas não da maneira que você tem.D
fonte
Outra solução Perl, que na verdade produz resultados uniformemente distribuídos:
Esta solução usa Perl
rand
, que retorna um número aleatório x no intervalo de 0 ≤ x <1. Ele adiciona um número aleatório a cada número inteiro na entrada, classifica os números de acordo com suas partes fracionárias e, finalmente, retira essas partes fracionárias novamente .(Eu acredito que o uso das variáveis especiais
$_
,$a
e$b
insere-se no espírito do desafio, já que esses são como perl passa a entrada paramap
esort
, e eles não são usados para qualquer outro propósito no código. Em qualquer caso, eu acredito eles são realmente aliases para os valores de entrada, não cópias independentes Este não é realmente um shuffle no lugar, embora,. tantomap
esort
criar cópias de entrada na pilha).fonte
Java
Estou surpreso que ninguém tenha declarado o óbvio: (presumo que a troca (x, x) não faça nada.
OK, ok, pode ser mais curto:
fonte
Burlesque
O que você está realmente pedindo é uma permutação aleatória de uma lista de números inteiros?
r@
nos dará todas as permutações, e apenas selecionamos uma aleatória.Como precisamos da verdadeira aleatoriedade, algo que o Burlesque não é capaz de fazer porque o Burlesque não possui funcionalidade de E / S, você precisará fornecer uma fonte de aleatoriedade através do STDIN.
Provavelmente isso é algo que eu corrigirei na versão posterior (ou seja, gere uma semente aleatória na inicialização e envie-a para a pilha secundária ou algo parecido, mas o próprio Burlesque Interpreter não possui E / S).
fonte
Javascript
Não tenho certeza se está "trapaceando", mas minha solução usa a matriz local nativa dos argumentos de uma função. Eu incluí minhas funções criadas por si
rand()
swap()
e defilldeck()
. De nota interessante, isso deve funcionar com um deck de qualquer tamanho.fonte
Tcl , 32 bytes
time
Função de abuso que serve para medir quanto tempo é gasto em um script, mas também pode servir como um mecanismo de loop sem declarar nenhuma variável.Experimente online!
fonte
perl - este não é um shuffle adequado, como explicado nos comentários!
Eu acho que não usei nada como troca, etc. foi necessário como parte do problema?
fonte
JavaScript 4 linhas
Resposta original que não foi aleatória o suficiente. A troca não era garantida para tocar em cada item no baralho.
fonte
shuffle
código ligeiramente para coincidir com a minhaswap
aplicação, mas aqui é textualmente: jsfiddle.net/m7km4u6g