A gaveta de padrão bonito (cubos pequenos incluídos)

18

A linda gaveta de padrões

Bom dia PPCG!

Outro dia, quando eu estava tentando ajudar alguém no Stack Overflow, uma parte do problema dele me deu uma ideia para esse desafio.

Antes de tudo, verifique a seguinte forma:

insira a descrição da imagem aqui

Onde todos os números em preto são o índice dos pontos na forma e todos os números em azul escuro são o índice dos links entre os pontos.

Agora, dado um número hexadecimal de 0x00000 a 0xFFFFF, você precisa desenhar uma forma no console usando apenas o espaço de caracteres e "■" (usar o caractere "o" também é bom).

Aqui estão alguns exemplos em que o número hexadecimal é inserido e a forma é gerada:

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

Aqui estão algumas explicações sobre como isso funciona:

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

Você aqui tem 20 bits, cada bit diz se um link existe ou não.

O índice do bit mais significativo (MSB) é 0 (referência à imagem) ou o bit menos significativo (LSB) é 19 (referência à imagem novamente).

Veja como ele funciona para a primeira forma, como exemplo:

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

O que significa que você terá os seguintes links existentes: 0,1,2,8,9,14,17,19.

Se você destacar as linhas na imagem de referência com esses números, ele terá a seguinte forma:

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

Aqui está uma implementação Python simples e simples, se você precisar de mais ajuda:

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)

É claro que não é perfeito e é muito longo para o que deve fazer, e essa é a razão exata pela qual você está aqui!

Tornando este programa ridiculamente curto :)

Isso é código-golfe, então a resposta mais curta vence!

Sygmei
fonte
Podemos imprimir um único espaço à direita em linhas? Seus exemplos os contêm.
orlp
Sim :) É permitido
Sygmei
4
A saída gráfica é permitida?
12Me21
1
Você precisa de entrada hexadecimal ou é decimal ok?
Titus
1
Talvez toda a golf código está apenas começando para mim, mas que o código é doloroso de ler ...
Lynn

Respostas:

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))

Como 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

Trabalhamos em uma grade gde 9 linhas de 10 caracteres. A grade é inicialmente preenchida com espaços, com um LineFeed a cada 10 caracteres.

Cada segmento é definido por uma posição inicial e uma direção.

As instruções são codificadas da seguinte forma:

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

Cada segmento é codificado como um número inteiro:

  • a direção é armazenada nos bits 0 e 1
  • a posição inicial é armazenada nos bits 2 a 8

Por exemplo, o segmento 3 começa na posição 55 e usa a 3ª direção. Portanto, é codificado como (55 << 2) | 3 == 223.

Abaixo está a lista resultante de números inteiros, do segmento 19 ao segmento 0:

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

Uma vez codificado em delta, começando em 356, ele se torna:

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

Finalmente codificado como:

`0${x=',16,-54,21,-26,21,21,-26,21,166'}${x},16`
Arnauld
fonte
Opa ... Esqueceu os espaços intermediários. Consertando isso.
Arnauld 27/01
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, apenas codificado.

orlp
fonte
Não poderia se "trq|t...a|eca".split("|")tornar "tqr t...a eca".split()?
Loovjo 27/01
@Loovjo Não, .split()destrói ||.
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}

Isso se baseia em alguns padrões que observei. Primeiro, o padrão se repete a cada 9 linhas. Em segundo lugar, se os pontos de partida das linhas horizontais são escolhidos adequadamente, as direções x circulam continuamente pela direita, esquerda e reta.

Ungolfed in program program

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],'---------'}

Acredito que exista uma solução de 112 bytes usando uma cadeia de 20 caracteres e alguma decodificação para definir os parâmetros das 20 linhas. Vou tentar isso mais tarde se tiver tempo.

Level River St
fonte
Boa explicação!
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 a forma o quanto for necessário; isto é, se a parte inferior estiver vazia, será cortada.
Corra com php -nr '<code>' <input>. Não prefixe a entrada

Teste on-line

Adicione 11 bytes para não cortar: Insira ,$r[80]=" "depois $r="".

codificação explicada

Cada linha pode ser descrita com um ponto de partida e uma das quatro direções.
Desenhando em uma grade 9x9, a posição inicial varia de 0,0a 8,4; ou, combinado, de 0a 8*9+4=76. Felizmente, todos os pontos de partida [0,4,8,36,40,44,72,76]são divisíveis por 4; então o código de direção [0..3]pode ser espremido nos bits 0 e 1 -> nenhuma mudança necessária.

Para um cálculo fácil do movimento do cursor, 0é utilizado o leste (somente direção sem movimento vertical) e [1,2,3]sudoeste, sul e sudeste, onde o deslocamento é 9(para o movimento vertical) mais [-1,0,1]-> [8,9,10]-> delta=code?code+7:1.

A direção da primeira e da última linha sendo leste, que resulta em códigos que variam 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]; e bit a bit xor 96 em cada valor resulta em códigos ascii imprimíveis e sem problemas [96,100,98,99,101,102,103,105,106,68, 72,70,71,73,74,75,77,78,40,44]-> `dbcefgijDHFGIJKMN(,. O código usa o LSB para o bit 0, enquanto a linha 0 corresponde ao MSB, portanto, a string deve ser revertida. Finito.

demolir

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

algum golfe explicou

  • Como ^96não tem efeito nos dois bits inferiores, pode ser ignorado ao extrair a direção; portanto, não há necessidade de armazenar o valor em uma variável, que economiza 5 bytes no init do cursor.
  • Usar em ~3vez de 124salva um byte e permite o próximo jogo de golfe:
  • A inicialização do contador de loop $k=3dentro da $patribuição economiza dois bytes
    e não prejudica a pré-condição (já que o valor superior ainda possui um dígito).
  • O uso de uma string para o resultado tem a menor inicialização e plotagem possível: Quando um caractere é definido além do final de uma string, o PHP define implicitamente os caracteres ausentes para o espaço. E chunk_splité a maneira mais curta de inserir as quebras de linha.
    Eu nem quero saber quanto mais qualquer coisa levaria.
  • 7+($c&3?:-6)é um byte menor que $c&3?$c%4+7:1.
  • Adicionado hexdec()(8 bytes) para satisfazer a restrição de entrada.
Titus
fonte
2

JavaScript, 184 183 178 168 167 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>

Era originalmente de 206 bytes, mas a resposta da @ Arnauld me inspirou a investigar uma solução de matriz unidimensional. Editar: salvou 1 byte graças a @ edc65. Guardado 5 15 bytes graças a @Arnauld. Economizou mais um byte, aprimorando a escolha dos caracteres.

Neil
fonte
[0,1,2,3,4]é mais curto
edc65 28/01
Eu acho que você pode salvar 4 bytes usando [67,65,52,36,51,50,34,49,48,35,33,20,4,19,18,2,17,16,3,1]e[0,2,4,6,8].map(i=>a[(e&102)*4+(e&17||15)*i]='o')
Arnauld 28/01
1
Ou você pode usar [..."ecVFUTDSREC6&54$32%#"]e [0,2,4,6,8].map(i=>a[(e&102)*4+(e&17||15)*i]='o',e=e.charCodeAt()-34)salvar mais 10 bytes.
Arnauld 28/01
@ Arnauld Você parece ter subconstruído sua economia em 1, e eu também consegui extrair um byte extra usando em ~vez de -34(infelizmente, eu entro em \ \, e é por isso que não economizo 2 bytes).
Neil
Gostaria de saber se você poderia substituir esse '\' pelo caractere ASCII # 220.
precisa saber é o seguinte
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: A última linha termina com um espaço. Colocar uma ifcondicional com uma variável dentro de um forloop está além do lote, de modo que precisa de sua própria sub-rotina. Como não faz nada visível, caio nele para sair. Entre ~aspas as strings no loop externo, permitindo que o loop interno faça um loop sobre os números. Os números são simplesmente as máscaras de bits para todos os lugares onde os devem ser desenhados.

Neil
fonte
1

C, 267 262 260 256 caracteres

A contagem de escapes como 1 caractere

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 é uma pesquisa que se refere a quais caixas colocar um 'o'.

Experimente online!

Ahemone
fonte
1

Anterior, 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%

Experimente online!

A primeira linha lê uma string de stdin, avaliando-a como um número hexadecimal. O restante do código é essencialmente apenas um loop duplo sobre as coordenadas x / y da grade, com um cálculo booleano massivo que determina se um odeve ser gerado para cada local.

Há basicamente uma condição separada para cada um dos 20 pontos da grade, por exemplo (os quatro primeiros):

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

E depois que calculamos todos os 20 deles, OR OU o lote juntos, e se esse resultado for verdadeiro, produzimos a o, caso contrário, produzimos um espaço.

O Befunge não possui nada no caminho das operações de manipulação de bits; portanto, para extrair os bits da entrada, estamos apenas avaliando repetidamente n%2e, depois n/=2, avançando nos cálculos das 20 condições.

James Holderness
fonte