Симетрично видавіть грані куба вздовж XYZ


33

Пісочниця

Для цілей поточного завдання куб одиничної довжини виводиться в косій проекції із символами ASCII таким чином:

  +-----+
 /     /|
+-----+ |
|     | +
|     |/
+-----+
  • + для вершин.
  • -для ребер X. Одинична довжина вздовж X представлена ​​п'ятьма -між двома вершинами.
  • |для ребер Y. Довжина одиниці вздовж Y представлена ​​двома |між двома вершинами.
  • /для ребер Z. Довжина одиниці вздовж Z представлена ​​однією /між двома вершинами.
  • Вершини малюються лише там, де перетинаються всі три площини.
  • Краї намальовані лише там, де перетинаються рівно дві площини.

Коли екструдована грань одиниці, вона зміщується на одиницю довжини від вихідного положення та створюються чотири нові краї для кожного напрямку (позитивні та негативні).

Ви можете думати про екструзію як про нанесення осей 3D-декартової системи координат, де кожна вісь представлена ​​у вигляді кубоїди з перетином 1x1 та довжиною nвід (0,0,0)

Витиснене на 1 вздовж X:

  +-----------------+
 /                 /|   
+-----------------+ |
|                 | +
|                 |/
+-----------------+

Завдання

Давши три числа для осей XYZ, екструдуйте грані одиничного куба симетрично зазначеними величинами та подайте результат символами ASCII, як зазначено вище.

Вхідні дані

x, y, z - негативні числа - довжини екструзії для відповідних осей. 0 означає відсутність екструзії. Вхідними даними можуть бути три числа, список з трьох чисел, трійка, рядок або все, що вам зручно.

Вихідні дані

Креслення куба ASCII після екструзії. Доступні провідні та кінцеві простори віхтів.

Тестові справи

X Y Z
0 0 0

  +-----+
 /     /|
+-----+ |
|     | +
|     |/
+-----+

1 0 0

  +-----------------+
 /                 /|   
+-----------------+ |
|                 | +
|                 |/
+-----------------+


0 0 1   
        +-----+
       /     /|
      /     / |
     /     /  +
    /     /  /
   /     /  /
  +-----+  /
  |     | / 
  |     |/
  +-----+


1 1 0

        +-----+
       /     /|      
      +-----+ |
  +---|     | +-----+
 /    |     |/     /|
+-----+     +-----+ |
|                 | +
|                 |/
+-----+     +-----+
      |     | +
      |     |/
      +-----+

2 0 1

                +-----+
               /     /|
  +-----------+     +-----------+
 /                             /|
+-----------+     +-----------+ |
|          /     /|           | +
|         +-----+ |           |/
+---------|     | +-----------+
          |     |/
          +-----+

1 1 1 

        +-----+
       /     /|-+   
      +-----+ |/|
  +---|     | +-----+
 /    |     |/     /|
+-----+-----+-----+ |
|    /     /|     | +
|   +-----+ |     |/
+---|     | +-----+
    |     |/| +
    +-----+ |/
      +-----+

Критерії виграшу

Виграє найкоротше рішення в байтах на кожній мові. Додайте короткий опис використовуваного методу та вашого коду.


Чи є верхня межа для кожного з видавлювань?
Втілення Невідомості

@Embodiment of Ignorance - 9 повинно вистачити
Гален Іванов

Відповіді:


14

JavaScript (ES6),  525 ... 475 471  459 байт

Збережено 13 байт завдяки @Neil

Приймає дані як масив [X,Y,Z]. Повертає матрицю символів.

a=>([X,Y,Z]=a,m=[],W=X*6+Z*2,'1uol9h824lsqpq17de52u1okgnv21dnjaww111qmhx1gxf4m50xg6pb42kzijq21xyh34t0h2gueq0qznnza2rrimsg3bkrxfh3yrh0em').replace(/.{7}/g,s=>[[c,x,A,y,B,w,C,h,D,t]=parseInt(s,36)+s,Y*W,Z,X,Y|!W,Z*X,X*Y*!Z,X*Z*!Y,Y*Z*!X][c]&&(g=H=>V<h&&((m[r=y-(3-B)*p+(t>1?H-V:V)+Y*3+Z*2]=m[r]||Array(W*2+9).fill` `)[x-2*(3-A)*p+(t>1?V:H-V*t)+W]=` ${c>5?'  + ':t>1?'|-':'-|'}+/+`[(H%~-w?0:+t?4:2)|!(V%~-h)],g(++H<w?H:!++V)))(V=0,p=a[c%3],w-=-3*C*p,h-=-D*p))&&m

Спробуйте в Інтернеті!

Як?

Креслення кроків

Вихід складається з 15 сторін, намальованих у певному порядку.

анімація

Впровадження

Функція малювання - g . Він працює з такими параметрами:

  • (x,y) : з чого почати малювати
  • w : ширина
  • h : висота
  • t : тип сторони

Вершини завжди намальовані. Залежно від значення іншого параметра c , ребра або малюються, або стираються.

Якщо t=0 , функція малює лицьову сторону:

...........      ...........
..+-----+..      ..+     +..
..|     |..  or  ..       ..
..|     |..      ..       ..
..+-----+..      ..+     +..
...........      ...........

Якщо t=1 , він звертає верхню сторону:

...........      ...........
...+-----+.      ...+     +.
../     /..  or  ..       ..
.+-----+...      .+     +...
...........      ...........

Якщо t=2 , він малює праву сторону:

......+....      ......+....
...../|....      .....  ....
....+ |....  or  ....+  ....
....| +....      ....  +....
....|/.....      ....  .....
....+......      ....+......

(x,y)(w,h)ХYZ . Крім того, кожна сторона складається лише тоді, коли виконується конкретна умова.

c[1..8]

Підсумовуючи, сторона повністю описана з:

{ctx=ox+mx×Py=oy+my×Pw=ow+mw×Ph=oh+mh×P

Пc

Тому нам потрібно зберігати наступні 10 параметрів для кожної сторони:

[c,ox,mx,oy,my,ow,mw,oh,mh,t]

Нижче наведені параметри 15 сторін, які потрібно намалювати:

sidecoxmxoymyowmwohmht0400237046014602346302226222403423366204030243062071240052220270341632600712301720222704008562224012294200370301101002370130111602313302126002070400137200070301148602040302

We force all values into the range [0..9] by applying the following operations:

mx(mx+6)/2mymy+3mwmw/3

It results in 15 numbers of exactly 10 decimal digits, which are stored as 15 groups of 7 digits in base 36.

For instance, the first side is encoded as 4032070460 and stored as 1uol9h8.


I think Array(W*2+9).fill` ` saves a byte.
Neil

Oops,sorry, my bad, I must of saw it wrong or something. Disregard.
Embodiment of Ignorance

@EmbodimentofIgnorance No worries. :)
Arnauld

3
Great visualization in addition to your traditionally cool description! Respect!
Galen Ivanov

@GalenIvanov Thank you! I really enjoyed working on this challenge.
Arnauld

13

APL (Dyalog Classic), 162 161 132 130 bytes

{' |+/+ +-? ??? ++'[⍉(⊃~∘0)⍤13⍉↑a↑¨⍨↓(--1-⌊/∘,)2-/1⌽↑⍳⍴a←16|29|1+{2⊥+/¨∊¨=⌿¨⍵(⍉⍵)(⍉↓⍵)}⌺2 2 2{⍉⍤2⍉⌽0,⍵}⍣63/↓2/61<⍵+.=⍨↑⍳1+2×⍵]}

Try it online!

  • generate a 3d bool array of unit cubies
  • replicate each cubie 6 3 2 times along x y z
  • surround with zeroes
  • for each 2×2×2 subarray compute a number between 0 and 16 that determines the corresponding output char: (1 + 4*cx + 2*cy + cz) mod 16 where cx,cy,cz are the number of same-value "rods" along axis x,y,z, i.e. vectors along that axis that consist of the same value: 0 0 or 1 1. we make an exception if the subarray is all-zero (or all-one - those don't matter) and we consider its number 0 instead of 28
  • for each cell compute where the corresponding char should be drawn on screen
  • for each cell build a transparent (0-padded) matrix that contains only one opaque "pixel"
  • mix the matrices - at this point we have a 5d array with dimensions inx,iny,inz,outx,outy
  • reduce the first three axes, keeping only the first non-transparent (≠0) item along them
  • use a lookup table (a string) to convert the numbers into -|/+

thanks Scott Milner for spotting that some +s rendered as ?s


How do you actually test this? I wanted to try extrusions of 2,3,4 for example, but nothing obvious seemed to work.
Neil

the algo is very wasteful, so 2 3 4 runs out of memory, but 2 3 3 is within reach
ngn

@Neil i made a small fix and now 2 3 4 works. lost a byte as a side effect :)
ngn

An APL solution that's half as long as a Charcoal one on an ascii-art challenge?! What's going on?!
Shaggy

3
Not 100% sure, but I'm pretty sure that this isn't desired behavior on 0 1 1
Scott Milner

6

Charcoal, 325 bytes

≔×⁶Nθ≔׳Nη≔⊗Nζ¿‹¹№⟦θηζ⟧⁰«B⁺⁷⊗θ⁺⁴⊗η↗↗⊕⊗ζ+⁺⁵⊗θP↙⊗⊕ζ↓+↓⁺²⊗η↙+↙⊕⊗ζ»«F‹⁰θ«↗+↗←+←⊖θ↙+/P→θ↓+↓²+⊖θ+»F‹⁰η«J⁶¦³↗+↗↓+↓⊖η↙+/P↑η←+←⁵↑+↑⊖η+»F‹⁰ζ«J⁸±²↓+↓↓↗+↗⊖ζ↑+↑²P↙ζ←+←⁵↙+↙⊖ζ+»J⁶¦⁰F‹⁰ζ«G↓³↙⊕ζ←⁷↑³↗⊕ζ ↙+↙⊖ζ↓+↓²+→⁵P↗ζ↑+↑²P←⁶↗+↗⊖ζ»F‹⁰η«G←⁶↑⊕η↗³→⁶↓⊕η ↑+↑⊖η←+←⁵↙+/P↓η+⁵P↗²↓+↓⊖η»F‹⁰θ«G↗²→⊕θ↓⁴↙²←⊕θ →+⊖θ↗+/↑+↑²P←θ↙+/P↓³←+←⊖θ»P↗∧∧θη²P↓∧∧ζθ³P←∧∧ηζ⁶+

Try it online! Link is to verbose version of code. Explanation:

≔×⁶Nθ≔׳Nη≔⊗Nζ

Input the extrusions, but premultiply them to save bytes.

¿‹¹№⟦θηζ⟧⁰«B⁺⁷⊗θ⁺⁴⊗η↗↗⊕⊗ζ+⁺⁵⊗θP↙⊗⊕ζ↓+↓⁺²⊗η↙+↙⊕⊗ζ»«

If at least two of the extrusions are zero, then simply draw a cuboid of dimensions (2x+1, 2y+1, 2z+1). Otherwise:

F‹⁰θ«↗+↗←+←⊖θ↙+/P→θ↓+↓²+⊖θ+»

Print the left extrusion, if any.

F‹⁰η«J⁶¦³↗+↗↓+↓⊖η↙+/P↑η←+←⁵↑+↑⊖η+»

Print the down extrusion, if any.

F‹⁰ζ«J⁸±²↓+↓↓↗+↗⊖ζ↑+↑²P↙ζ←+←⁵↙+↙⊖ζ+»

Print the back extrusion, if any.

J⁶¦⁰

The remaining extrusions all meet at this point (which doesn't get drawn until the very end!)

F‹⁰ζ«G↓³↙⊕ζ←⁷↑³↗⊕ζ ↙+↙⊖ζ↓+↓²+→⁵P↗ζ↑+↑²P←⁶↗+↗⊖ζ»

Print the front extrusion, if any, taking care to erase parts of the left and down extrusions that may overlap.

F‹⁰η«G←⁶↑⊕η↗³→⁶↓⊕η ↑+↑⊖η←+←⁵↙+/P↓η+⁵P↗²↓+↓⊖η»

Print the up extrusion, if any, taking care to erase parts of the back and left extrusions that may overlap.

F‹⁰θ«G↗²→⊕θ↓⁴↙²←⊕θ →+⊖θ↗+/↑+↑²P←θ↙+/P↓³←+←⊖θ»

Print the right extrusion, if any, taking care to erase parts of the down and back extrusions that may overlap.

P↗∧∧θη²P↓∧∧ζθ³P←∧∧ηζ⁶+

Draw the joins between the latter extrusions.


325 bytes in Charcoal?! On an ascii-art challenge?! That's enough to make me not even attempt this in Ja(vaScri)pt!
Shaggy

@Shaggy This might not be an optimal approach, and there might be ways of golfing it that I've overlooked anyway. I do have to say though that ngn's method looks intriguing, it looks as if he draws the shape into an internal array and then performs edge detection to generate his output.
Neil

@Shaggy I've come up with a 195 byte solution, which I've posted separately as it's a completely different approach. Still well short of APL though.
Neil

3

Charcoal, 195 164 144 bytes

≔⁺³×⁶Nθ≔⁺²×³Nη≔⊕⊗NζF…·±ζζF…·±ηηF…·±θθ«J⁻λι⁺κι≔⟦⟧δFE²↔⁻⁺ιμ·⁵FE²↔⁻κνFE²↔⁻⁺λξ·⁵⊞δ⌊⟦‹μζ‹νη‹ξθ‹¹№E⟦μνξ⟧‹π⊕ρ¹⟧≡Σδ¹+²§ |-/⁺⌕δ¹⌕⮌δ¹¦³+⁴§ +Σ…δ⁴¦⁶§ |-/⌕δ⁰

Try it online! Link is to verbose version of code. I'm posting this as a separate answer as it uses a completely different approach to drawing the extrusion. Explanation:

≔⁺³×⁶Nθ≔⁺²×³Nη≔⊕⊗Nζ

Input the extrusions and calculate half the size of the enclosing cuboid, but in integer arithmetic because Charcoal's ranges are always integers. The origin of the output maps to the centre of the original unit cube.

F…·±ζζF…·±ηηF…·±θθ«

Loop over all coordinates within (including the boundary) the cuboid containing the extrusion.

J⁻λι⁺κι

Jump to the output position corresponding to those coordinates.

≔⟦⟧δFE²↔⁻⁺ιμ·⁵FE²↔⁻κνFE²↔⁻⁺λξ·⁵⊞δ⌊⟦‹μζ‹νη‹ξθ‹¹№E⟦μνξ⟧‹π⊕ρ¹⟧

From the given coordinates, peek in all eight diagonal directions to determine whether the extrusion overlaps in that direction. The peeked coordinates are checked that they still lie within the cuboid, and then the number of axes in which the coordinate lies within the original cube must be greater than 1. Note that since the cube has an odd display height, the Y-axis values that are peeked are integers while the other axes use fractional coordinates.

≡Σδ

Розглянемо кількість напрямків, в яких екструзія перекривається. Є п’ять випадків інтересу, коли ми хочемо щось надрукувати, як у випадку нуля, це означає, що це порожній простір, і ми не хочемо нічого друкувати, тоді як у восьми, це означає, що це всередині видавлювання і все, що ми робимо, надрукували б шаром, що наближався до точки зору.

¹+

Якщо екструзія перекривається лише в одному напрямку, то це зовнішній кут, і нам потрібно вивести a +.

²§ |-/⁺⌕δ¹⌕⮌δ¹¦

Якщо екструзія перекривається в двох напрямках, то це зовнішній край. Який різновид ребра визначається від поділу між двома перекриттями; 6 і 7 є задніми краями і будуть перезаписані, 4 - це діагональний край, 2 - вертикальний край і 1 - горизонтальний край. (Я фактично обчислюю 7 мінус поділу, як це здається легше.)

³+

Якщо екструзія перекривається в трьох напрямках, то це внутрішній кут у випадку, коли одна з екструзій дорівнює нулю, і нам потрібно вивести a +.

⁴§ +Σ…δ⁴¦

Якщо екструзія перекривається в чотирьох напрямках, то є два випадки: грані (будь-якого напрямку) та внутрішні кути у корпусі з трьома позитивними витисками. В останньому випадку спостерігається непарна кількість перекриттів щодо глядача.

⁶§ |-/⌕δ⁰

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


2

K (нг / к) , 172 байт

{s:1+|/'i-:&//i:1_--':1_4#!#'2*:\a:16!29!1+2/(!3){+'+x}/'{2+':''1+':'0=':x}'{++'x}\6{+'+0,|x}/{6}#{3}#'{2}#''s#1<+/x=!s:1+2*x;" |+/+ +-? ??? ++"s#@[&*/s;s/i;{x+y*~x};,//a]}

Спробуйте в Інтернеті!

обов'язковий k переписати моє рішення apl

той же алгоритм, за винятком того, що 3d-> 2d візуалізація виконується з (k еквівалентом) розподілу індексу розкидання замість створення 2d матриць для кожного 3d елемента та змішування їх


Як би ви ngn/aplпрацювали в порівнянні з вашим Dyalog APLрішенням?
Гален Іванов

@GalenIvanov це не було б справедливим порівнянням, тому що в моєму рішенні apl я витрачаю багато пам’яті, щоб заощадити кілька байтів, і в k коротше, в цьому випадку стане швидше
ngn

Я запитав про порівняння між двома рішеннями APL - вашим APL / Dyalog one та гіпотетичним рішенням у ngn / apl
Гален Іванов

ой, я не знаю, чому я читаю це як "ngn / k" ... це знову несправедливо - ngn / apl - це хобі-javascript, dyalog - це професійно c
ngn

1
@GalenIvanov, мабуть, ні. ngn / apl не вистачає останніх доповнень до такої мови, як оператор рангів ( ) та трафарет ( )
ngn
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.