Arte ASCII aleatorio del día # 5: mosaicos de diamantes

21

Mash Up Time!

Esta es la entrega n. ° 5 de mi serie Random Golf of the Day y ASCII Art of the Day de Optimizer . Su (s) envío (s) en este desafío contarán para ambas tablas de clasificación (que puede encontrar las publicaciones vinculadas). Por supuesto, puede tratar esto como cualquier otro desafío de código de golf y responderlo sin preocuparse por ninguna de las series.

Hoyo 5: azulejos de diamante

Un hexágono regular siempre se puede colocar en mosaico con diamantes de esta manera:

Usaremos una representación de arte ASCII de estas inclinaciones. Para un hexágono de longitud lateral 2, hay 20 inclinaciones de este tipo:

   ____     ____     ____     ____     ____     ____     ____     ____     ____     ____  
  /\_\_\   /\_\_\   /\_\_\   /\_\_\   /_/\_\   /_/\_\   /\_\_\   /_/\_\   /_/\_\   /_/\_\ 
 /\/\_\_\ /\/_/\_\ /\/_/_/\ /\/_/\_\ /\_\/\_\ /\_\/_/\ /\/_/_/\ /\_\/\_\ /\_\/_/\ /_/\/\_\
 \/\/_/_/ \/\_\/_/ \/\_\_\/ \/_/\/_/ \/\_\/_/ \/\_\_\/ \/_/\_\/ \/_/\/_/ \/_/\_\/ \_\/\/_/
  \/_/_/   \/_/_/   \/_/_/   \_\/_/   \/_/_/   \/_/_/   \_\/_/   \_\/_/   \_\/_/   \_\/_/ 
   ____     ____     ____     ____     ____     ____     ____     ____     ____     ____  
  /_/_/\   /\_\_\   /_/\_\   /_/_/\   /_/\_\   /_/\_\   /_/_/\   /_/_/\   /_/_/\   /_/_/\ 
 /\_\_\/\ /\/_/_/\ /_/\/_/\ /\_\_\/\ /\_\/_/\ /_/\/_/\ /_/\_\/\ /\_\_\/\ /_/\_\/\ /_/_/\/\
 \/\_\_\/ \/_/_/\/ \_\/\_\/ \/_/\_\/ \/_/_/\/ \_\/_/\/ \_\/\_\/ \/_/_/\/ \_\/_/\/ \_\_\/\/
  \/_/_/   \_\_\/   \_\/_/   \_\/_/   \_\_\/   \_\_\/   \_\/_/   \_\_\/   \_\_\/   \_\_\/ 

Dada una longitud lateral N, debe generar un mosaico para un hexágono de longitud lateral Nal azar. La distribución exacta no importa, pero cada mosaico debe devolverse con una probabilidad distinta de cero.

Para N ≤ 4, su presentación debe producir un mosaico dentro de 1 minuto al menos el 80% del tiempo y al menos el 80% de las inclinaciones deben generarse potencialmente dentro de 1 minuto. La mayoría de los enfoques no tendrán que preocuparse por esta regla (es muy indulgente); esto es solo para descartar algoritmos basados ​​en el rechazo muy ingenuos que generan cadenas arbitrarias hasta que uno sea un mosaico.

Es posible que desee saber que el número total de posibles inclinaciones para un determinado N se puede encontrar en OEIS A008793 .

Puede escribir un programa completo o una función y recibir información a través de STDIN (o la alternativa más cercana), argumento de línea de comando o argumento de función y producir salida a través de STDOUT (o la alternativa más cercana), valor de retorno de función o parámetro de función (out).

No debe generar más espacios iniciales de los necesarios para alinear el hexágono (es decir, la esquina izquierda del hexágono no debe tener espacios delante). Cada línea puede contener hasta Nespacios finales (no necesariamente consistentemente, por lo que podría tener, por ejemplo, una salida rectangular, imprimiendo el cuadro delimitador del hexágono).

Este es el código de golf, por lo que gana el envío más corto (en bytes). Y, por supuesto, la presentación más corta por usuario también entrará en la tabla de clasificación general de la serie.

Tablas de clasificación

La primera publicación de cada serie genera una tabla de clasificación.

Para asegurarse de que sus respuestas aparezcan, comience cada respuesta con un título, utilizando la siguiente plantilla de Markdown:

# Language Name, N bytes

¿Dónde Nestá el tamaño de su envío? Si mejora su puntaje, puede mantener los puntajes antiguos en el título, tachándolos. Por ejemplo:

# Ruby, <s>104</s> <s>101</s> 96 bytes

(El idioma no se muestra actualmente, pero el fragmento sí lo requiere y analiza, y puedo agregar una tabla de clasificación por idioma en el futuro).

Martin Ender
fuente
3
¿Soy yo quien sigue viendo la imagen de ejemplo en 3D?
LegionMammal978
3
@ LegionMammal978 No, eso es perfectamente normal. ;) (Y probablemente también sea una buena forma de abordar el desafío.)
Martin Ender
For N ≤ 4, your submission must produce a tiling within 1 minute at least 80% of the time.demasiado fácil: el 80% del tiempo de la misma, suelo de baldosas básica, de lo contrario buscar otro mosaico en cualquier momento quiero
edc65
@ edc65 Buen punto, déjame reformular eso.
Martin Ender

Respuestas:

10

CJam, 105 bytes

ri:A" __"e*A,2f*:B,[W1]{J+B:):B,{N1$S*"\/"J%A2*4$-:D*
0{;B{_1&!2mr+J*m1e>D(2*e<}%__:)&}g:B{'_t}/+@J+}*}fJ;

Nueva línea agregada para evitar el desplazamiento. Pruébalo en línea

Explicación:

Esta solución comienza cada línea como un zigzag, luego coloca N guiones bajos en ella, según su posición en la línea anterior y un par de reglas. Obtuve esto de una serie de observaciones mientras miraba la salida como una matriz de caracteres 2D simple:

  • cada línea tiene exactamente N guiones bajos
  • los guiones bajos se pueden reemplazar con / o \ para hacer un patrón de zigzag que se repita perfectamente ( /\en la mitad superior, \/en la mitad inferior)
  • los guiones bajos no pueden tocar los lados y no pueden ser adyacentes a otro guión bajo
  • Al pasar a la siguiente línea, la posición de cada subrayado cambia en -1, 0 o 1
  • más que eso, /_/solo puede cambiar en -1 o 0, y \_\solo puede cambiar en 0 o 1
  • para las posiciones iniciales de subrayado podemos usar un "_ "patrón o un " _"patrón, ambos están bien
  • las reglas anteriores son suficientes para obtener todas las inclinaciones

Así que decidí implementarlo manteniendo las posiciones de subrayado anteriores, modificándolas con un factor aleatorio (2 opciones para cada subrayado) y repitiendo hasta que se cumplan las reglas. En el proceso de optimización, cambié a las posiciones de subrayado en relación con el lado izquierdo del hexágono (sin incluir espacios).

ri:A" __"e*       read the input (A) and generate the top line
A,2f*:B           make an array [0 2 4 ... 2A-2] and store in B
                  these are the initial positions for the underscores
,                 B's length = A, used as the initial number of leading spaces
                  let's call it C
[W1]{…}fJ         for J in [-1 1] (top half, bottom half)
  J+              add J to C
  B:):B           increment the underscore positions (adjustment before each half)
  ,{…}*           repeat A times
    N1$S*         add a newline and C spaces
    "\/"J%        take "\/" and reverse it if J=-1 (zigzag pattern)
    A2*4$-:D*     calculate D=A*2-C and repeat the pattern
    0             dummy value (for the next loop)
    {…}g          do-while
      ;B          pop last value and push B
      {…}%        apply block to each item (say x)
        _1&!      duplicate x and calculate !(x&1) (for /_/ vs \_\)
        2mr+      randomly add 0 or 1
        J*m       multiply by J and subtract from x
        1e>       limit the minimum value to 1
        D(2*e<    and the maximum value to 2*(D-1)
      __:)&       check if the modified array has any adjacent values
    :B            store the new positions in B
    {'_t}/        place underscores over the zigzag pattern
    +@J+          bring C to the top and add J to it
;                 pop C

Antigua versión "3D", 189 bytes:

ri:A" __"e*aA4*S*aA2**+[0-2XXW1]:C;"/\_\\\/_/":D;A3m*{{C2/.f*:.+~
A(2*+:V;A+:U;2{UI+1$1$=4{_V+D4/I=@=t}/t}fI}:F~}/[0Y1WWW]:C;
"/_/\\\_\/":D;AaA*:B;A{A[_{_BI=e<)mr}fI]:B;{BQ={[PQR]F}fR}fQ}fPN*

Pruébalo en línea

aditsu
fuente
+1 por un trabajo increíble y también porque un voto más te pondría en 10k rep, pero principalmente por el increíble trabajo. (Oh, hola, mira eso. Felicidades por 10k :))
Alex A.
¡Un gran análisis sobre los patrones! Lo usaré para mi respuesta.
anatolyg
6

Python 2, 337 335 324 318 311 300 296 bytes

from random import*
n=input()
R=range(n*2)
b=[]
l=[]
for i in R:o=abs(i-n)-(i<n);b+=[o];l+=[list(' '*o+'\//\\'[i<n::2]*(n*2-o))]
for i in R[:n]:
 o=1;p=n+i*2
 for j in R:r=randint(0,p<n*3+i*2-j);p+=(r or-1)*(o==r);q=p<=b[j];o=r|q;p+=q;l[j][p]='_';b[j]=p+1
for s in[' '*n+'__'*n]+l:print''.join(s)

La idea es crear primero un hexágono de diamantes, como este:

  ____
 /\/\/\
/\/\/\/\
\/\/\/\/
 \/\/\/

Y luego llénalo con caminos de guiones bajos hacia abajo, como este:

  ____                          ____
 /_/\/\                        /\_\/\
/_/\/\/\    or maybe this:    /\/_/\/\
\_\/\/\/                      \/_/\/\/
 \_\/\/                        \_\/\/

El resultado final con todas las rutas agregadas se vería así:

  ____                          ____  
 /_/\_\                        /\_\_\ 
/_/\/_/\    or maybe this:    /\/_/\_\
\_\/_/\/                      \/_/\/_/
 \_\_\/                        \_\/_/ 

Se necesita bastante código para asegurarse de que estos caminos no se salgan de los límites ni se crucen entre sí.

El código sin golf:

# Initialize l with all diamonds
blocked = []
l = [[] for _ in range(n*2)]
for i in range(n*2):
    offset = n-i-1 if i<n else i-n
    blocked.append(offset)
    l[i] += ' '*offset + ('/\\' if i<n else '\/')*(2*n - offset)

# Generate the random _'s
for i in range(n):
    oldright = True
    pos = n + i*2
    for j in range(n*2):
        # Go randomly right (true) or left (false), except when you out of bounds on the right side
        right = randint(0, 1) and pos < n*3 + i*2 - j
        if right == oldright:
            pos += 1 if right else -1
        if pos <= blocked[j]:
            right = True
            pos += 1
        l[j][pos] = '_'
        blocked[j] = pos + 1
        oldright = right

# Print the result
print ' '*n + '__'*n
for s in l:
    print ''.join(s)
Matty
fuente
1
Acabo de notar que su salida parece incorrecta. Tienes triángulos en tus dos resultados exactos (arriba a la derecha y abajo a la derecha).
Martin Ender
1
@MartinEnder Los ejemplos mostraron solo una 'ruta de guiones bajos' para mostrar la idea del algoritmo. El resultado final tiene todas las rutas (en este caso 2), lo que elimina los triángulos. También agregué ejemplos del resultado final.
Matty
Ohhh ya veo, eso tiene sentido. Gracias por la aclaración.
Martin Ender
2
Creo que se puede acortar randint(0,1)*(p<n*3+i*2-j)a randint(0,p<n*3+i*2-j).
12Me21
Oooh si, gracias!
Matty
4

Perl, 174 168 166 161

#!perl -n
for$l(-$_..$_){$t=/_/?join'',map'/_'x($%=rand
1+(@z=/__?/g)).'/\\'.'_\\'x(@z-$%),split/\/\\/:__
x$_;$l>0&&$t!~s!^.(\\.*/).$!$1!?redo:print$"x abs$l-.5,$_=$t.$/}

Trate de mí .

nutki
fuente
Siempre parece generar el mismo mosaico (al menos en ideone)
aditsu
@aditsu, Ideone muestra un resultado en caché si solo hace clic en el enlace. Necesita bifurcar para ejecutarlo nuevamente.
nutki
2

JavaScript ( ES6 ), 376416494

Solo para estar allí ...

Esto construye todas las inclinaciones, luego elige una aleatoria. El tiempo para las inclinaciones 232848 para N = 4 es de ~ 45 segundos en mi computadora portátil. No probé N = 5.

Siendo EcmaScript 6, se ejecuta solo en Firefox.

F=n=>{
  for(i=s=r=b='';i<n;i++)
    s='\n'+b+'/\\'[R='repeat'](n-i)+'_\\'[R](n)+s,
    r+='\n'+b+'\\/'[R](n-i)+'_/'[R](n),
    b+=' ';
  for(h=[t=0],x=[s+r];s=x[t];t++)
    for(d='';!d[n*3];d+='.')
      if(l=s.match(r=RegExp("(\n"+d+"/)\\\\_(.*\n"+d+"\\\\)/_","g")))
        for(j=2<<l.length;j-=2;h[z]||(h[z]=x.push(z)))
          z=s.replace(r,(r,g,h)=>(k+=k)&j?g+'_/'+h+'_\\':r,k=1);
  return b+'__'[R](n)+x[Math.random()*t|0]
}


function go()
{
  var n = N.value | 0,
  t0 = performance.now(),
  r = F(n),
  t1 = performance.now();
  
  O.innerHTML = r+'\n\nTime (msec): '+(t1-t0)
}
N: <input id=N value=3><button onclick="go()">GO</button>
<pre id=O></pre>

edc65
fuente
En Cromo 42 me sale "no detectada SyntaxError: Unexpected token =>" y "no detectada ReferenceError: Go no está definido"
aditsu
1
@aditsu es ES6, Chrome: no Firefox: sí. ¿No es un hecho bien conocido?
edc65
No tenía ni idea, esperaba que Chromium usara el último y mejor JavaScript, lo que se llama aparentemente no. Gracias por la explicación.
aditsu
Lo ejecuté ahora en Firefox (31.5.3) y funciona para N = 1, 2 o 3, pero para N = 4 se ejecuta durante aproximadamente 10 segundos, termina y no muestra nada (y no hay ningún error en la consola )
aditsu
@aditsu no estoy seguro ... tal vez JavaScript en un sandbox se elimine silenciosamente cuando exceda el límite de tiempo dom.max_script_run_time. Es una preferencia global en aproximadamente: config, la mía está establecida en 30.
edc65
1

SmileBASIC, 241 bytes

INPUT N
T=N*2CLS?" "*N;"__"*N
DIM B[T]FOR I=-1TO N-1O=1P=N+I*2FOR J=0TO T-1IF I<0THEN O=ABS(J0N+.5)<<0B[J]=O?" "*O;MID$("\/\",J<N,2)*(T-O)ELSE R=P<N*3+I*2-J&&RND(2)P=P+(R*2-1)*(O==R)A=P<=B[J]R=R||A:P=P+A:LOCATE P,J+1?"_"B[J]=P+1O=R
NEXT
NEXT

Basada en la respuesta de Matty

12Me21
fuente