Ящик з красивим малюнком (маленькі кубики)


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
Чи дозволено графічний вихід?
12Me21

1
Вам потрібен шістнадцятковий ввід чи десяткове?
Тит

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

Працюємо над сіткою gз 9 рядів по 10 символів. Сітка спочатку заповнена пробілами, а LineFeed - кожен 10-й символ.

Кожен сегмент визначається вихідною позицією та напрямком.

Напрямки кодуються наступним чином:

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 Nope, .split()руйнує ||.
орл

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 рядків. По-друге, якщо початкові точки горизонтальних ліній обрані належним чином, х напрямки проходять безперервно через праву, ліву, пряму.

Ungolfed в програмі тестування

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

Я вважаю, що існує 112-байтне рішення, що використовує 20-символьну рядок і деяке декодування для визначення параметрів 20 рядків. Я спробую це пізніше, якщо матиму час.


Приємне пояснення!
Сигмей

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="".

кодування пояснено

Кожен рядок можна описати з початковою точкою та одним із чотирьох напрямків.
Малюючи на сітці 9х9, вихідне положення коливається від 0,0до 8,4; або, у поєднанні, від 0до 8*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]; і побітове значення xor 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, тому рядок повинен бути перетворений. Фініто.

зламатися

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не впливає на два нижні біти, його можна ігнорувати при витягуванні напрямку; тому немає необхідності зберігати значення у змінній, яка зберігає 5 байтів на курсорі init.
  • Використання ~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 байт, але відповідь @ Арнаульда надихнула мене дослідити рішення одновимірного масиву. Редагувати: Збережено 1 байт завдяки @ edc65. Збережено 5 15 байт завдяки @Arnauld. Збережено подальший байт, налаштувавши вибір символів.


[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')
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 Ви, здається, знизили ваші заощадження на 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циклу виходить за межі партії, тому потрібна власна підпрограма. Оскільки він нічого не бачить, я потрапляю в нього, щоб вийти. ~Unquotes струни в зовнішньому контурі , дозволяючи внутрішню петлю до петлі над числами. Цифри - це просто бітові маски для всіх місць, де 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слід виводити а для кожного місця.

В основному є окрема умова для кожної з 20 точок сітки, наприклад (перші чотири):

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

А потім, коли ми обчислили всі 20 з них, ми АБО партія разом, і якщо цей результат правдивий, ми виводимо a o, інакше ми виводимо пробіл.

У Befunge немає нічого на шляху операцій з маніпуляцією бітами, тому для витягування бітів з вхідних даних ми просто неодноразово еваліруємося, n%2і тоді, n/=2коли ми пробиваємося через 20 обчислень умов.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.