El objetivo de este rompecabezas es tomar un mazo de 52 cartas y barajarlo para que cada carta esté en una posición aleatoria.
Dado:
- Una matriz,
deck
de 52 enteros distintos que representan las cartas. Cuando comienzas,deck
contiene exactamente una de cada tarjeta en un orden desconocido. - Una función,
int rand(min, max)
que devuelve un entero aleatorio entre intsmin
emax
inclusive. Puede suponer que esta función es verdaderamente aleatoria. - Una función,
void swap(x, y)
que intercambia dos cartas en el mazo. Si llamaswap(x, y)
, las tarjetas en las posicionesx
yy
cambiarán de lugar.
Cuando:
- El programa llama
shuffle()
(oshuffle(deck)
odeck.shuffle()
o como quiera que se ejecute su implementación),
Luego:
deck
debe contener exactamente una de cada tarjeta en orden perfectamente aleatorio.
La captura:
No puedes declarar ninguna variable. Llama swap
y rand
tanto como quieras, pero no puedes declarar ninguna variable propia. Esto incluye for
contadores de bucle, incluso los implícitos como en a foreach
.
Aclaraciones:
- Puede cambiar detalles menores para adaptarlos al idioma elegido. Por ejemplo, puede escribir
swap
para cambiar dos enteros por referencia. Los cambios deberían ser para que esto funcione con su idioma, no para facilitar el rompecabezas. deck
puede ser una variable global o puede tomarlo como parámetro.- Puede hacer lo que quiera con el contenido
deck
, pero no puede cambiar su longitud. - Sus tarjetas pueden estar numeradas del 0 al 51, del 1 al 52 o de lo que desee.
- Puede escribir esto en cualquier idioma, pero no hacer trampa con la
shuffle
función incorporada de su idioma . - Sí, podrías escribir la misma línea 52 veces. Nadie quedará impresionado.
- El tiempo de ejecución no importa, pero la verdadera aleatoriedad sí.
- Esto no es realmente golf de código, pero siéntase libre de minimizar / ofuscar su código.
Editar: código repetitivo y visualizador
Si usó .NET o JavaScript, aquí hay algunos códigos de prueba que pueden resultarle útiles:
JavaScript:
- Visualizador JavaScript rápido y sucio, con fuente de CoffeeScript: https://gist.github.com/JustinMorgan/3989752bdfd579291cca
- Versión ejecutable (solo pegue en su
shuffle()
función): http://jsfiddle.net/4zxjmy42/
C#:
- Visualizador ASP.NET con código C # detrás: https://gist.github.com/JustinMorgan/4b630446a43f28eb5559
- Stub con sólo las
swap
yrand
de servicios públicos métodos: https://gist.github.com/JustinMorgan/3bb4e6b058d70cc07d41
Este código clasifica y baraja el mazo varios miles de veces y realiza algunas pruebas básicas de cordura: para cada barajado, verifica que hay exactamente 52 cartas en el mazo sin repeticiones. Luego, el visualizador traza la frecuencia de cada carta que termina en cada lugar del mazo, mostrando un mapa de calor en escala de grises.
La salida del visualizador debe verse como nieve sin un patrón aparente. Obviamente, no puede probar la verdadera aleatoriedad, pero es una forma rápida y fácil de verificar. Recomiendo usarlo o algo así, porque ciertos errores en el algoritmo de barajado conducen a patrones muy reconocibles en la salida. Aquí hay un ejemplo del resultado de dos implementaciones, una con una falla común:
La versión defectuosa baraja parcialmente el mazo, por lo que podría verse bien si examinaras la matriz a mano. El visualizador hace que sea más fácil notar un patrón.
fuente
deck
sí mismo.swap
desee, siempre y cuando cumpla con su propósito básico. Parte de mi razón para hacerswap
un hecho era que las personas pudieran tratarlo como 'mágico' y concentrarse en el problema principal sin tener que preocuparse de que funcione en el idioma de su elección. Puedes hacer eso o escribir el tuyoswap
, depende de ti.Respuestas:
JavaScript
Creo que esta es la forma prevista de solución, utilizo la tarjeta en la posición 0 para realizar un seguimiento del progreso, solo barajando las tarjetas que ya se han utilizado como contador, ¡esto alcanza el estándar 52! permutaciones con una distribución equitativa perfecta. El procedimiento se complica porque XOR swap no permite que un elemento se intercambie por sí mismo.
Editar: construí una clasificación que clasifica cada elemento en su lugar justo antes de usarlo, lo que permite que esto funcione con una matriz sin clasificar. También abandoné las llamadas recursivas a favor de un ciclo while.
fuente
Haskell
Aquí hay una implementación sin puntos. Sin variables, parámetros formales o recursividad explícita. Yo solía lambdabot 's
@pl
función refactorización ( 'sin sentido') un poco.Aquí está mi procedimiento de prueba para asegurarme de que los números se distribuyan uniformemente:
Aquí está el algoritmo original:
fuente
((.) .) . (. (++))
y este(((.) . (,)) .)
son mis favoritos. Wow lambdabot. Simplemente guau.J
Ignorando que el mazo es una variable, está lo obvio ...
Por supuesto, si realmente quieres una función, existe esta, que funcionará incluso si olvidas eliminar los comodines (o intentas barajar algo que no sean cartas).
Así que eso...
Esto probablemente esté fuera de la intención de la pregunta, que sería implementar el shuffle usted mismo de rand (
?
). Podría hacerlo más tarde cuando no se supone que esté trabajando.Explicación
Explicación de
52 ? 52
:x ? y
es x elementos únicos aleatorios de y.La explicación de
{~ (# ? #)
es más difícil debido a los tenedores y ganchos . Básicamente, es lo mismo queshuffle =: 3 : '((# y) ? (# y)) { y'
, que tiene un argumento implícito (y
).# y
da la longitud de yx { y
es el elemento de y en el índice x, o (en este caso) elementos en los índices en x.Consulte el vocabulario J para obtener detalles de los operadores, aunque la sintaxis y la semántica son bastante complicadas debido a la programación tácita y de rango.
fuente
{52?⍵}
es una función anónima que toma 52 elementos aleatorios de su argumento, que aquí sería una lista de 52 enteros)Pitón
fuente
[1:]
eso? ¿Eso se repite en una sub-matriz dedeck
?a, b = b, a
truco.Usando representación factoradic
En la representación factoradic de una permutación, un elemento i toma valores de 0 a Ni. Entonces, una permutación aleatoria es solo
rand(0,i)
para cada Ni.En J:
donde
? x
estarand(0,x-1)
y|.>:i.52
esta52 51 ... 1
Entonces, si
a
es el valor de ITH factoradic, hacemos el canje:swap(deck[i], deck[i+a])
. La lista de pares para intercambiar son:El intercambio que usaremos funciona de esta manera:
No es realmente "por referencia", pero no hay funciones reales en J.
Usaremos la longitud del mazo (
#deck
) para evitar usar una constante.Programa completo en J:
fuente
C#
Aquí está mi propia respuesta basada en el algoritmo de Fisher-Yates . Debería darle una combinación perfecta si su generador de números aleatorios es lo suficientemente bueno.
Versión inglesa:
deck[0]
la que está endeck[v]
, dondev
es el valor nominal de la tarjeta endeck[0]
. Repetir hastav == 0
. Esto ordenará parcialmente el mazo, pero eso no importa. Ahora sabe que la Tarjeta 0 está en la parte delantera del mazo, lo que significa que puede robar ese espacio en la matriz y usarlo como contador de bucles. Este es el "truco" clave para el problema de las variables locales.i
con la que está enrand(i, 51)
. Tenga en cuenta que usted necesitarand(i, 51)
, NOrand(1, 51)
. Eso no asegurará que cada carta sea aleatoria.deck[0]
de nuevo a 0. Ahora toda la cartas se barajan a excepción de la primera tarjeta, de modo de intercambiodeck[0]
condeck[rand(0, 51)]
y ya está.Versión C #:
Versión Javascript:
... donde
swap(a, b)
intercambiadeck[a]
condeck[b]
.fuente
Rubí, una línea
¿Se considera esto hacer trampa? Debería ser lo más aleatorio posible.
(El
rand
método de Ruby solo toma un argumento y luego genera un número n tal que 0 <= número <argumento).Además, similar a la solución Perl de sogart, pero que yo sepa, no sufre el problema:
Ruby sort_by es diferente de sort: primero genera la lista de valores para ordenar la matriz, y solo luego la ordena por ellos. Es más rápido cuando es costoso descubrir la propiedad por la que estamos clasificando, algo más lento en todos los demás casos. También es útil en el código de golf: P
fuente
deck[0..51]
elude la regla de "no variables" utilizando una característica del lenguaje. Es justo, solo creo que pierde parte del desafío. :) No conozco a Ruby; puedes explicar la(0..51).map{deck.delete_at(rand deck.length)}
parte? ¿Eso elimina las tarjetas dedeck
?deck
y la agrega a la lista interna de resultados que semap
está acumulando. Luego, cuando no queda nada endeck
elmap
resultado, se copiadeck
. Básicamente hay una función temporal, pero es una función del lenguaje en lugar de una variable explícita :)deck.sort_by!{rand}
Es más corto.JavaScript
NOTA: Esta solución no es técnicamente correcta porque utiliza un segundo parámetro
i
, en la llamada ashuffle
, que cuenta como una variable externa.Llamar con
shuffle(deck,52)
Un ejemplo de trabajo completo (tuvo que modificarse
swap
ligeramente porque no hay referencias de ints en JavaScript):fuente
shuffle
como variables, pero no lo especifiqué +1. Buen uso de la recursividad, también.deck[rand(0,i-1)]
lugar dedeck[rand(0,i-2)]
. También cambie por completo eni=0
lugar de detenerse eni=1
. ¿Eso ayuda?C ++
Evita intercambiar elementos consigo mismos, por lo que debe llamar dos veces para ser aleatorio.
fuente
swap(deck[rand(1, 51)], (deck[0] - 51) / 100);
¿Cómoswap
sabrá dónde poner el segundo valor? También te falta un)
.deck[0]
, pero no de la manera que tú la tienes.re
fuente
Otra solución de Perl, que en realidad produce una salida distribuida uniformemente:
Esta solución utiliza Perl
rand
, que devuelve un número aleatorio x en el rango 0 ≤ x <1. Agrega un número aleatorio a cada número entero en la entrada, ordena los números de acuerdo con sus partes fraccionarias y finalmente elimina esas partes fraccionarias nuevamente. .(Creo que el uso de las variables especiales
$_
,$a
y$b
cae dentro del espíritu del desafío, ya que así es como perl pasa la entradamap
ysort
, y no se usan para ningún otro propósito en el código. En cualquier caso, creo en realidad son alias de los valores de entrada, no copias independientes Esto no es en realidad una reproducción aleatoria en el lugar, sin embargo;. tantomap
ysort
crean copias de la entrada en la pila).fuente
Java
Me sorprende que nadie haya dicho lo obvio: (supondré que swap (x, x) no hace nada.
OK, ok, puede ser más corto:
fuente
Burlesco
¿Lo que realmente está pidiendo es una permutación aleatoria de una lista de enteros?
r@
nos dará todas las permutaciones, y solo seleccionaremos una aleatoria.Como necesitamos una aleatoriedad verdadera, algo que Burlesque no es capaz de hacer porque Burlesque no tiene funcionalidad de E / S, necesitaría proporcionar alguna fuente de aleatoriedad a través de STDIN.
Eso es probablemente algo que arreglaré en una versión posterior (es decir, generar una semilla aleatoria al inicio y empujarla a la pila secundaria o algo así, pero el Intérprete Burlesque en sí no tiene E / S).
fuente
Javascript
No estoy seguro de si es "trampa", pero mi solución utiliza la matriz local nativa de los argumentos de una función. Incluí mis propias funciones de
rand()
swap()
yfilldeck()
. De nota interesante, esto debería funcionar con un mazo de cualquier tamaño.fuente
Tcl , 32 bytes
time
Función de abuso que sirve para medir cuánto tiempo se está ejecutando un script, pero también puede servir como un mecanismo de bucle sin declarar ninguna variable.Pruébalo en línea!
fuente
Perl: ¡esta no es una combinación adecuada como se explica en los comentarios!
Creo que no usé nada como un intercambio, etc. ¿Era eso necesario como parte del problema?
fuente
JavaScript 4 líneas
Respuesta original que no fue lo suficientemente aleatoria. No se garantizó que el intercambio tocaría cada elemento de la baraja.
fuente
shuffle
código ligeramente para que coincida con miswap
implementación, pero aquí está al pie de la letra: jsfiddle.net/m7km4u6g