Predecessor-completed Ascii Cubes

34

4

The first Predecessor-completed Ascii Cube (PAC 1) is a simple cube with side length 1 and looks like this:

 /////\
/////  \
\\\\\  /
 \\\\\/

The PAC 2 is a geometric shape such that combining it with its predecessor (the PAC 1) completes a side length 2 cube:

      front                back
   /////////\           /////////\
  /////////  \         /////////  \
 /////\\\\\   \       /////////    \
/////  \\\\\   \     /////////      \
\\\\\  /////   /     \\\\\\\\\      /
 \\\\\/////   /       \\\\\\\\\    /
  \\\\\\\\\  /         \\\\\\\\\  /
   \\\\\\\\\/           \\\\\\\\\/

Because the back-view is kind of boring, we are only interested in the front-view.

The same goes for the PAC 3: With some visual thinking the PAC 2 can be turned around and plugged into the PAC 3 to form a solid side length 3 cube:

     /////////////\
    /////////////  \
   /////\\\\\\\\\   \
  /////  \\\\\\\\\   \
 /////   /////\\\\\   \
/////   /////  \\\\\   \
\\\\\   \\\\\  /////   /
 \\\\\   \\\\\/////   /
  \\\\\  /////////   /
   \\\\\/////////   /
    \\\\\\\\\\\\\  /
     \\\\\\\\\\\\\/

And so on with PAC 4:

       /////////////////\
      /////////////////  \
     /////\\\\\\\\\\\\\   \
    /////  \\\\\\\\\\\\\   \
   /////   /////////\\\\\   \
  /////   /////////  \\\\\   \
 /////   /////\\\\\   \\\\\   \
/////   /////  \\\\\   \\\\\   \
\\\\\   \\\\\  /////   /////   /
 \\\\\   \\\\\/////   /////   / 
  \\\\\   \\\\\\\\\  /////   /
   \\\\\   \\\\\\\\\/////   /
    \\\\\  /////////////   /
     \\\\\/////////////   /
      \\\\\\\\\\\\\\\\\  /
       \\\\\\\\\\\\\\\\\/

Task:

Write a full program or function which takes a positive integer n as input and returns or prints the corresponding front-view of PAC n exactly as shown above. Additional trailing white space is acceptable.

This is , so try to use as few bytes as possible in the language of your choice.

Laikoni

Posted 2017-02-18T17:05:42.167

Reputation: 23 676

Is it okay to print laterally inverted output, i.e. switch left and right? – busukxuan – 2017-02-18T17:32:57.947

No, it's part of the challenge to keep the "lighting" consistent. – Laikoni – 2017-02-18T17:39:32.213

Usually the bounty for code-golf questions goes to the shortest answer to encourage competition and the golfing of answers, but it really can't be enforced, and you're more than welcome to award it to any answer that deserves it. – mbomb007 – 2018-03-29T19:57:30.587

Answers

11

JavaScript (ES6), 229 bytes

f=
(n,l=n*4+1,r=1,i=n*2,g=a=>` / \\ /
`.replace(/./g,c=>c.repeat(a.pop())))=>n?g([r,,l,--i])+g([r,2,l,--i])+f(n-1,l-1?1:r-4,r-1?1:l-4).replace(/(\S).*(.)/g,r-1?`$1   $&$2$2$2$2`:`$1$1$1$1$&   $2`)+g([r,2,l,,,i])+g([r,,l,,,i+1]):``
<input type=number min=0 oninput=o.textContent=f(+this.value)><pre id=o>

Neil

Posted 2017-02-18T17:05:42.167

Reputation: 95 035

4

Batch, 559 432 400 bytes

@echo off
set m=
for /l %%i in (1,1,%1)do call set m=  %%m%%
call:c "%m:~2%" %m: =//%/\
exit/b
:c
setlocal
set m=%~1%2%~3
echo  %m%
echo %m:/\=/  \%
set s=%~1
if "%s:~,1%"=="/" goto g
set t=%2
set t=%t:~3,-3%
if %t:~,1%==/ (call:c "%s:~2%////" /\%t:/=\% "   \%~3")else call:c "%s:~2%/   " %t:\=/%/\ "\\\\%~3"
:g
set m=%m:/=-%
set m=%m:\=/%
set m=%m:-=\%
echo %m:\/=\  /%
echo  %m%

Explanation: The bottom half of the cube is drawn by reflecting the top half. The halves are further split into seven six three strips parts, as per this diagram showing the top half:

1       12/////////////////\233
1      12/////////////////  \233
1     ////12/\\\\\\\\\\\\\23   \3
1    ////12/  \\\\\\\\\\\\\23   \3
1   /////   12/////////\23\\\\   \3
1  /////   12/////////  \23\\\\   \3
1 /////   ////12/\\\\\23   \\\\\   \3
1/////   ////12/  \\\\\23   \\\\\   \3
  1. The indentation (which decreases every row) and the left triangle, which increases every other row
  2. The middle shrinking zigzag triangle, with the small triangle on alternate sides every other row
  3. The right triangle, which increases in sync with the left

Edit: Saved over 20% by improving the code that reflected the top to the bottom half. Saved almost 10% by merging the left two and middle three strips.

Neil

Posted 2017-02-18T17:05:42.167

Reputation: 95 035

4

Canvas, 36 bytes

;Xø;{1x/╋
ø╶{«5⁸2²4×⁸²«1╋²«\+;↔53╋}═

Try it here!

dzaima

Posted 2017-02-18T17:05:42.167

Reputation: 19 048

The ASCII art version of SOGL was outgolfed by SOGL in an ASCII art challenge? – dylnan – 2018-04-03T18:23:07.530

@dylnan Canvas didn't have the diagonal space prepend built-in which could golf this a bit. Didn't feel right adding a built-in for the challenge – dzaima – 2018-04-03T18:25:12.780

got it. Just curious. Still two cool languages – dylnan – 2018-04-03T18:42:44.717

4

SOGL V0.12, 32 bytes

ø.∫4*I└*2∙f«5└*∙+¼F«╝┼;↔±53╬5}╬±

Try it here!

Simple explanation:
1. iterate for each of 1..x
2. make a shape with the width of i*4+1 and height = (0-indexed)i // 2
3. pad it so it looks like
4. append a "\" shape to that horizontally
5. insert the previous step inside that reversed 6. after everything, mirror vertically

full program:

ø                                 push an empty string - starting stage
 .∫                          }    iterate over 1..input
   4*                               multiply the 1-indexed counter by 4
     I                              and add 1
      └*                            repeat "/" that many times
        2∙                          and repeat vertically twice. Top 2 lines are done
          f«                        push the 0-indexed counter floor divided by 2
            5└*                     push "/" repeated 5 times
               ∙                    and repeat that vertically by the result of the "f«"
                +                   add vertically, creating a "⌐" shape
                 ¼                  prepend each next line with one less space than the above
                  F«                push 1-indexed counter floor divided by 2
                    ╝               create a "\" diagonal that long
                     ┼              and append it horizontally. Shell is done of this hexagon
                      ;↔±           get the previous item on the stack and reverse it horizontally
                         53╬5       and at [5;3] insert the previous result in this
                              ╬±  once everything's done, mirror vertically to finish the hexagon

dzaima

Posted 2017-02-18T17:05:42.167

Reputation: 19 048

2

Python 2, 254 234 226 203 201 199 bytes

Finally sub 200!

P=[];n=0
M=lambda r:(u''+r).translate({47:92,92:47})
exec r"n+=1;q='/'*4;P=[q*n+'/\\',q*n+'/  \\']+[q+'%s   \\'%M(r[::-1])for r in P];"*input()
print'\n'.join(l.center(8*n)for l in(P+map(M,P[::-1])))

Tricks:

This function is used to swap all \ with / and vice versa
A bit long in Python2 - works only with unicode
Check out this for how it works

M=lambda r:(u''+r).translate({47:92,92:47})

Generates new top two rows for each iteration
For now I can't find compact way to receive this lines from previous iteration

P=[q*n+'/\\',q*n+'/  \\']

Reverse all rows of previous iteration and swap slashes

[q+'%s   \\'%M(r[::-1])for r in P]

Copy top half, reversed by rows, swap slashes

P+map(M,P[::-1])

Neat method for center padding strings

l.center(8*n)

Try it online!

Dead Possum

Posted 2017-02-18T17:05:42.167

Reputation: 3 256

2

Haskell, 232 227 224 187 183 180 175 bytes

m '/'='\\'
m '\\'='/'
m c=c
r=reverse
k=map
n?s=('/'<$[1..4*n])++s
f 0=[]
f n=n?"/\\":n?"/  \\":[1?k m(r s)++"   \\"|s<-f$n-1]
s="":k(' ':)s
((++).r<*>k(k m)).zipWith(++)s.r.f

The anonymous function in the last line takes an integer argument and yields the lines to be printed for a cube of that size.

The idea is to use recursion to draw larger cubes from smaller ones. Lets look at the upper half of a cube of size 1. Then we get the upper half of a cube of size 2 by mirroring the former half and add a fixed pattern of slashes and spaces around it:

                                         /////////\
                                        /////////  \
     /////\    ==>    /\\\\\    ==>    /////\\\\\   \
    /////  \         /  \\\\\         /////  \\\\\   \

So the algorithm to draw a cube of size n is

  1. Get the lines for the upper cube half of size n-1.
  2. Mirror each line (by flipping /s and \s), and pad //// and \ around.
  3. Prepend two lines with the pattern ////n plus /\ and / \.
  4. Mirror the resulting lines to get the full cube.
  5. Pad lines with appropriate number of spaces.

siracusa

Posted 2017-02-18T17:05:42.167

Reputation: 623

3

Anonymous functions are allowed, so you can drop g=. (\l->r l++k(k m)l) is the same as liftM2 (++) r (k(k m)), which again can be shortened to (++).r<*>k(k m). Try it online!

– Laikoni – 2018-03-30T10:54:11.787

2

Ruby, 174 167 169 167 bytes

->n{a=(1..m=n*4).map{' '*m}
(-n..0).map{|i|(-2*i).times{|k|a[y=k+2*j=n+i][m+~k+i*2,2+k*2-s=4*i]=?/*(1-~j%2*s)+'  '*k+?\\*(1-j%2*s)
a[~y]=a[y].tr('/\\','\\\\/')}}
a*$/}

Try it online!

creates an array of n*4 strings filled with spaces, then overwrites it with successively smaller cubes.

Commented code

->n{a=(1..m=n*4).map{' '*m}                 #make an array of n*4 strings of n*4 spaces (up to centreline of final output)
  (-n..0).map{|i|                           #iterate through cube sizes from n down to 0 (i is negative -n to 0)
    (-2*i).times{|k|                        #iterate through the number of lines in the top half of the cube
      a[y=k+2*j=n+i][m+~k+i*2,2+k*2-s=4*i]= #overwrite the correct part of the correct line
      ?/*(1-~j%2*s)+'  '*k+?\\*(1-j%2*s)    #with the correct string of the form "/spaces\" with an additional -4*i symbols on one side
      a[~y]=a[y].tr('/\\','\\\\/')          #copy the current line from top half into bottom half, subsituting / for \ and vice versa
    }
  }
a*$/}                                       #return the elements of the array a, concatenated with newlines $/

Level River St

Posted 2017-02-18T17:05:42.167

Reputation: 22 049

1

Stax, 36 bytes

äª.$u>↓Z╙╝B↨EXª¡╜?Xáhç∙╩p/♂ù⌠r↨c⌐f/*

Run and debug it

This approach builds up the top half of the output iteratively. It executes the main block the specified number of times. In that block, each row is mirrored and has a prefix and suffix added. The top two new rows are added separately. When all the rows are built, they're centered, and then the bottom is mirrored vertically.

Here's the program unpacked, ungolfed, and commented.

{               begin block to repeat
  iHYH^H'\*     make a string of '\' characters and set the Y register
                  pseudo-code: push(((y = (i * 2)) * 2 + 1) * 2 * '\')
                  given the 0-based iteration index `i`, let y = 2 * i
                  and push a string consisting of (i*8 + 2) backslashes
  2M            split the string into to equal size (i*4 + 1) substrings
  ~+            push array to input stack and concatenate
                  on the first iteration, this is a no-op
                  subsequently, it prepends the array to the result so far
  {             begin a block to use for mapping
    4'\*+       append 4 backslashes to this element
    :R          "brace-wise" reverse
                  this reverses the string AND the slashes in it
    |YH3+92&    write 92 to index (++y * 2 + 3) in the array
                  this puts the trailing backslash at the correct position
                  this will be an out of bounds index, so the string will grow
                  92 is the character code for backslash 
  m             execute map using block
}*              repeat block specified number of times
|C              vertically center all rows
{               begin block for output mapping
  Q             output this line without popping
  :Rr           "brace-wise" reverse, and then actually reverse
                  net effect is to swap forward and backward slashes
m               execute map using block
rm              reverse array, and output all rows

Run this one

recursive

Posted 2017-02-18T17:05:42.167

Reputation: 8 616

1

Haskell, 193 bytes

Longer than the winner, but the approach may be interesting -- uses even cos and pi :)

Code:

i s e f|max e f>s=""|max e f<s=" "|e==s="\\"|1<2="/"
w n y x=head$do{d<-[1..n];o<-[-2*d..2*d];z<-[(cos(pi*(n-d)))*o+x];i(2*d)(abs$z-y)(abs$z+y-1)}++" "
n!h=h<$>[1-2*n..2*n]
f n=((2*n)!)<$>n!w n

Run it like this:

mapM_ putStrLn (f 4)

This program basically 'draws' many diamonds like this one:

------------------------
------------------------
-----------/\-----------
----------/  \----------
---------/    \---------
--------/      \--------
--------\      /--------
---------\    /---------
----------\  /----------
-----------\/-----------
------------------------
------------------------

Function i s e f 'draws' one diamond of size s, where e, f are (abs$z-y)(abs$z+y-1).

Function w moves the diamonds drawn by i to correct places. head used in its definition is responsible for looking at the topmost layer only.

Try it here

Radek

Posted 2017-02-18T17:05:42.167

Reputation: 171

1Maybe someone has some ideas how to make the code shorter? – Radek – 2018-04-04T11:31:02.483

0

Charcoal, 42 bytes

FN«↗×⊗⊕ι/↓↘G↖²→⊕×⁴⊕ι↘²\G←⁴↘⊕⊗ι→⁴\M⁴→‖T»‖M↓

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

FN«

Draw the cubes from the smallest to the largest. (Drawing from the largest to the smallest meant that I ended up with a mirror image for odd numbers which cost too many bytes to fix.)

↗×⊗⊕ι/

Print a line of /s. (This will become the \s on the right, but the drawing is done mirrored because it's golfier to mirror at the end of the loop.)

↓↘G↖²→⊕×⁴⊕ι↘²\

Print the top two rows of \s. (Drawing all the \s in one polygon meant that the cursor ended up in an awkward position which cost too many bytes to fix.)

G←⁴↘⊕⊗ι→⁴\

Print the left four rows of \s. (The fifth row comes from the previous cube.)

M⁴→

Move to the start of the next cube.

‖T»

Reflect horizontally ready for the next cube.

‖M↓

Mirror everything vertically to complete the cube.

Neil

Posted 2017-02-18T17:05:42.167

Reputation: 95 035