沿XYZ对称地拉伸立方体的面


33

沙盒

出于当前任务的目的,单位长度的多维数据集以ASCII符号的斜投影方式呈现,如下所示:

  +-----+
 /     /|
+-----+ |
|     | +
|     |/
+-----+
  • + 用于顶点。
  • -X边缘。沿X的单位长度由-两个顶点之间的五个表示。
  • |为Y边缘。沿Y的单位长度由|两个顶点之间的两个表示。
  • /Z边缘。沿Z的单位长度由/两个顶点之间的1表示。
  • 仅在所有三个平面相交的位置绘制顶点。
  • 仅在恰好两个平面相交的位置绘制边缘。

拉伸单位面时,它会从其原始位置偏移单位长度,并为每个方向(正方向和负方向)创建四个新边。

您可以将拉伸视为绘制3D笛卡尔坐标系的轴,其中每个轴都表示为长方体,其横截面为1x1,长度n为(0,0,0)

沿X拉伸1:

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

任务

给定XYZ轴的三个数字,按指定的数量对称拉伸单位立方体的面,并使用上面指定的ASCII符号呈现结果。

输入项

x,y,z –非负数–各个轴的挤出长度。0表示不挤出。输入可以是三个数字,三个数字的列表,三个字符,一个字符串或任何您方便使用的东西。

输出量

挤压后立方体的ASCII图。允许前导和尾随wihtespace。

测试用例

X Y Z
0 0 0

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

1 0 0

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


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


1 1 0

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

2 0 1

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

1 1 1 

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

获奖标准

每种语言中以字节为单位的最短解决方案为准。请添加所用方法和代码的简短描述。


每个挤压件都有上限吗?
无知的体现

@无知的实现-9应该足够
Galen Ivanov

Answers:


14

JavaScript(ES6), 525 ...  475471459字节

@Neil节省了13个字节

将输入作为数组[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ÿ:从哪里开始绘制
  • w:宽度
  • H:高度
  • Ť:侧面类型

总是绘制顶点。取决于另一个参数C的值,将绘制或擦除边缘。

如果Ť=0,则该函数绘制正面:

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

如果Ť=1个,它将绘制一个顶面:

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

Ť=2

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

XÿwHXÿž

C[1..8]

总而言之,用以下内容充分描述了一个方面:

{CŤX=ØX+X×Pÿ=Øÿ+ÿ×Pw=Øw+w×PH=ØH+H×P

PC

因此,我们需要为每侧存储以下10个参数:

[CØXXØÿÿØwwØHHŤ]

以下是需要绘制的15个面的参数:

CØXXØÿÿØwwØHHŤ04002-3704601个4602-346302226-2224034233662040302430-62071240052220-270341个632-600712301个720-22270400856-222401个2294200-370301个101个002-3701个30111个602-31个3302126002070400137200070301个148602040302

[0..9]

XX+6/2ÿÿ+3ww/3

结果为15个正好为10个十进制数字的数字,这些数字作为15组的7个数字存储在基数36中。

例如,第一面编码为,4032070460并存储为1uol9h8


我认为Array(W*2+9).fill` ` 可以节省一个字节。
尼尔

抱歉,抱歉,我必须看到它有误。漠视。
无知的体现

@EmbodimentofIgnorance不用担心。:)
Arnauld

3
除了传统上很酷的描述之外,还具有出色的可视化效果!尊重!
Galen Ivanov

@GalenIvanov谢谢!我真的很喜欢应对这个挑战。
Arnauld

13

APL(Dyalog经典)162个 161 132 130字节

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

在线尝试!

  • 生成单位立方的3d bool数组
  • 沿xyz复制每个cubie 6 3 2次
  • 用零包围
  • 对于每个2×2×2子阵列计算0和16之间的数,其确定相应的输出字符:(1 + 4*cx + 2*cy + cz) mod 16其中cxcycz是相同的值“棒”的个数沿轴线X,Y,Z,即载体沿着该轴的是由的值相同:0 0或1 1.如果子数组为全零(或全为1,则无所谓),则我们将其设为0,而不是28
  • 对于每个单元格计算,应在屏幕上绘制相应的字符
  • 为每个单元格构建一个透明的(填充0)矩阵,其中仅包含一个不透明的“像素”
  • 混合矩阵-此时,我们有一个尺寸为inx,iny,inz,outx,outy的5d数组
  • 减少前三个轴,沿它们仅保留第一个非透明(≠0)项
  • 使用查找表(字符串)将数字转换为 -|/+

感谢Scott Milner发现某些+s呈现为?s


您如何实际测试呢?例如,我想尝试2、3、4的拉伸,但是似乎没有明显的效果。
尼尔

算法非常浪费,因此2 3 4内存不足,但是2 3 3可以实现
ngn

@Neil我做了一个小修复,现在2 3 4可以工作。失去了一个字节作为副作用:)
ngn

一种APL解决方案,要比应对木炭挑战的木炭长一半?这是怎么回事?!
毛茸茸的

3
不确定100%,但是我很确定这不是0 1 1时的
Scott Milner

6

木炭,325字节

≔×⁶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←∧∧ηζ⁶+

在线尝试!链接是详细版本的代码。说明:

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

输入拉伸,但要乘以节省字节。

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

如果至少两个拉伸为零,则只需绘制尺寸为(2x + 1、2y + 1、2z + 1)的长方体即可。除此以外:

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

打印左挤出(如果有)。

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

打印向下挤压(如果有)。

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

打印背面挤出(如果有)。

J⁶¦⁰

其余的所有拉伸都在此时相遇(直到最后才被绘制!)

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

打印前凸出部分(如果有),请小心以消除可能重叠的左侧和下部凸出部分。

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

打印上凸出部分(如果有的话),请注意擦除可能重叠的背面和左侧凸出部分。

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

打印正确的拉伸(如果有的话),注意擦除可能重叠的向下和向后拉伸的部分。

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

在后面的拉伸之间绘制连接。


325字节的木炭?在挑战ascii艺术?这足以使我什至没有在Ja(vaScri)pt中尝试这种操作!
毛茸茸的

@Shaggy这可能不是一个最佳方法,而且无论如何我可能都忽略了打高尔夫球的方法。我确实必须说,尽管ngn的方法看起来很有趣,但看起来他好像将形状绘制到内部数组中,然后执行边缘检测以生成他的输出。
尼尔

@Shaggy我想出了一个195字节的解决方案,由于它是完全不同的方法,所以我将其单独发布。仍然远远低于APL。
尼尔

3

木炭195个 164 144字节

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

在线尝试!链接是详细版本的代码。我将其作为单独的答案发布,因为它使用了完全不同的方法来绘制拉伸。说明:

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

输入拉伸并计算封闭的长方体的一半大小,但是使用整数算术,因为木炭的范围始终是整数。输出的原点映射到原始单位立方体的中心。

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

在包含拉伸的长方体内(包括边界)上的所有坐标循环。

J⁻λι⁺κι

跳转到与那些坐标相对应的输出位置。

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

根据给定的坐标,在所有八个对角线方向上进行窥视,以确定拉伸是否在该方向上重叠。检查偷看的坐标以确保它们仍然位于长方体内,然后坐标位于原始立方体内的轴数必须大于1。请注意,由于立方体的显示高度为奇数,因此Y轴值被窥视的是整数,而其他轴使用小数坐标。

≡Σδ

考虑拉伸重叠的方向数。在五种感兴趣的情况下,我们要打印一些东西,例如零,这意味着这是空白空间,我们不想打印任何东西,而在八种情况下,这意味着它是在里面。挤出物和我们所做的任何打印操作都将在靠近视点的位置上叠印。

¹+

如果拉伸仅在一个方向上重叠,则这是一个外角,我们需要输出a +

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

如果挤压在两个方向上重叠,则这是外边缘。根据两个重叠部分之间的距离确定哪种边缘;6和7是面向后的边缘,将被覆盖,4是对角边缘,2是垂直边缘,1是水平边缘。(实际上,我计算出7减去间隔,因为这样做似乎更容易。)

³+

如果拉伸在三个方向上重叠,则在其中一个拉伸为零的情况下,这是一个内角,我们需要输出a +

⁴§ +Σ…δ⁴¦

如果拉伸在四个方向上重叠,则有两种情况:面(任何方向)和带有三个正向拉伸的情况下的内角。在后一种情况下,向观看者存在奇数个重叠。

⁶§ |-/⌕δ⁰

如果挤压在六个方向上重叠,则这是一个内边缘。它的工作方式类似于外边缘的补码,只是我们仅对两个空白空间之一是朝向视点的方向(数组中的最后一个条目)感兴趣。


2

K(ngn / 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]}

在线尝试!

我的apl解决方案必须进行k重写

相同的算法,不同之处在于3d-> 2d渲染是通过分散索引分配(等于k)完成的,而不是为每个3d元素创建2d矩阵并将其混合


如何将你ngn/apl相比,你会借此Dyalog APL解决方案?
Galen Ivanov

@GalenIvanov,这将不是一个公平的比较,因为在我的apl解决方案中,我浪费了大量内存来节省一些字节,而在这种情况下,k较短的时间会更快
ngn

我问过两种APL解决方案之间的比较-您的APL / Dyalog解决方案和ngn / apl中的假设解决方案
Galen Ivanov

哎呀,我不知道为什么我读为“NGN / K” ......这是不公平的又- NGN / APL为爱好者的javascript,dyalog是专业的C
NGN

1
@GalenIvanov可能不会。ngn / apl缺少最新添加的语言,例如等级运算符()和模具(
nten
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.