美しい模様の引き出し(小さな立方体が含まれています)


18

美しい模様の引き出し

おはようございますPPCG!

先日、私がStack Overflowで誰かを助けようとしたとき、彼の問題の一部がこの挑戦のアイデアを与えてくれました。

まず、次の形状を確認します。

ここに画像の説明を入力してください

ここで、すべての黒の数字はシェイプ内のポイントのインデックスであり、すべての濃い青の数字はポイント間のリンクのインデックスです。

ここで、0x00000〜0xFFFFFの16進数を指定すると、コンソールで文字スペースと「■」のみを使用して図形を描画する必要があります(文字「o」を使用しても問題ありません)。

16進数が入力され、形状が出力される例を次に示します。

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

うん

4
グラフィック出力は許可されていますか?
12Me21

1
16進数の入力が必要ですか、それとも10進数でも大丈夫ですか?
タイタス

1
たぶん、すべてのコードゴルフが私に届いているだけですが、そのコードは読むのが苦痛です…
リン

回答:


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

g10行の9行のグリッドで作業します。グリッドは最初はスペースで埋められ、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`

おっと...間のスペースを忘れました。それを修正します。
アーナルド

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いいえ、.split()破壊し||ます。
orlp

3

ルビー、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バイトのソリューションがあると思います。時間があれば、これを後で試します。


いい説明!
シグメイ

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=""ます。

エンコードの説明

すべての線は、開始点と4つの方向のいずれかで記述できます。
9x9グリッドに描画すると、開始位置の範囲は0,0から8,4です。または、組み合わせてfrom 0から8*9+4=76。幸いなことに、すべての開始点[0,4,8,36,40,44,72,76]は4で割り切れます。そのため、方向コード[0..3]はビット0および1に圧縮できます->シフトはまったく必要ありません。

カーソルの動きを簡単に計算する0ために、東(垂直方向の動きのない方向のみ)および[1,2,3]南西、南、南東のオフセットが9(垂直方向の動きの場合)plus [-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]です。各値のビットごとのxor 96は、印刷可能な問題のないASCIIコード[96,100,98,99,101,102,103,105,106,68, 72,70,71,73,74,75,77,78,40,44]->になり`dbcefgijDHFGIJKMN(,ます。コードはビット0にLSBを使用しますが、行0はMSBに対応するため、文字列を逆にする必要があります。フィニート。

壊す

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下位2ビットには影響がないため、方向を抽出するときに無視できます。そのため、変数に値を保存する必要はありません。変数は、カーソルの初期化で5バイトを節約します。
  • ~3代わりに124を使用すると、1バイト節約され、次のゴルフが可能になります。
  • 割り当て$k=3内のループカウンターを初期化すると、$p2バイト
    を節約でき、前提条件を損なうことはありません(上限値は1桁のままなので)。
  • 結果に文字列を使用すると、初期化とプロットが最短になります。文字列の末尾を越えて文字が設定されると、PHPは欠落している文字を暗黙的にスペースに設定します。そしてchunk_split、改行を挿入する最短の方法です。
    私は他に何かがどれくらいかかるか知りたくさえありません。
  • 7+($c&3?:-6)は、より1バイト短い$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の答えがきっかけで、1次元配列ソリューションを調査することになりました。編集:@ edc65のおかげで1バイト保存されました。@Arnauldのおかげで5 15バイト節約されました。文字の選択を微調整して、さらにバイトを節約しました。


[0,1,2,3,4]短いです
-edc65

私はあなたが使用して4つのバイトを保存することができると思う[67,65,52,36,51,50,34,49,48,35,33,20,4,19,18,2,17,16,3,1][0,2,4,6,8].map(i=>a[(e&102)*4+(e&17||15)*i]='o')
アルノー

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あなたはあなたの節約を1つ少なく数えているようです、そして私は~代わりに使用して余分なバイトをゴルフオフすることもできました-34(悲しいことに私は2バイトを節約しない理由である「\」のファウルになります)。
ニール

この '\'をASCII文字#220に置き換えることができるのだろうか。
アーナルド

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入れることはバッチを超えているため、独自のサブルーチンが必要です。それは目に見える何もしないので、私はそこに抜けて終了します。~外側のループ内の文字列の引用符を外すと、内側のループが数値をループできます。数字は、単にosを描画するすべての場所のビットマスクです。


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から文字列を読み取り、16進数として評価します。コードの残りの部分は、基本的にグリッドのx / y座標の二重ループであり、o各場所に出力するかどうかを決定する大規模なブール計算を使用します。

基本的に、20個のグリッドポイントのそれぞれに個別の条件があります。たとえば、最初の4つです。

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

そして、それらの20個すべてを計算したら、ロットのORをとり、その結果が真であればaを出力しo、そうでなければスペースを出力します。

Befungeは我々だけ繰り返しevalatingしているので、入力からビットを抽出するために、ビット操作の操作の仕方には何も持っていないn%2し、その後n/=2、我々は20の状態の計算を通じて、私たちの道を作るよう。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.