Huracán Matthew y los rayos

27

Reto

Inspirado por este desafío y el desagradable huracán Matthew , generaremos dinámicamente algunos rayos.

n = 15:

   \
   /\
  /  \
 /   /
/\  /\
 /  \ \
/   / /\
   /\ \
  / /  \
 /\ \  /\
  /  \ \
 /\  /  
   \
    \
    /\

Entrada

Entero positivo ndetermina la profundidad de la ronda de rayos.

Reglas y restricciones

  • /y \debe ser usado
  • La probabilidad que guía la dirección del rayo es la siguiente:
    • 25% se divide en 2 caminos
    • El 25% de la ruta llega al final
    • 25% va a la izquierda
    • 25% va bien
    • Hay algunas excepciones con respecto a la superposición y el callejón sin salida a continuación:
  • El código no debe ser determinista, se debe generar un nuevo rayo al azar cada vez
  • Los pernos no deben superponerse: por ejemplo, si ya hay un perno a la izquierda del perno actual, el perno actual debe terminar o ir a la derecha, pero no ir a la izquierda o dividirse (la probabilidad aún se aplica, en este caso se convierte en un 50% de finalización) / 50% correcto)
  • Si no existe otra ruta dividida disponible, la ruta no debe terminar: por ejemplo, al principio cuando solo hay 1 ruta, la ruta no debe terminar hasta que se divide, también se aplica cuando hay varias rutas, pero todas excepto una ruta están muertas , (la probabilidad se convierte en un 33% de división / 33% a la izquierda / 33% a la derecha) su objetivo es llegar al fondo
  • Se pueden agregar espacios en blanco a la izquierda (todo lo que necesitaría debe ser solo altura-1)
  • Sin embargo, si desea generar el perno, depende de usted, puede ir de abajo hacia arriba, de izquierda a derecha, etc. Siempre y cuando se cumplan todas las reglas anteriores

Otro ejemplo

n = 10

 \
 /
 \
 /\
  /\
 / /
/\ \
 / /\
 \   \
 /

El huracán Matthew aparentemente dispara rayos rojos en el cielo, llamados sprites

¡Manténgase seguro y diviértase jugando al golf! ¡Juegue de manera responsable solo cuando se encuentre en un área segura!

Zukaberg
fuente
77
Stay safe and have fun golfing!¡Quizás también especifique que si EAS ataca, abandone todo y siga las órdenes! El código de golf no es su prioridad en tal situación.
Erik the Outgolfer
17
@EriktheGolfer, entonces no eres un verdadero golfista.
Azul
44
No creo que "el camino más al centro deba ser el que llega al suelo" es consistente con el resto de la descripción de generación aleatoria. Por ejemplo, es posible aleatoriamente que el tornillo original se divida dos veces y luego que los dos tornillos centrales terminen; ¿Cómo se puede anular esta posibilidad mientras se conservan las probabilidades indicadas?
Greg Martin
Además, ¿qué sucede si (por ejemplo) los dos primeros pasos son dos divisiones? Luego, los dos pernos del medio se tocan, lo que parece problemático pero tampoco está descartado por los casos especiales.
Greg Martin
@GregMartin Buen punto en la parte más central, originalmente esperaba que generara un perno equilibrado, pero ahora que lo pienso, incluso sin esa restricción, aproximadamente el 50% del tiempo debería terminar en algún lugar en el medio, una profundidad de 15 solo tendría un 1-2% de posibilidades donde aterriza la derecha o la izquierda de la mayoría del camino Eliminaré esa regla. Y para la parte de división de 2 pasos, lo único que se debe evitar es que no se unan 2 caminos: \/en cualquier punto.
Zukaberg

Respuestas:

6

Perl, 92 90 89 84 bytes

Incluye +1 para -n

Dar altura en STDIN:

perl -M5.010 bolt.pl <<< 15

bolt.pl:

#!/usr/bin/perl -n
map{$_=$;until$;=$_,s/.6|3.?/53|16*rand/eg,/3|6/>/36/;say y|3615|\\/ |r}(1x$_.6)x$_

Explicación

Si llama al desplazamiento del punto de inicio 0 (un punto está en la esquina de un cuadro de caracteres), en la siguiente fila puede haber ido hacia la izquierda o hacia la derecha (o no) y puede terminar con puntos en los desplazamientos -1,1. La siguiente fila muestra los -2,0,2posibles desplazamientos, etc. Todos difieren en 2. Si luego llama al carácter a la esquina inferior izquierda de un punto par y el carácter a la esquina inferior derecha impar, puede extenderlo para asignar pares o impares a cada posición de carácter. en una fila tal que la alternativa par e impar (de hecho, todo el plano está en mosaico en un patrón de tablero de ajedrez). Una posición par puede tener un /o , una posición impar puede tener \o .

El personaje justo antes de a /está en una posición extraña, por lo que podría ser uno \o , pero \/está prohibido, por lo que solo es posible. Del mismo modo, el carácter después de a \ debe ser a (suponiendo que la fila esté rellenada con suficientes espacios a la izquierda y a la derecha para que los límites de la fila no sean un problema). Entonces un rayo continúa en la siguiente fila siempre directamente debajo de \ao debajo de a /. En cualquier caso, el punto más bajo está en el medio y la siguiente fila puede tener uno de , /, \o /\directamente debajo de la tapa 2 caracteres. Entonces, para generar la siguiente fila, simplemente puedo reemplazar cualquiera \o/por cualquiera de estas 4 expansiones con igual probabilidad (también podría reemplazar independientemente el primer carácter por o /y el segundo carácter por o \). En perl podrías hacer esto con algo como:

s#\\ | /#("  "," \\","/ ","/\\")[rand 4]#eg

Si la fila resultante sin embargo contiene \/(prohibido unirse a) o ninguna /, o \en todos los troqueles (pernos y no llega a la parte inferior) el resultado no es válido. En ese caso, tiro toda la fila y simplemente intento de nuevo. Siempre existe una continuación válida y si intenta con suficiente frecuencia se encontrará una (por ejemplo, todo muere excepto por 1 flujo). Esta es una distribución de probabilidad ligeramente diferente del algoritmo anti-superposición sugerido, pero creo que de hecho es mejor ya que no tiene sesgo direccional. La validez se puede probar de forma golfística utilizando

m#\\|/#>m#\\/#

El problema aquí es que la sustitución aleatoria es muy larga y todos estos \escapes también comen bytes. Así que decidí construir mis filas usando cadenas de dígitos y reemplazar los dígitos apropiados por , /y \justo antes de imprimir. El reemplazo aleatorio básico es

53|16*rand

lo que da una de 53, 55, 61o 63con igual probabilidad. Luego interpreto 5y 1as , 3as \y 6as /. Eso explica la impresión de la fila:

say y|3615|\\/ |r

En una competencia de golf seria, ahora comenzaría a explorar sistemáticamente fórmulas mágicas alternativas, pero esto debería ser bastante bueno (dentro de 3 bytes de óptimo)

El resto de los componentes del programa:

1x$_.6

Esto inicializa $_(ver el siguiente mapa) a espacios de altura seguidos de a /. Esta es una fila invisible encima de la primera que se imprime y se asegura de que el campo sea lo suficientemente ancho para que el perno nunca se quede sin espacio a la izquierda

map{ ... ; say ...}(1x$_.6)x$_

Procesaré esta misma altura de cadena inicial veces imprimiendo una nueva fila cada vez

$_=$;until$;=$_,...

Guardar la fila actual en $;. Si el reemplazo resulta no válido, restaure $_desde$;

s/.6|3.?/53|16*rand/eg

Haz la sustitución real. No tengo que verificar qué es antes /o después, \ya que debe ser un espacio. Esto es conveniente ya que el espacio puede ser representado por 1o 5. Como solo acolché la cadena a la izquierda, el espacio después de \que todavía puede estar ausente, así que haga que ese carácter sea opcional

/3|6/>/36/

Verifique si la nueva fila es válida

Ton Hospel
fuente
+1 Neat! deberías incluir este probador en línea perl -M5.010 main.pl <<< 25 , ¡he estado obteniendo algunos buenos resultados!
Zukaberg
¿Te importaría explicar un poco cómo funciona? Me estoy divirtiendo demasiado generándolos jaja, honestamente no anticipé tan buenos resultados.
Zukaberg
Desafortunadamente, necesita agregar 3 bytes para-n , porque el espacio y el guión también cuentan. La misma regla es para argumentos de línea de comandos. Consulte "Invocaciones especiales", segundo punto: cuento como una diferencia en el recuento de caracteres a la invocación equivalente más corta sin ellas.
Erik the Outgolfer
1
@EriktheGolfer No, +1 está bien porque este programa funciona bien desde la línea de comandos usando -nEsolo 1 carácter más que -E(vea el artículo al que hizo referencia. Esto también elimina la necesidad de -M5.010) Siempre presento mi código como archivos porque es más conveniente, pero siempre cuento opciones como esta: si se puede ejecutar desde la línea de comandos, no cuento el espacio y el guión. Si debe estar en un archivo (por ejemplo, porque usa do$0), cuento el espacio y el guión
Ton Hospel
@TonHospel Oh, no sabía que usabas -E. Si es así, eres bueno.
Erik the Outgolfer
0

JavaScript (ES6), 154 bytes

f=(n,r=[],s=" ".repeat(n)+"/",t=s.replace(/ \/|\\ |\\$/g,_=>"  /  \\/\\".substr(Math.random()*8&6,2)))=>n?/^ +$|\\\//.test(t)?f(n,r,s):f(n-1,[...r,t],t):r
<input type="number" min=1 oninput=o.textContent=f(this.value).join`\n`><pre id=o>

Luché con la implementación hasta que vi la respuesta de @ TonHospel, momento en el que simplemente degeneró en un puerto. Salida de muestra:

         /\
        / /\
       /\   \
        /\   \
         /\  /
          / /\
         / / /\
            / /\
            \   \
             \
Neil
fuente