El hermoso cajón de patrones (cubitos incluidos)

18

El hermoso cajón de patrones

Buenos dias PPCG!

El otro día, cuando estaba tratando de ayudar a alguien en Stack Overflow, una parte de su problema me dio una idea para este desafío.

En primer lugar, verifique la siguiente forma:

ingrese la descripción de la imagen aquí

Donde todos los números negros son el índice de los puntos en la forma y todos los números azul oscuro son el índice de los enlaces entre los puntos.

Ahora, dado un número hexadecimal de 0x00000 a 0xFFFFF, debe dibujar una forma en la consola usando solo el espacio de caracteres y "■" (también está bien usar el carácter "o").

Estos son algunos ejemplos en los que se ingresa el número hexadecimal y se genera la forma:

0xE0C25 :
■ ■ ■ ■ ■ ■ ■ ■ ■ 
■               ■ 
■               ■ 
■               ■ 
■ ■ ■ ■ ■       ■ 
        ■       ■ 
        ■       ■ 
        ■       ■ 
        ■ ■ ■ ■ ■
0xC1043 :
■ ■ ■ ■ ■ ■ ■ ■ ■ 
              ■   
            ■     
          ■       
        ■         
      ■           
    ■             
  ■               
■ ■ ■ ■ ■ ■ ■ ■ ■ 
0xE4F27 :
■ ■ ■ ■ ■ ■ ■ ■ ■ 
■       ■       ■ 
■       ■       ■ 
■       ■       ■ 
■ ■ ■ ■ ■ ■ ■ ■ ■ 
■       ■       ■ 
■       ■       ■ 
■       ■       ■ 
■ ■ ■ ■ ■ ■ ■ ■ ■ 
0xF1957 :
■ ■ ■ ■ ■ ■ ■ ■ ■ 
■ ■           ■ ■ 
■   ■       ■   ■ 
■     ■   ■     ■ 
■       ■       ■ 
■     ■   ■     ■ 
■   ■       ■   ■ 
■ ■           ■ ■ 
■ ■ ■ ■ ■ ■ ■ ■ ■ 
0xD0C67 :
■ ■ ■ ■ ■ ■ ■ ■ ■ 
  ■             ■ 
    ■           ■ 
      ■         ■ 
■ ■ ■ ■ ■       ■ 
      ■ ■       ■ 
    ■   ■       ■ 
  ■     ■       ■ 
■ ■ ■ ■ ■ ■ ■ ■ ■ 
0x95E30 :
■ ■ ■ ■ ■       ■ 
  ■     ■     ■ ■ 
    ■   ■   ■   ■ 
      ■ ■ ■     ■ 
■ ■ ■ ■ ■ ■ ■ ■ ■ 
        ■ ■       
        ■   ■     
        ■     ■   
        ■       ■ 
0x95622 :
■ ■ ■ ■ ■       ■ 
  ■     ■     ■   
    ■   ■   ■     
      ■ ■ ■       
■ ■ ■ ■ ■ ■ ■ ■ ■ 
        ■         
        ■         
        ■         
■ ■ ■ ■ ■         
0xC5463 : 
■ ■ ■ ■ ■ ■ ■ ■ ■ 
        ■     ■   
        ■   ■     
        ■ ■       
■ ■ ■ ■ ■         
      ■ ■         
    ■   ■         
  ■     ■         
■ ■ ■ ■ ■ ■ ■ ■ ■ 
0xE5975 :
■ ■ ■ ■ ■ ■ ■ ■ ■ 
■       ■     ■ ■ 
■       ■   ■   ■ 
■       ■ ■     ■ 
■       ■       ■ 
■     ■ ■ ■     ■ 
■   ■   ■   ■   ■ 
■ ■     ■     ■ ■ 
■       ■ ■ ■ ■ ■ 
0xB5E75 :
■ ■ ■ ■ ■       ■ 
■ ■     ■     ■ ■ 
■   ■   ■   ■   ■ 
■     ■ ■ ■     ■ 
■ ■ ■ ■ ■ ■ ■ ■ ■ 
      ■ ■ ■     ■ 
    ■   ■   ■   ■ 
  ■     ■     ■ ■ 
■       ■ ■ ■ ■ ■ 
0xF4C75 :
■ ■ ■ ■ ■ ■ ■ ■ ■ 
■ ■     ■       ■ 
■   ■   ■       ■ 
■     ■ ■       ■ 
■ ■ ■ ■ ■       ■ 
      ■ ■ ■     ■ 
    ■   ■   ■   ■ 
  ■     ■     ■ ■ 
■       ■ ■ ■ ■ ■
0xF5D75 :
■ ■ ■ ■ ■ ■ ■ ■ ■ 
■ ■     ■     ■ ■ 
■   ■   ■   ■   ■ 
■     ■ ■ ■     ■ 
■ ■ ■ ■ ■       ■ 
■     ■ ■ ■     ■ 
■   ■   ■   ■   ■ 
■ ■     ■     ■ ■ 
■       ■ ■ ■ ■ ■ 

Aquí hay algunas explicaciones sobre cómo funciona:

0xFFFFF(16) = 1111 1111 1111 1111 1111(2)

Aquí tiene 20 bits, cada bit dice si existe un enlace o no.

El índice del bit más significativo (MSB) es 0 (referencia de imagen) o el bit menos significativo (LSB) es 19 (referencia de imagen nuevamente).

Así es como funciona para la primera forma dada como ejemplo:

0xE0C25(16) = 1110 0000 1100 0010 0101(2)

Lo que significa que tendrá los siguientes enlaces existentes: 0,1,2,8,9,14,17,19.

Si resalta las líneas en la imagen de referencia con esos números, le dará esta forma:

■ ■ ■ ■ ■ ■ ■ ■ ■ 
■               ■ 
■               ■ 
■               ■ 
■ ■ ■ ■ ■       ■ 
        ■       ■ 
        ■       ■ 
        ■       ■ 
        ■ ■ ■ ■ ■

Aquí hay una implementación de Python simple y sin golf si necesitas más ayuda:

patterns = [
  0xE0C25, 0xC1043, 0xE4F27, 0xF1957, 
  0xD0C67, 0x95E30, 0x95622, 0xC5463, 
  0xE5975, 0xB5E75, 0xF4C75, 0xF5D75
]

def printIfTrue(condition, text = "■ "):
  if condition:
    print(text, end="")
  else:
    print(" "*len(text), end="")

def orOnList(cube, indexes):
  return (sum([cube[i] for i in indexes]) > 0)

def printPattern(pattern):
  cube = [True if n == "1" else False for n in str(bin(pattern))[2::]]
  for y in range(9):
    if y == 0: printIfTrue(orOnList(cube, [0, 2, 3]))
    if y == 4: printIfTrue(orOnList(cube, [2, 4, 9, 11, 12]))
    if y == 8: printIfTrue(orOnList(cube, [11, 13, 18]))
    if y in [0, 4, 8]:
      printIfTrue(cube[int((y / 4) + (y * 2))], "■ ■ ■ ")
      if y == 0: printIfTrue(orOnList(cube, [0, 1, 4, 5, 6]))
      if y == 4: printIfTrue(orOnList(cube, [3, 5, 7, 9, 10, 13, 14, 15]))
      if y == 8: printIfTrue(orOnList(cube, [12, 14, 16, 18, 19]))
      printIfTrue(cube[int((y / 4) + (y * 2)) + 1], "■ ■ ■ ")
    elif y in [1, 5]:
      for i in range(7):
        if i in [2, 5]:
          print(" ", end=" ")
        printIfTrue(cube[y * 2 + (1 - (y % 5)) + i])
    elif y in [2, 6]:
      for i in range(5):
        if i in [1, 2, 3, 4]:
          print(" ", end=" ")
        if i in [1, 3]:
          if i == 1 and y == 2:
            printIfTrue(orOnList(cube, [3, 4]))
          elif i == 3 and y == 2:
            printIfTrue(orOnList(cube, [6, 7]))
          if i == 1 and y == 6:
            printIfTrue(orOnList(cube, [12, 13]))
          elif i == 3 and y == 6:
            printIfTrue(orOnList(cube, [15, 16]))
        else:
          printIfTrue(cube[(y * 2 - (1 if y == 6 else 2)) + i + int(i / 4 * 2)])
    elif y in [3, 7]:
      for i in range(7):
        if i in [2, 5]:
          print("  ", end="")
        ri, swap = (y * 2 - 2) + (1 - (y % 5)) + i, [[3, 6, 12, 15], [4, 7, 13, 16]]
        if ri in swap[0]: ri = swap[1][swap[0].index(ri)]
        elif ri in swap[1]: ri = swap[0][swap[1].index(ri)]
        printIfTrue(cube[ri])
    if y == 0: printIfTrue(orOnList(cube, [1, 7, 8]))
    if y == 4: printIfTrue(orOnList(cube, [6, 8, 10, 16, 17]))
    if y == 8: printIfTrue(orOnList(cube, [15, 17, 19]))
    print()

for pattern in patterns:
  printPattern(pattern)

Por supuesto, no es perfecto y es bastante largo para lo que debería hacer, ¡y esa es la razón exacta por la que estás aquí!

Haciendo este programa ridículamente corto :)

Este es el código de golf, por lo que gana la respuesta más corta.

Sygmei
fuente
¿Podemos imprimir un solo espacio final en las líneas? Tus ejemplos los contienen.
orlp
Sí :) Está permitido
Sygmei
44
¿Se permite la salida gráfica?
12Me21
1
¿Requiere entrada hexadecimal o está bien decimal?
Titus
1
Tal vez todo el código de golf me está afectando, pero ese código es doloroso de leer ...
Lynn

Respuestas:

8

JavaScript (ES6), 202 188 187 bytes

let f =

n=>`0${x=',16,-54,21,-26,21,21,-26,21,166'}${x},16`.split`,`.map((d,i)=>(k-=d,n)>>i&1&&[..."ooooo"].map(c=>g[p-=(k&3||9)^8]=c,p=k>>2),g=[...(' '.repeat(9)+`
`).repeat(9)],k=356)&&g.join``

console.log(f(0xE0C25))
console.log(f(0xC1043))
console.log(f(0xE4F27))
console.log(f(0xF1957))

Cómo funciona

n =>                                                 // given 'n':
  `0${x = ',16,-54,21,-26,21,21,-26,21,166'}${x},16` // build the list of delta values
  .split`,`.map((d, i) =>                            // split the list and iterate
    (k -= d, n) >> i & 1 &&                          // update 'k', test the i-th bit of 'n'
    [..."ooooo"].map(c =>                            // if the bit is set, iterate 5 times:
      g[                                             // 
        p -= (k & 3 || 9) ^ 8                        // compute the direction and update 'p'
      ] = c,                                         // write a 'o' at this position
      p = k >> 2                                     // initial value of 'p'
    ),                                               //
    g = [...(' '.repeat(9) + `\n`).repeat(9)],       // initialization of the 'g' array
    k = 356                                          // initial value of 'k'
  )                                                  //
  && g.join``                                        // yield the final string

Trabajamos en una cuadrícula gde 9 filas de 10 caracteres. La cuadrícula se llena inicialmente con espacios, con un LineFeed cada 10 caracteres.

Cada segmento está definido por una posición inicial y una dirección.

Las instrucciones están codificadas de la siguiente manera:

ID | Dir.| Offset
---|-----|-------
 0 |  W  |  -1        Offset encoding formula:
 1 | NE  |  -9        -((ID || 9) ^ 8)
 2 |  N  |  -10
 3 | NW  |  -11

Cada segmento está codificado como un entero:

  • la dirección se almacena en los bits # 0 y # 1
  • la posición inicial se almacena en los bits 2 a 8

Por ejemplo, el segmento # 3 comienza en la posición 55 y usa la tercera dirección. Por lo tanto, está codificado como (55 << 2) | 3 == 223.

A continuación se muestra la lista resultante de enteros, desde el segmento # 19 al segmento # 0:

356,340,394,373,399,378,357,383,362,196,180,234,213,239,218,197,223,202,36,20

Una vez codificado en delta, comenzando en 356, se convierte en:

0,16,-54,21,-26,21,21,-26,21,166,16,-54,21,-26,21,21,-26,21,166,16

Que finalmente se codifica como:

`0${x=',16,-54,21,-26,21,21,-26,21,166'}${x},16`
Arnauld
fuente
Vaya ... Olvidé los espacios intermedios. Arreglando eso.
Arnauld
5

Python 3, 289 bytes

def f(n):
 for r in range(9):print(*(" o"[any(n&1<<ord(c)-97for c in"trq|t|t|t|tspon|s|s|s|sml|r|q||p|o|n||m|l|r||qp||o||nm||l|r|p||q|o|m||n|l|rpkih|k|k|k|qomkjgfe|j|j|j|nljdc|i|h||g|f|e||d|c|i||hg||f||ed||c|i|g||h|f|d||e|c|igb|b|b|b|hfdba|a|a|a|eca".split("|")[r*9+c])]for c in range(9)))

Nada inteligente, solo codificación.

orlp
fuente
No pudo "trq|t...a|eca".split("|")ser "tqr t...a eca".split()?
Loovjo
@Loovjo No, .split()destruye ||.
orlp
3

Ruby, 116 bytes

->n{s=[' '*17]*9*$/
20.times{|i|j=i%9
n>>19-i&1>0&&5.times{|k|s[i/9*72+(j>1?~-j/3*8+k*18:j*16)+k*(2--j%3*2)]=?O}}
s}

Esto se basa en un par de patrones que observé. En primer lugar, el patrón se repite cada 9 líneas. En segundo lugar, si los puntos de inicio de las líneas horizontales se eligen apropiadamente, las direcciones x cambian continuamente de derecha a izquierda, recta.

Sin golf en el programa de prueba

f=->n{
   s=[' '*17]*9*$/                    #Setup a string of 9 newline separated lines of 17 spaces.
   20.times{|i|                       #For each of the 20 bits..
     j=i%9                            #The pattern repeats every 9 bits.
     n>>19-i&1>0&&                    #If the relevant bit is set,
     5.times{|k|                      #draw each of the 5 points on the relevant line.
       s[i/9*72+                      #There are 9 lines starting on each row. Row y=0 starts at 0 in the string, row y=1 at 72, etc.
       (j>1?~-j/3*8+k*18:j*16)+       #~-j=j-1. For j=2..8, the starting x coordinates are (0,0,1,1,1,2,2)*8. For j=0 and 1 starting x coordinates are 0 and 16. 
       k*(2--j%3*2)                   #From the starting points, draw the lines right,left,straight. Down movement if applicable is given by conditional k*18 above.
       ]=?O                           #Having described the correct index to modify, overwrite it with a O character.
     }
   }
s}                                    #Return the string.


[0xE0C25, 0xC1043, 0xE4F27, 0xF1957, 
  0xD0C67, 0x95E30, 0x95622, 0xC5463, 
  0xE5975, 0xB5E75, 0xF4C75, 0xF5D75].map{|m|puts f[m],'---------'}

Creo que hay una solución de 112 bytes que usa una cadena de 20 caracteres y algo de decodificación para definir los parámetros de las 20 líneas. Intentaré esto más tarde si tengo tiempo.

Level River St
fuente
Buena explicación!
Sygmei
2

PHP, 142 150 149 bytes

for($r="";$c=ord(",(NMKJIGFHDjigfecbd`"[$i]);)if(hexdec($argv[1])>>$i++&1)for($p=96^$c&~$k=3;$k++<8;$p+=7+($c&3?:-6))$r[$p]=o;echo chunk_split($r,9);

imprime la forma tanto como sea necesario; es decir, si la parte inferior está vacía, se cortará.
Corre con php -nr '<code>' <input>. No prefijo entrada

Pruébelo en línea

Agregue 11 bytes para no cortar: inserte ,$r[80]=" "después $r="".

codificación explicada

Cada línea se puede describir con un punto de partida y una de las cuatro direcciones.
Dibujando en una cuadrícula de 9x9, la posición inicial varía de 0,0a 8,4; o, combinado, de 0a 8*9+4=76. Afortunadamente, todos los puntos de partida [0,4,8,36,40,44,72,76]son divisibles por 4; por lo que el código de dirección [0..3]puede exprimirse en los bits 0 y 1 -> no se necesita ningún desplazamiento.

Para un cálculo fácil del movimiento del cursor, 0se toma para el este (solo dirección sin movimiento vertical) y [1,2,3]para el sudoeste, sur, sudeste, donde el desplazamiento es 9(para el movimiento vertical) más [-1,0,1]-> [8,9,10]-> delta=code?code+7:1.

La dirección para la primera y última línea es este, lo que da como resultado códigos que van de 0 a 76 [0+0,4+0,0+2,0+3,4+1,4+2,4+3,8+1,8+2,...,44+1,44+2,72+0,76+0]; y bitor xor 96 en cada valor da como resultado códigos ascii imprimibles y sin problemas [96,100,98,99,101,102,103,105,106,68, 72,70,71,73,74,75,77,78,40,44]-> `dbcefgijDHFGIJKMN(,. El código utiliza el LSB para el bit 0, mientras que la línea 0 corresponde al MSB, por lo que la cadena debe invertirse. Finito

Descompostura

for($r="";                  // init result string, loop through line codes
    $c=ord(",(NMKJIGFHDjigfecbd`"[$i]);)
    if(hexdec($argv[1])>>$i++&1)// if bit $i is set, draw line 19-$i:
        for($p=96^$c&~$k=3          // init $k to 3, init cursor to value&~3
            ;$k++<8;                // loop 5 times
            $p+=7+($c&3?:-6)            // 2. map [0,1,2,3] to [1,8,9,10], move cursor
        )
            $r[$p]=o;                   // 1. plot
echo chunk_split($r,9);     // insert a linebreak every 9 characters, print

algo de golf explicado

  • Como ^96no tiene efecto en los dos bits inferiores, puede ignorarse al extraer la dirección; Por lo tanto, no es necesario almacenar el valor en una variable, lo que ahorra 5 bytes en el cursor init.
  • Usar en ~3lugar de 124guardar un byte y permite el próximo golf:
  • La inicialización del contador de bucle $k=3dentro de la $pasignación ahorra dos bytes
    y no daña la condición previa (ya que el valor superior todavía tiene un dígito).
  • El uso de una cadena para el resultado tiene la inicialización y el trazado más cortos posibles: cuando un carácter se establece más allá del final de una cadena, PHP implícitamente establece los caracteres que faltan en el espacio. Y chunk_splites la forma más corta de insertar los saltos de línea.
    Ni siquiera quiero saber cuánto más tomaría cualquier otra cosa.
  • 7+($c&3?:-6)es un byte más corto que $c&3?$c%4+7:1.
  • Agregado hexdec()(8 bytes) para satisfacer la restricción de entrada.
Tito
fuente
2

JavaScript, 184 183 178 168 167 bytes

f=
n=>[...`<>K[LM]NO\\^k{lm}no|~`].map((e,i)=>n>>i&1&&[0,2,4,6,8].map(i=>a[(e&102)*4+(e&17||15)*i]=`o`,e=~e.charCodeAt()),a=[...(` `.repeat(31)+`
`).repeat(9)])&&a.join``
<input oninput=o.textContent=f(+this.value)><pre id=o>

Originalmente tenía 206 bytes, pero la respuesta de @ Arnauld me inspiró a investigar una solución de matriz unidimensional. Editar: Guardado 1 byte gracias a @ edc65. Guardado 5 15 bytes gracias a @Arnauld. Se guardó un byte adicional al ajustar la elección de los personajes.

Neil
fuente
[0,1,2,3,4]es más corto
edc65
Creo que puede guardar 4 bytes usando [67,65,52,36,51,50,34,49,48,35,33,20,4,19,18,2,17,16,3,1]y[0,2,4,6,8].map(i=>a[(e&102)*4+(e&17||15)*i]='o')
Arnauld
1
O puede usar [..."ecVFUTDSREC6&54$32%#"]y [0,2,4,6,8].map(i=>a[(e&102)*4+(e&17||15)*i]='o',e=e.charCodeAt()-34)para guardar 10 bytes más.
Arnauld
@Arnauld Parece que no has contado lo que ahorraste en 1, y también me las arreglé para jugar un byte extra usando en ~lugar de -34(lamentablemente me caigo de '\', por eso no guardo 2 bytes).
Neil
Me pregunto si podría reemplazar este '\' con el carácter ASCII # 220.
Arnauld
1

Lote, 491 bytes

@set n=%1
@for %%i in ("720896 524288 524288 524288 843776 262144 262144 262144 268288" "131072 65536 0 32768 16384 8192 0 4096 2048" "131072 0 98304 0 16384 0 12288 0 2048" "131072 32768 0 65536 16384 4096 0 8192 2048" "165248 1024 1024 1024 89312 512 512 512 10764" "256 128 0 64 32 16 0 8 4" "256 0 192 0 32 0 24 0 4" "256 64 0 128 32 8 0 16 4" "322 2 2 2 171 1 1 1 17")do @set s=&(for %%j in (%%~i)do @set/am=%1^&%%j&call:c)&call echo(%%s%%
:c
@if %m%==0 (set s=%s%  )else set s=%s%o 

Nota: La última línea termina con un espacio. Poner un ifcondicional con una variable dentro de un forbucle está más allá del lote, por lo que necesita su propia subrutina. Como no hace nada visible, caigo en él para salir. Las ~comillas entre comillas en el bucle externo permiten que el bucle interno recorra los números. Los números son simplemente las máscaras de bits para todos los lugares donde se odeben dibujar s.

Neil
fuente
1

C, 267 262 260 256 caracteres

Contando escapes como 1 personaje

void f(int i){char*k="\0\x1\x2\x3\x4\x4\x5\x6\x7\x8\0\x9\x12\x1b\x24\0\xa\x14\x1e\x28\x4\xc\x14\x1c\x2d\x4\xd\x16\x1f\x28\x4\xe\x18\x22\x2c\x8\x10\x18\x20\x28\x8\x11\x1a\x23\x2c\x24\x25\x26\x27\x28\x28\x29\x2a\x2b\x2c\x24\x2d\x36\x3f\x48\x24\x2e\x38\x42\x4c\x28\x30\x38\x40\x48\x28\x31\x3a\x43\x4c\x28\x31\x3a\x43\x4c\x28\x32\x3c\x46\x50\x2c\x35\x3e\x47\x50\x48\x49\x4a\x4b\x4c\x4c\x4d\x4e\x4f\x50";for(int n=0,s,l;n<81;!(++n%9)&&putchar(10))for(s=l=0;s<20;!(++l%5||++s^20)&&putchar(32))if(i<<s&1<<19&&k[l]==n&&putchar(111))break;}

k es una búsqueda que se refiere a qué cuadros poner una 'o'.

Pruébalo en línea!

Ahemone
fuente
1

Befunge, 468 bytes

~:85+`!#v_86*-:9`7*-48*%\82**+
3%2:/2\<$v0%2:/2\*g02*!g03%2:/2\*!+4g07%2:/2\*g02*!-8g06%2:/2\*g02*!-4g0
g!*20g*^00>50g*\2/:2%00g8-!*40g*\2/:2%30g8-!*20g*\2/:2%60g66+-!*\2/:2%70
`\5:p00:<g^*!-8g00%2:\-10:\p07-g00:p06+g00:p05`3:p04`\5:p03:<0\p02`3:p01
#o 8`#@_^4>*50g*\2/2%00g!*40g*0\>:#<1#\+_$!1+4g,48*,\1+:8`!#^_55+,$\1+:
g03%2:/2<-^!g00%2:/2\*g01*!g03%2:/2\*g01*!g07%2:/2\*!-4g06%2:/2\*g01*!-4
70g4-!*\^>!*50g*\2/:2%00g4-!*40g*\2/:2%30g8-!*10g*\2/:2%60g8-!*10g*\2/:2%

Pruébalo en línea!

La primera línea lee una cadena de stdin, evaluándola como un número hexadecimal. El resto del código es esencialmente un doble bucle sobre las coordenadas x / y de la cuadrícula, con un cálculo booleano masivo que determina si se odebe emitir un para cada ubicación.

Básicamente, hay una condición separada para cada uno de los 20 puntos de la cuadrícula, por ejemplo (los primeros cuatro):

(y==0) * (x<5) * bit0
(y==0) * (x>3) * bit1
(x==0) * (y<5) * bit2
(x==y) * (y<5) * bit3

Y luego, una vez que hemos calculado los 20, O juntos, y si ese resultado es verdadero, sacamos un o, de lo contrario, sacamos un espacio.

Befunge no tiene nada en el camino de las operaciones de manipulación de bits, por lo que para extraer los bits de la entrada, solo estamos evadiendo repetidamente n%2y luego a n/=2medida que avanzamos a través de los 20 cálculos de condición.

James Holderness
fuente