漂亮的图案抽屉(包括小立方体)


18

漂亮的花纹抽屉

早安PPCG!

前几天,当我试图帮助Stack Overflow上的某个人时,他的问题的一部分使我对这一挑战有所了解。

首先,检查以下形状:

在此处输入图片说明

其中所有黑色数字是形状中点的索引,所有深蓝色数字是这些点之间的链接的索引。

现在,给定一个从0x00000到0xFFFFF的十六进制数字,您需要在控制台中仅使用字符空间和“■”绘制形状(也可以使用字符“ o”)。

以下是输入十六进制数并输出形状的一些示例:

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

以下是有关其工作原理的一些解释:

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

您这里有20位,每一位都说明链接是否存在。

最高有效位(MSB)的索引为0(参考图片)或最低有效位(LSB)的索引为19(再次参考图片)。

这是示例中给出的第一个形状的工作方式:

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

意味着您将拥有以下现有链接:0,1,2,8,9,14,17,19。

如果您用这些数字突出显示参考图片上的线条,它将得到以下形状:

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

如果您需要更多帮助,这是一个简单的Python实现:

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)

当然,它并不是完美的,它应该做的时间很长,这就是您来这里的确切原因!

使这个程序短的荒谬:)

这是代码高尔夫,所以最短的答案会成功!


我们可以在行上打印一个尾随空格吗?您的示例包含它们。
orlp

是的:)允许
Sygmei

4
是否允许图形输出?
17Me21年

1
您需要输入十六进制还是可以使用十进制?
泰特斯(Titus),

1
也许所有的代码高尔夫球手都对我而言,但是该代码很难阅读……
Lynn

Answers:


8

的JavaScript(ES6),202个 188 187字节

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

怎么运行的

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

我们在g9行10个字符的网格上工作。网格最初填充有空格,每10个字符就有一个LineFeed。

每个片段由起始位置和方向定义。

路线编码如下:

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

每个段均编码为整数:

  • 方向存储在位#0和#1中
  • 起始位置存储在#2至#8位中

例如,段#3从位置55开始并使用第3方向。因此,它被编码为(55 << 2) | 3 == 223

以下是从段#19到段#0的整数列表:

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

从356开始经过增量编码后,它变为:

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

最终被编码为:

`0${x=',16,-54,21,-26,21,21,-26,21,166'}${x},16`

糟糕...忘记了两者之间的空格。解决它。
Arnauld

5

Python 3,289个字节

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

没有什么聪明的,只是硬编码。


无法"trq|t...a|eca".split("|")成为"tqr t...a eca".split()
Loovjo

@Loovjo Nope,.split()销毁||
orlp

3

Ruby,116个字节

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

这取决于我观察到的几种模式。首先,该模式每9行重复一次。其次,如果适当选择了水平线的起点,则x方向会连续地沿右,左,笔直循环。

取消测试程序

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

我相信有一个使用20个字符的字符串和一些解码来定义20行参数的112字节解决方案。如果有时间,我会稍后再尝试。


很好的解释!
Sygmei

2

PHP,142个 150 149字节

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

根据需要打印形状;即如果下部是空的,它将被切割。
用运行php -nr '<code>' <input>。不要给输入加前缀

在线测试

添加11个字节以免剪切:在,$r[80]=" "之后插入$r=""

编码说明

每条线都可以用起点和四个方向之一来描述。
在9x9网格上绘制,起始位置的范围是从0,08,4;或结合起来,从08*9+4=76。幸运的是,所有起点[0,4,8,36,40,44,72,76]都可以除以4;因此[0..3]可以将方向码压缩为0和1位->完全不需要移位。

为了便于计算光标移动,0采用东(仅垂直方向没有垂直移动)以及[1,2,3]西南,南,东南的偏移量9(对于垂直移动)加上[-1,0,1]-> [8,9,10]-> delta=code?code+7:1

第一行和最后一行的方向是东,导致代码范围从0到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];每个值的按位异或96导致可打印且无问题的ascii代码[96,100,98,99,101,102,103,105,106,68, 72,70,71,73,74,75,77,78,40,44]-> `dbcefgijDHFGIJKMN(,。该代码将LSB用于位0,而行0对应于MSB,因此该字符串必须反转。Finito。

分解

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

一些打高尔夫球的解释

  • 由于^96对低两位没有影响,因此在提取方向时可以忽略不计。因此,无需将值存储在变量中,该变量在游标init上节省了5个字节。
  • 使用~3而不是124保存一个字节,并允许下一次打高尔夫球:
  • $k=3$p赋值内部初始化循环计数器可节省两个字节
    ,并且不会损害前提条件(因为较高的值仍为一位)。
  • 将字符串用于结果具有最短的初始化和绘制可能:当在字符串末尾设置字符时,PHP将隐式将丢失的字符设置为空格。并且chunk_split是插入换行符的最短方法。
    我什至不想知道还要多花什么钱。
  • 7+($c&3?:-6)$c&3?$c%4+7:1。短一字节。
  • 增加了hexdec()(8个字节)以满足输入限制。

2

JavaScript中,184个 183 178 168 167字节

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>

最初是206个字节,但是@Arnauld的回答启发了我研究一维数组解决方案。编辑:由于@ edc65,节省了1个字节。感谢@Arnauld,节省了5个 15字节。通过调整字符选择来节省更多的字节。


[0,1,2,3,4]
edc65

我认为您可以使用[67,65,52,36,51,50,34,49,48,35,33,20,4,19,18,2,17,16,3,1]和节省4个字节[0,2,4,6,8].map(i=>a[(e&102)*4+(e&17||15)*i]='o')
Arnauld

1
或者,您可以使用[..."ecVFUTDSREC6&54$32%#"][0,2,4,6,8].map(i=>a[(e&102)*4+(e&17||15)*i]='o',e=e.charCodeAt()-34)保存10个以上的字节。
Arnauld

@Arnauld您似乎已将节省的金额低估了1,而且我还通过使用~代替来额外节省了一个字节-34(可惜我对`\`犯规,这就是为什么我不保存2个字节)。
尼尔,

我想知道是否可以用ASCII字符#220替换此'\'。
Arnauld

1

批次,491字节

@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 

注意:最后一行以空格结尾。将带if条件的条件变量放入for循环内已成批处理,因此需要它自己的子例程。由于它什么都看不见,因此我进入了它退出。将~外循环中的字符串取消引号,使内循环可以循环编号。数字只是o应该绘制s的所有位置的位掩码。


1

C,267个 262 260 256个字符

将转义计数为1个字符

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是查找,指的是在其中放入“ o”的框。

在线尝试!


1

Befunge,468个字节

~: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%

在线尝试!

第一行从stdin读取一个字符串,并将其评估为十六进制数。其余代码本质上只是在网格的x / y坐标上的双循环,并通过大量的布尔计算确定是否o应为每个位置输出an 。

对于20个网格点中的每一个,基本上都有一个单独的条件,例如(前四个):

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

然后,当我们计算完所有20个之后,我们便对这些批次进行或运算,如果结果为true,则输出a o,否则输出一个空格。

Befunge没有位操作的任何方式,因此要从输入中提取位,我们只是反复进行评估n%2,然后逐步n/=2进行20个条件计算。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.