ASCII Art of the Day #3 - Chinese Shrines

16

1

In today's episode of AAOD, we are going to construct a Chinese Shrine of varying heights.

Consider the following examples for height (N) 1 to 6

N = 1:

       .
       |
  .   ]#[   .
   \_______/
.    ]###[    .
 \__]#.-.#[__/
  |___| |___|
  |___|_|___|
  ####/_\####
     |___|
    /_____\

N = 2:

         .
         |
    .   ]#[   .
     \_______/
  .    ]###[    .
   \___________/
.     ]#####[     .
 \___]#.---.#[___/
  |__|_|   |_|__|
  |__|_|___|_|__|
  #####/___\#####
      |_____|
     /_______\

N = 3:

           .
           |
      .   ]#[   .
       \_______/
    .    ]###[    .
     \___________/
  .     ]#####[     .
   \_______________/
.      ]#######[      .
 \____]#.-----.#[____/
  |__|__|     |__|__|
  |__|__|_____|__|__|
  ######/_____\######
       |_______|
      /_________\

N = 4:

             .
             |
        .   ]#[   .
         \_______/
      .    ]###[    .
       \___________/
    .     ]#####[     .
     \_______________/
  .      ]#######[      .
   \___________________/
.       ]#########[       .
 \_____]##.-----.##[_____/
  |__|__|_|     |_|__|__|
  |__|__|_|_____|_|__|__|
  ########/_____\########
         |_______|
        /_________\

N = 5:

               .
               |
          .   ]#[   .
           \_______/
        .    ]###[    .
         \___________/
      .     ]#####[     .
       \_______________/
    .      ]#######[      .
     \___________________/
  .       ]#########[       .
   \_______________________/ 
.        ]###########[        .
 \______]###.-----.###[______/
  |__|__|___|     |___|__|__|
  |__|__|___|_____|___|__|__|
  ##########/_____\##########
           |_______|
          /_________\

N = 6:

                 .
                 |
            .   ]#[   .
             \_______/
          .    ]###[    .
           \___________/
        .     ]#####[     .
         \_______________/
      .      ]#######[      .
       \___________________/
    .       ]#########[       .
     \_______________________/ 
  .        ]###########[        .
   \___________________________/ 
.         ]#############[         .
 \_______]####.-----.####[_______/
  |__|__|__|__|     |__|__|__|__|
  |__|__|__|__|_____|__|__|__|__|
  ############/_____\############
             |_______|
            /_________\

and so on.

Construction Details

I am sure most of the details about the pattern are clear. Here are some finer details:

  • The door at the bottom of the shrine can at minimum be of 1 _ width and at maximum be of 5 _ width.
  • There will always be two . directly above the pillars around the door (two vertical |).
  • The stairs start with the same width as the door and increase like show in the pattern
  • The ]##..##[ blocks above each roof level increase in size of 2 from top to bottom.
  • The \__...__/ roofs levels increase in size of 4 from top to bottom.
  • The walls blocks around the door should at minimum contain 1 _ and at maximum, 3 _ between the two |. Priority goes to the outer wall blocks so that the one closest to the door gets a varying size for each level.
  • The space between the . and the ] (or [) is filled by # in the roof just above the doors.

Challenge Details

  • Write a function or full program that reads a positive integer greater than 0 via STDIN/ARGV/function argument or closest equivalent and outputs (to STDOUT or closest equivalent) the Nth Chinese Shrine
  • Trailing newline is optional.
  • There should either be no trailing spaces or enough trailing spaces to pad the output in the minimum bounding rectangle.
  • There should not be any leading spaces that are not part of the pattern.

Leaderboard

The first post of the series generates a leaderboard.

To make sure that your answers show up, please start every answer with a headline, using the following Markdown template:

# Language Name, N bytes

where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:

# Ruby, <s>104</s> <s>101</s> 96 bytes

Optimizer

Posted 2015-05-22T09:51:15.450

Reputation: 25 836

The door width seems rather arbitrary to me - why is it 1 in the N=1 case? Why not 3 and have smaller side windows like in the N=2 case? – Matty – 2015-05-22T13:49:22.430

Also, in the N=1 case, isn't the first rooftop too long (wide)? – Matty – 2015-05-22T13:58:28.320

@Matty regarding door - if door was of width 3, then there would be no # beside the . to support the ] and [ above it. About the starting roof size - That is the roof size in each height's top roof. – Optimizer – 2015-05-22T14:00:26.743

I was asking about the bottom most roof just above the windows. In all other cases it is the size of the roof above it +4 (+2 on either sides). But here it is +8. – Matty – 2015-05-22T14:18:11.313

@Matty oh, you are right. Fixed. – Optimizer – 2015-05-22T14:21:47.173

Why do the N=2 and N=4 cases have leading spaces? – Reto Koradi – 2015-05-23T17:16:08.787

@RetoKoradi because ASCII art and markdown don't go along ? Thanks for pointing out! Fixed! – Optimizer – 2015-05-23T17:20:09.993

Answers

2

CJam, 200 bytes

-4'.-4'|]2/ri:M),{2af.-~[W'.I3+~']'#I)*][-2'\'_I2*4+*]]}fI~[~M)<']
M2m1e>'#*'.'-M3e<:D*][-3"|__"M*M2+M2*(e>:L<"_|"D~][_~~'_*][-3'#L)*
'/'_D*][L2+~'|'_D)*][L)~'/'_D2+*]]{{_0<{~S*}&}%s_W%1>"\/]""/\["erN}%

Newlines added to avoid scrolling. Try it online

Brief explanation:

The program builds the left half of the shrine (including the middle), then reverses it and replaces some characters to get the right half. A series of n spaces is represented as the number ~n (bitwise "not") during construction, and replaced with the actual spaces at the end.

The program starts with the top 2 lines, then for each roof level, it prepends all the previous lines with 2 spaces and adds the new roof (2 lines). The last roof is modified to add the "above door" part.

Next, the upper wall is built by repeating "|__" and truncating at the right length, followed by a fixed "_|" and spaces. The wall is then duplicated and the door spaces are replaced with underscores. Finally, the lower part is constructed line by line.

aditsu quit because SE is EVIL

Posted 2015-05-22T09:51:15.450

Reputation: 22 326

5

Perl, 332 316 294

$:=($w=<>)*2+6;$r=2x($m=$w>3?3:$w);$k=1x($w-3).b.4x$m;
y!a-f1-4!/.|\\[,#_ -!,/,/,s/(.*),(.*).{@{-}}/$2$1/,printf"%$:s%s
",y!/\\[!\\/]!r,(reverse=~s/.//r)for@x=(b,c,
(map{b33.3x$_.e.1x$_,"[#$k,"x/$w/.a__.22x$_}1..++$w),
_c.3x$m.f.($z=substr"|__"x$:,0,2*++$w),"_|$r,$z","d$r,".11x$w,c_.$r,d__.$r)

Try me.

C, 371

d,i,w;char s[1<<24];m(){v(w,13);}p(){puts(s+1);}
v(i,j){s[w-i]=".|]\\#/"[j%7];s[w+i]=".|[/#\\"[j%7];
while(i--)s[w-i]=s[w+i]="# _-"[j/7];}
main(l){scanf("%d",&l);d=l>3?3:l;m(w=l*2+6);p(v(0,0));
for(v(0,1);i++<=l;v(i*2+2,17))p(),v(i*2+3,7),m(p(v(i,2)));v(l+2,2);p(v(d,21));
for(m(i=w-3);i>d+1;i-=3)v(i,15);p(v(d,8));p(v(d,15));
v(w-3,4);m(p(v(d,19)));p(v(d+1,15));p(v(d+2,19));}

Try me.

JavaScript, 365

The above can be translated almost 1 to 1 into JavaScript:

s=[];r="";i=0;m=()=>v(w,13);p=()=>r+=s.join('')+"\n";
v=(i,j)=>{s[w-i]=".|]\\#/"[j%7];s[w+i]=".|[/#\\"[j%7];
while(i--)s[w-i]=s[w+i]="# _-"[j/7|0];};
f=l=>{d=l>3?3:l;m(w=l*2+6);p(v(0,0));
for(v(0,1);i++<=l;v(i*2+2,17))p(),v(i*2+3,7),m(p(v(i,2)));v(l+2,2);p(v(d,21));
for(m(i=w-3);i>d+1;i-=3)v(i,15);p(v(d,8));p(v(d,15));
v(w-3,4);m(p(v(d,19)));p(v(d+1,15));p(v(d+2,19));}

Use:

f(2);console.log(r)

nutki

Posted 2015-05-22T09:51:15.450

Reputation: 3 634

The C version crashes for sizes above 12. Since it looks like you're using a fixed size string to hold temporary results, I think you'll always have an upper limit, no matter how you choose the size of s. Unless you allocate it dynamically, of course. – Reto Koradi – 2015-05-24T15:44:01.710

@RetoKoradi, Yes you are right, I posted version with a small buffer by mistake. But in the end, unless it is dynamically allocated there always will be a limit. – nutki – 2015-05-24T15:56:16.533

4

Python 2, 356 352 347 344 bytes

n=input()
A,B,C,D,E,F,G,H,I='_ |\/#.]['
def p(*S):
 for s in S:print(5+2*n-len(s)/2)*B+s
p(G,C,'.   ]#[   .')
for i in range(n):b=B*(4+i);p(D+A*(7+4*i)+E,G+b+H+F*(3+2*i)+I+b+G)
d=2*min(3,n)-1
a=A*(2+i)
f=F*(1+i-d/2)
j=4+2*i-d/2
w=('|__'*n)[:j-1]+A+C
v=w[::-1]
p(D+a+H+f+G+'-'*d+G+f+I+a+E,w+B*d+v,w+A*d+v,F*j+E+A*d+D+F*j,C+A*(d+2)+C,E+A*(d+4)+D)

This basically builds the shrine line by line. The function p prints a string with the spaces needed to center it.

I used python 2 to save lots of bytes, because the python 3 map object doesn't trigger. I guess I should always golf in python 2, just saves a few more bytes (even if it's just to not have to parse the input to int). Hehehe, it's not like code's pretty for golfing in the first place.

Edit: and of course, I now don't need the map anymore...

Here's the code in ungolfed form:

n = int(input())

# A function to print strings centered
half_width = 5 + 2*n
def p(string):
    spaces = ' ' * (half_width - len(string) // 2)
    print(spaces + string)

# The rooftops
p('.')
p('|')
p('.   ]#[   .')
for i in range(n):
    p('\\' + '_'*(7 + 4*i) + '/')
    p('.{0}]{1}[{0}.'.format(' '*(i + 4), '#'*(3 + 2*i)))

# The bottom rooftop
door_width = 2 * min(3, n) - 1
# (11+4i - (3+2i) - 4) / 2 = (4 + 2i) / 2 = 2 + i
p('\{0}]{1}.{2}.{1}[{0}/'.format('_'*(2 + i), '#'*(1 + i - door_width // 2), '-'*door_width))

# The windows
w = '|__'*n
w = w[:4 + 2*i  - door_width // 2]
if w[-1] == '|':
    w = w[:-1] + '_'
w += '|'
p(w + ' '*door_width + w[::-1])
p(w + '_'*door_width + w[::-1])

# The foundation and the stairs
w = '#'*(4 + 2*i - door_width // 2)
p(w + '/' + '_'*(door_width) + '\\' + w)

# The remaining stairs
p('|' + '_'*(door_width + 2) + '|')
p('/' + '_'*(door_width + 4) + '\\')

Matty

Posted 2015-05-22T09:51:15.450

Reputation: 471

1Since you're using Python 2 you can change print(B*(5+2*n-len(s)//2)+s) into print B*(5+2*n-len(s)/2)+s (remove parentheses and change // into /). – user12205 – 2015-05-22T19:22:28.440

1Thanks @ace, didn't know python2 ignored float division. – Matty – 2015-05-22T19:38:05.163

1@Matty It doesn't ignore float division. You're performing division on integers, so the result is an integer. It only does float division if one or more operands is a float. – mbomb007 – 2015-05-22T21:58:23.330

2If you rearrange the order of print B*(5+2*n-len(s)/2)+s to print(5+2*n-len(s)/2)*B+s, you can remove the space after print. – isaacg – 2015-05-22T23:51:39.393

4

JavaScript (ES6), 440

Edit Fixed lintel bug

A function whith height as a parameter, output to console.

Using template string a lot, all newlines are significant and counted.

Run snippet to test in Firefox (with console output)

f=x=>{R=(n,s=0)=>' #_-'[s][Z='repeat'](n),M=c=>R(2)+'|__'[Z](z+1).slice(0,z-1)+'_|'+R(y,c)+'|_'+'__|'[Z](z+1).slice(1-z)
for(z=x+x+(x<2)+(x<3),y=x>2?5:x>1?3:1,l=-1,o=`${t=R(x+x+5)}.
${t}|
`;l++<x;)o+=`${t=R(x+x-l-l)}.${u=R(l+3)}]${R(l*2+1,1)}[${u}.
 ${t}\\${l-x?R(7+l*4,2):`${t=R(x+1,2)}]${u=R(x<3||x-2,1)}.${R(y,3)}.${u}[${t}`}/
`;console.log(`${o+M(0)}
${M(2)}
${R(2)}${t=R(z,1)}/${u=R(y,2)}\\${t}
${R(1+z)}|__${u}|
${R(z)}/____${u}\\`)}

// TEST
f(1),f(2),f(3),f(4),f(5),f(6)
Output 1 to 6 in console

Ungolfed version for interactive test:

// Not so golfed

f=x=>{
  R=(n,s=0)=>' #_-'[s].repeat(n); // base building blocks
  M=c=>R(2)+'|__'.repeat(z+1).slice(0,z-1)+'_|'+R(y,c)+'|_'+'__|'.repeat(z+1).slice(1-z); // manage door level

  z=x+x+(x<2)+(x<3); // door and stairs surroundings
  y=x>2?5:x>1?3:1; // door and stairs width
  
  o = `${R(x+x+5)}.\n${R(x+x+5)}|\n`; // top 
  for(l=-1;l++<x;)
    o += `${ // even row
      t=R(x+x-l-l) // left padding
    }.${
      u=R(l+3)
    }]${
      R(l*2+1,1)
    }[${
      u
    }.\n ${ // end even row, start odd row
      t // left padding
    }\\${
      l-x?R(7+l*4,2)
      :`${t=R(x+1,2)}]${u=R(x<3||x-2,1)}.${R(y,3)}.${u}[${t}` // if last row before the door, insert lintel 
    }/\n`;
  
  o += `${
    M(0) // door level row 1
  }\n${
    M(2) // door level row 2
  }\n${
    R(2)}${t=R(z,1)}/${u=R(y,2)}\\${t  // stairs row 1
  }\n${ 
    R(1+z)}|__${u  // stairs row 2
  }|\n${ 
    R(z)}/____${u // stairs row 3
  }\\`;
  
  out(o)
}

out=x=>O.innerHTML=x

f(3)
<input id=I value=3><button onclick='f(+I.value)'>-></button><br>
<pre id=O></pre>

edc65

Posted 2015-05-22T09:51:15.450

Reputation: 31 086

2

Haskell, 473 bytes

g '\\'='/'
g '/'='\\'
g '['=']'
g ']'='['
g x=x
z=reverse
d=min 3
m n s=putStrLn$(6+2*n+1-length s)#' '++map g(z s)++tail s
n#c=replicate n c
t 0=".";t n=n#'#'++"["++(2+n)#' '++"."
r 0="|";r n=(2+2*n)#'_'++"/"
q n=d n#'-'++"."++max(n-2)1#'#'++"["++(n+1)#'_'++"/"
e i n=d n#i++"|_"++z(take(max(n+2)(2*n-1))(cycle"|__"))
b n=d n#'_'++"\\"++max(2*n)(3+n)#'#'
w i n=(d n+1+i)#'_'++["|","\\"]!!i
f n=mapM_(m n)$[u k|k<-[0..n],u<-[t,r]]++(t(n+1):map($n)[q,e ' ',e '_',b,w 0,w 1])

Damien

Posted 2015-05-22T09:51:15.450

Reputation: 2 407

OK thanks. Looks correct now – Damien – 2015-05-23T13:22:09.913

I think it's OK now. btw, the base in your N=1 shrine has one more # – Damien – 2015-05-23T13:38:09.430

Yup, works now. Fixed that extra unintended # – Optimizer – 2015-05-23T13:52:39.403

0

C, 660 bytes

The pattern just seemed to be too irregular to come up with anything fancy, particularly in a language without string processing. So here is my brute force approach:

m,d,w,k,j;r(n,c){for(j=0;j++<n;)putchar(c);}c(char*s){for(;*s;)putchar(*s++);}f(n){m=n*2;d=n<3?m-1:5;w=m-d/2+2;r(m+5,32);c(".\n");r(m+5,32);c("|\n");for(;;){r(m-k*2,32);c(".");r(k+3,32);c("]");r(k*2+1,35);c("[");r(k+3,32);c(".\n");if(k==n)break;r(m-k*2+1,32);c("\\");r(k++*4+7,95);c("/\n");}c(" \\");r(n+1,95);c("]");r(n-d/2,35);c(".");r(d,45);c(".");r(n-d/2,35);c("[");r(n+1,95);c("/\n");for(k=0;k<2;){c("  ");for(j=0;j<w/3;++j)c("|__");c("|_|"-w%3+2);r(d,k++?95:32);c(!w%3?"|":w%3<2?"|_":"|_|");for(j=0;j<w/3;++j)c("__|");c("\n");}c("  ");r(w,35);c("/");r(d,95);c("\\");r(w,35);c("\n");r(w+1,32);c("|");r(d+2,95);c("|\n");r(w,32);c("/");r(d+4,95);c("\\\n");}

Before golfing:

#include <stdio.h>

void r(int n, int c) {
    for (int i = 0; i++ < n; )
        putchar(c);
}

void c(char* s) {
    for (; *s; ++s) putchar(*s);
}

int f(int n) {
    int m = n * 2;
    int d = n < 3 ? m - 1 : 5;
    int w = m - d / 2 + 2;

    r(m + 5, 32);
    c(".\n");

    r(m + 5, 32);
    c("|\n");

    for (int k = 0; ; ++k) {
        r(m - k * 2, 32);
        c(".");
        r(k + 3, 32);
        c("]");
        r(k * 2 + 1, 35);
        c("[");
        r(k + 3, 32);
        c(".\n");

        if (k == n) break;

        r(m - k * 2 + 1, 32);
        c("\\");
        r(k * 4 + 7, 95);
        c("/\n");
    }

    c(" \\");
    r(n + 1, 95);
    c("]");
    r(n - d / 2 , 35);
    c(".");
    r(d, 45);
    c(".");
    r(n - d / 2 , 35);
    c("[");
    r(n + 1, 95);
    c("/\n");

    for (int k = 0; k < 2; ++k) {
        c("  ");
        for (int j = 0; j < w / 3; ++j)
            c("|__");
        c("|_|" - w % 3 + 2);
        r(d, k ? 95 : 32);
        c(!w % 3 ? "|" : w % 3 < 2 ? "|_" : "|_|");
        for (int j = 0; j < w / 3; ++j)
            c("__|");
        c("\n");
    }

    c("  ");
    r(w, 35);
    c("/");
    r(d, 95);
    c("\\");
    r(w, 35);
    c("\n");

    r(w + 1, 32);
    c("|");
    r(d + 2, 95);
    c("|\n");

    r(w, 32);
    c("/");
    r(d + 4, 95);
    c("\\\n");

    return 0;
}

Not much to explain here. It just goes line by line, and generates the necessary count of each character. I tried to keep the code itself compact, but it still adds up. d is the width of the door, w the width of each brick wall.

Reto Koradi

Posted 2015-05-22T09:51:15.450

Reputation: 4 870

1c(char*s){for(;*s;)putchar(*s++);} ==> #define c printf; r(n,c){for(j=0;j++<n;)putchar(c);} ==> r(n,C){while(n--)putchar(C);} – user12205 – 2015-05-23T22:47:56.193