Выдавливать грани куба симметрично вдоль XYZ


33

песочница

Для целей текущей задачи куб единичной длины отображается в косой проекции с символами ASCII следующим образом:

  +-----+
 /     /|
+-----+ |
|     | +
|     |/
+-----+
  • + для вершин.
  • -для X ребер. Длина единицы вдоль X представлена ​​пятью -между двумя вершинами.
  • |для Y ребер. Длина единицы вдоль Y представлена ​​двумя |между двумя вершинами.
  • /для Z ребер. Длина единицы вдоль Z представлена ​​одной /между двумя вершинами.
  • Вершины отображаются только там, где пересекаются все три плоскости.
  • Края рисуются только там, где пересекаются ровно две плоскости.

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

Вы можете думать о выдавливании как о рисовании осей трехмерной декартовой системы координат, где каждая ось представлена ​​в виде кубоида с поперечным сечением 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 

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

Критерии победы

Самое короткое решение в байтах на каждом языке выигрывает. Пожалуйста, добавьте краткое описание используемого метода и ваш код.


Есть ли верхняя граница для каждого из выдавливаний?
Воплощение Невежества

@ Воплощение невежества - 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) каждой стороны либо имеют постоянное значение, либо зависят точно от одной из входных переменных: X , Y или Z . Кроме того, каждая сторона рисуется тогда и только тогда, когда выполняется определенное условие.

c[1..8]

Подводя итог, сторона полностью описывается с помощью:

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

Pc

Поэтому нам нужно хранить следующие 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.

≡Σδ

Consider the number of directions in which the extrusion overlaps. There are five cases of interest where we want to print something, as in the case of zero, that means that this is empty space and we don't want to print anything, while in the case of eight, that means that this is inside the extrusion and anything we did print would be overprinted by a layer nearer the eye point.

¹+

If the extrusion only overlaps in one direction then this is an outer corner and we need to output a +.

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

If the extrusion overlaps in two directions then this is an outer edge. Which sort of edge is determined from the separation between the two overlaps; 6 and 7 are rear-facing edges and will get overwritten, 4 is a diagonal edge, 2 is a vertical edge and 1 is a horizontal edge. (I actually calculate 7 minus the separation as it seems to be easier to do.)

³+

If the extrusion overlaps in three directions then this is an inner corner in the case where one of the extrusions is zero and we need to output a +.

⁴§ +Σ…δ⁴¦

If the extrusion overlaps in four directions then there are two cases: faces (any direction), and inner corners in the case with three positive extrusions. In the latter case there are an odd number of overlaps towards the viewer.

⁶§ |-/⌕δ⁰

If the extrusion overlaps in six directions then this is an inner edge. It works like the complement of an outer edge except that we're only interested when one of the two empty spaces is the direction towards the eye point (the last entry in the array).


2

K (ngn/k), 172 bytes

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

Try it online!

obligatory k rewrite of my apl solution

same algorithm, except that 3d->2d rendering is done with (the k equivalent of) scatter index assignment instead of creating 2d matrices for each 3d element and mixing them


How would your ngn/apl perfrom in comparison to your Dyalog APL solution?
Galen Ivanov

@GalenIvanov it wouldn't be a fair comparison because in my apl solution i waste a lot of memory to save a few bytes, and in k shorter happens to be faster in this case
ngn

I asked about comparison between two APL solutions - yours APL/Dyalog one and a hypothetical solution in ngn/apl
Galen Ivanov

oops, i don't know why i read that as "ngn/k"... it's again unfair - ngn/apl is hobbyist javascript, dyalog is professional c
ngn

1
@GalenIvanov probably not. ngn/apl is missing recent additions to the language like the rank operator () and stencil ()
ngn
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.