Extruye las caras de un cubo simétricamente a lo largo de XYZ

33

Salvadera

Para los propósitos de la tarea actual, un cubo de unidad de longitud se representa en proyección oblicua con símbolos ASCII de la siguiente manera:

  +-----+
 /     /|
+-----+ |
|     | +
|     |/
+-----+
  • + para los vértices
  • -para los bordes X La unidad de longitud a lo largo de X está representada por cinco -entre dos vértices.
  • |para los bordes Y La unidad de longitud a lo largo de Y está representada por dos |entre dos vértices.
  • /para los bordes Z La unidad de longitud a lo largo de Z está representada por uno /entre dos vértices.
  • Los vértices solo se dibujan donde se cruzan los tres planos.
  • Los bordes solo se dibujan donde se cruzan exactamente dos planos.

Cuando se extruye una cara de unidad, se compensa con una longitud de unidad desde su posición original y se crean cuatro bordes nuevos para cada dirección (positiva y negativa).

Puede pensar en la extrusión como en dibujar los ejes de un sistema de coordenadas cartesianas 3D donde cada eje se representa como un cuboide con una sección transversal de 1x1 y una longitud nde (0,0,0)

Extruido por 1 a lo largo de X:

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

Tarea

Dados tres números para los ejes XYZ, extruya las caras de un cubo unitario simétricamente por las cantidades indicadas y rinda el resultado con los símbolos ASCII como se especificó anteriormente.

Entrada

x, y, z - números no negativos - longitudes de extrusión para los ejes respectivos. 0 significa que no hay extrusión. La entrada puede ser tres números, una lista de tres números, un triple, una cadena o cualquier cosa que sea conveniente para usted.

Salida

El dibujo ASCII del cubo después de la extrusión. Se permiten espacios en blanco iniciales y finales.

Casos de prueba

X Y Z
0 0 0

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

1 0 0

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


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


1 1 0

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

2 0 1

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

1 1 1 

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

Criterios ganadores

La solución más corta en bytes en cada idioma gana. Agregue una breve descripción del método utilizado y su código.

Galen Ivanov
fuente
¿Hay un límite superior para cada una de las extrusiones?
Encarnación de la ignorancia
@Embodiment of Ignorance - 9 debería ser suficiente
Galen Ivanov

Respuestas:

14

JavaScript (ES6),  525 ... 475 471  459 bytes

Guardado 13 bytes gracias a @Neil

Toma la entrada como una matriz [X,Y,Z]. Devuelve una matriz de caracteres.

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

Pruébalo en línea!

¿Cómo?

Pasos de dibujo

La salida consta de 15 lados, dibujados en un orden específico.

animación

Implementación

La función de dibujo es sol . Funciona con los siguientes parámetros:

  • (X,y) : dónde comenzar a dibujar
  • w : ancho
  • h : altura
  • t : tipo de lado

Los vértices siempre se dibujan. Dependiendo del valor de otro parámetro do , los bordes se dibujan o se borran.

Si t=0 0 , la función dibuja un lado frontal:

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

Si t=1 , dibuja un lado superior:

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

t=2

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

(X,y)(w,h)XYZ

do[1..8]

Para resumir, un lado se describe completamente con:

{dotX=oX+metroX×PAGSy=oy+metroy×PAGSw=ow+metrow×PAGSh=oh+metroh×PAGS

PAGSdo

Por lo tanto, necesitamos almacenar los siguientes 10 parámetros para cada lado:

[do,oX,metroX,oy,metroy,ow,metrow,oh,metroh,t]

A continuación se muestran los parámetros de los 15 lados que deben dibujarse:

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.

Arnauld
fuente
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

ngn
fuente
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.

Neil
fuente
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⟦μνξ⟧‹π⊕ρ¹⟧≡Σδ¹+²§ |-/⁺⌕δ¹⌕⮌δ¹¦³+⁴§ +Σ…δ⁴¦⁶§ |-/⌕δ⁰

Pruébalo en línea! El enlace es a la versión detallada del código. Estoy publicando esto como una respuesta separada, ya que utiliza un enfoque completamente diferente para dibujar la extrusión. Explicación:

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

Ingrese las extrusiones y calcule la mitad del tamaño del cuboide envolvente, pero en aritmética de enteros porque los rangos de carbón son siempre enteros. El origen de la salida se asigna al centro del cubo de la unidad original.

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

Pase sobre todas las coordenadas dentro (incluido el límite) del cuboide que contiene la extrusión.

J⁻λι⁺κι

Salta a la posición de salida correspondiente a esas coordenadas.

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

Desde las coordenadas dadas, mire en las ocho direcciones diagonales para determinar si la extrusión se superpone en esa dirección. Se verifica que las coordenadas observadas todavía se encuentran dentro del cuboide, y luego el número de ejes en los que se encuentra la coordenada dentro del cubo original debe ser mayor que 1. Tenga en cuenta que dado que el cubo tiene una altura de visualización impar, los valores del eje Y que se miran son enteros, mientras que los otros ejes usan coordenadas fraccionarias.

≡Σδ

Considere la cantidad de direcciones en las que se superpone la extrusión. Hay cinco casos de interés en los que queremos imprimir algo, como en el caso de cero, eso significa que este es un espacio vacío y no queremos imprimir nada, mientras que en el caso de ocho, eso significa que está dentro la extrusión y cualquier cosa que imprimiéramos estaría sobreimpresa por una capa más cerca del punto del ojo.

¹+

Si la extrusión solo se superpone en una dirección, entonces esta es una esquina exterior y necesitamos generar una +.

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

Si la extrusión se superpone en dos direcciones, entonces este es un borde exterior. Qué tipo de borde se determina a partir de la separación entre las dos superposiciones; 6 y 7 son bordes orientados hacia atrás y se sobrescribirán, 4 es un borde diagonal, 2 es un borde vertical y 1 es un borde horizontal. (Realmente calculo 7 menos la separación, ya que parece ser más fácil de hacer).

³+

Si la extrusión se superpone en tres direcciones, entonces esta es una esquina interna en el caso de que una de las extrusiones sea cero y necesitemos generar a +.

⁴§ +Σ…δ⁴¦

Si la extrusión se superpone en cuatro direcciones, entonces hay dos casos: caras (cualquier dirección) y esquinas internas en el caso con tres extrusiones positivas. En el último caso, hay un número impar de superposiciones hacia el espectador.

⁶§ |-/⌕δ⁰

Si la extrusión se superpone en seis direcciones, entonces este es un borde interno. Funciona como el complemento de un borde exterior, excepto que solo nos interesa cuando uno de los dos espacios vacíos es la dirección hacia el punto del ojo (la última entrada en la matriz).

Neil
fuente
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]}

Pruébalo en línea!

obligatorio reescribir k de mi solucion apl

mismo algoritmo, excepto que el renderizado 3d-> 2d se realiza con (el k equivalente de) la asignación del índice de dispersión en lugar de crear matrices 2d para cada elemento 3d y mezclarlos

ngn
fuente
¿Cómo sería su ngn/apldesempeño en comparación con su Dyalog APLsolución?
Galen Ivanov
@GalenIvanov no sería una comparación justa porque en mi solución apl i perder una gran cantidad de memoria para ahorrar unos pocos bytes, y en k más corta pasa a ser más rápido en este caso
NGN
Le pregunté sobre la comparación entre dos soluciones APL: la suya APL / Dyalog y una solución hipotética en ngn / apl
Galen Ivanov
Uy, yo no sé por qué he leído que como "NGN / k" ... es más injusta - NGN / LPA es aficionado javascript, dyalog es profesional c
NGN
1
@GalenIvanov probablemente no. A ngn / apl le faltan adiciones recientes al lenguaje como el operador de rango ( ) y stencil ( )
ngn