This is a CC-BY-SA challenge from the CCSC Mid-South Programming Contest 2018.
Author(s): Brent Yorgey
Source: Consortium for Computing Sciences in Colleges Mid-South Programming contest 2018

Good news: you have been hired to do all the special effects for a film! One of the scenes will take place outside, on a windswept plain with a towering mountain range in the background. Your job is to turn a description of the mountain range into a rendered image.

The bad news: the film’s producers have an extremely small budget, and so they can’t afford luxuries like rendered 3D graphics made up of pixels. Hence, you will be making your image out of ASCII characters.

Write a function or full program to produce mountain range ASCII art according to the spec below. This is ; tie breaker is earlier submission.


You will receive a list of 5-tuples in any standard input format for PPCG and/or your language. Each 5-tuple is the values (x, h, z, t, s) representing one mountain of the range you will draw.

  • x is the x-coordinate of the mountain's peak, with 1≤x≤199.
  • h is the height of the mountain, with 1≤h≤100.
  • z indicates the relative distance of the mountain from the viewer, with 1≤z≤m. The smaller the value of z, the closer the mountain is to the viewer. Closer mountains hide ones that are farther away.
  • t is the height of the treeline. The side of the mountain up to the treeline should be filled with trees, represented by the ASCII character Y.
  • s is the height of the snowline. The side of the mountain above the snowline should be filled with snow, represented by the ASCII character *.

The base of each mountain will not extend beyond 0 or 200 horizontally; you may assume that 0≤x−h and x+h≤200. The height of each mountain is no more than 100, so all mountains will fit within a 100x200 grid. The snow and trees will not overlap or exceed the height of the mountain; you may assume that 0≤t≤s≤h. All numbers are non-negative, and all z-values will be unique.


The output should consist of an ASCII drawing of the specified mountain range. Each mountain is triangular in shape with its sides drawn using / and \ characters. For example, here is a mountain of height 4:

  /  \
 /    \
/      \

This mountain has x-coordinate 4, since the horizontal distance from the left margin to its peak is 4 units.

Trees and snow should fill the interior of the mountain but not obscure the sides of the mountain. For example, here is a mountain with height 6, treeline height 2, and snowline height 3:

  /      \

That is, the trees extend from the base of the mountain up to a height of 2 units, and the snow starts at a height of 3 units and extends to the top of the mountain.

Mountains with a smaller z-coordinate may hide all or part of a mountain with a larger z-coordinate; see the third sample input/output below.

Leading whitespace is significant, and should be as specified by the x-position and width of the drawn mountains. Leading/trailing newlines are allowed, and any amount of spaces after each line.


(8, 5, 1, 2, 3)

     /    \

(2, 2, 1, 0, 1)

/  \

(8, 5, 2, 2, 3), (2, 2, 1, 0, 1), (9, 8, 3, 1, 4), (17, 4, 4, 4, 4)

    / /**\   \  /\
   / /    \   \/YY\
 /\ /YYYYYY\   \YYY\

If you find other interesting examples, please share in your answers!


Python 2, 194 191 186 bytes

g=map(list,[' '*200]*100)
for x,h,z,t,s in sorted(input(),key=lambda m:-m[2]):
 for i in range(h):g[-h+i][x+~i:x-~i]=['/']+[' *Y'[(i<h-s)-(i>=h-t)]]*2*i+['\\']
for l in g:print''.join(l)

Try it online!

Prints the whole 100x200 grid.

| improve this answer | |

Ruby, 133 bytes

->a{r=[];a.sort_by{|x|-x[2]}.map{|x,h,z,t,s|h.times{|i|(r[i]||=?\s*200)[x-j=h-i,j*2]=?/+" Y*"[i<t ?1:i<s ?0:2]*~-j*2+?\\}};r.reverse}

Try it online!

Anonymous lambda. Takes input as array of parameter arrays for mountains, returns array of strings.


->a{                 #Input array is a
 r=[];               #Initialize the output array
 a.sort_by{|x|-x[2]} #Sort by decreasing distance
 .map{|x,h,z,t,s|    #Loop through the mountains
  h.times{|i|        #For each mountain fill h lines starting from the ground
   (r[i]||=?\s*200)  #If we haven't yet been so high, initialize with spaces
   [x-j=h-i,j*2]=    #Take a slice from x-(h-i) for double length of h-i
    ?/+" Y*"[i<t ?1:i<s ?0:2]*~-j*2+?\\ #Draw the sides of the mountain (/\),
  } #with (h-i-1)*2 of the appropriately selected filler symbols in the middle
 };r.reverse         #Reverse to the top->bottom order suitable for printing 
| improve this answer | |

Charcoal, 79 bytes

  AθWθ«≔⊟Φθ⁼§κ²⌈Eθ§μ²ι≔Φθ¬⁼κιθ≔§ι¹ηJ§ι⁰±η≔⟦§ι⁴⁻η§ι³η⟧ζFY *«≔⊟ζεG↘ε←⊗ε↗εκ→»P↘η←↙η

Try it online! Link is to verbose version of code. Note: Leading space used to force the required indentation. Explanation:


Loop while the input array is not empty.


Find the most distant mountain in the array.


Remove it from the array.


Get the height of the mountain.


Jump to the top of the mountain.


Get the snowline, treeline and height.

FY *«

Loop over the trees, bare mountain and snow.


Draw a trapezium of the desired height.


Draw the sides of the mountain.

| improve this answer | |

C (clang), 284 261 257 252 bytes

a,b,*z,i,j,k,o;c(*a,*b){return b[2]-a[2];}f(*m,n){qsort(m,n,5*sizeof *m,c);for(i=101;--i>0;puts(""))for(j=0;++j<200;putchar(o))for(o=32,k=0;k<n;z=&m[5*k++],a=z[0]-z[1]+i,b=z[0]-~z[1]-i,o=z[1]/i&&j/a&&b/j?"/\\*Y "[j==a?0:j==b?1:i>z[4]?2:z[3]/i?3:4]:o);}

Try it online!


-3 bytes Thanks Kevin Cruijssen

f() takes these params:

m: array of integers with all mountains' parameters
n: number of mountains

m should be a flat array of specifying x, h, z, t and s for mountains with each mountain's parameters appended to this array.

f() prints full 100x200 grid of ASCII scenery render.


c(*a,*b){return b[2]-a[2];}             //comaprison function for sort by z-order
 qsort(m,n,5*sizeof(*m),c);             //sort mountains by z-order
 for(i=100;i>0;i--,puts("")) {          //for each row
  for(j=1;j<200;j++){                   // for each pixel in this row
   o=' ';                               //initialize pixel to background pixel value
   for(k=0;k<n;k++) {                   // for each mountain, in z-order distant to close
    z=&m[5*k];                          //start pointer for mountain's params
    a=z[0]-z[1]+i;                      //min x limit of mountain on this line
    b=1+z[0]+z[1]-i;                    //max x limit of mountain on this line
    o=z[1]/i && j/a && b/j ? "/\\*Y "[j==a?0:j==b?1:i>z[4]?2:z[3]/i?3:4]:o;
                                        //calculate pixel value ovrwriting previous mountain if necessary
   putchar(o);                  //print pixel value
| improve this answer | |
  • \$\begingroup\$ for(j=1;j<200;putchar(o),j++) can be for(j=0;++j<200;putchar(o)) (-2 bytes) and b=1+z[0]+z[1]-i can be b=z[0]-~z[1]-i (-1 byte) \$\endgroup\$ – Kevin Cruijssen Apr 19 '18 at 14:02
  • \$\begingroup\$ Thanks @Kevin. Applied same trick to i too, saved 2 more bytes. \$\endgroup\$ – GPS Apr 19 '18 at 14:27
  • \$\begingroup\$ Suggest 40 instead of 5*sizeof *m, --i instead of --i>0, b=*z++-~*z-i,o=*z/i&&j/a&&b/j?j-a?j-b?i>z[3]?42:z[2]/i?89:32:92:47:o)a=i-1[z=m+5*k++]+*z instead of z=&m[5*k++],a=z[0]-z[1]+i,b=z[0]-~z[1]-i,o=z[1]/i&&j/a&&b/j?"/\\*Y "[j==a?0:j==b?1:i>z[4]?2:z[3]/i?3:4]:o) \$\endgroup\$ – ceilingcat Jul 9 '18 at 3:00

JavaScript (Node.js), 265 243 229 210 204 203 bytes

a=>a.sort((x,y)=>y[2]-x[2]).map(([x,h,,t,s])=>{for(y=h;y--;)for(i=h+x-y;i--;)(d=R[y]=R[y]||[])[i]=i<x-h+y?d[i]||" ":"Y *\\/"[i>x-h+y?i<h+~y+x?y<t?0:y<s?1:2:3:4]},R=[])&&R.map(x=>s=x.join``+`

Try it online!

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.