Print out a shape in printable ASCII art based on a specific number of sides provided by the user

6

1

The Challenge:

Just as the title says, your challenge is to use the printable ASCII characters to create a program that prints out a random polygon in the terminal based on the number of sides, n provided by the user, where n is an integer in the range 3 -> 10 including 3 and 10, in as few bytes as possible.

For example:

If n = 4 it should print out a 4 sided shape. For instance, it may print out a square, like so:

 ______
|      |
|      |
|______|

However, if the program is called again with the same attribute of n=4, it should print out a different polygon based on the same number of sides. For instance, maybe a plain, old parallelogram this time, like so:

    ______________
   /             / 
  /             /
 /_____________/

As another example, consider n=6. At least once, it should print out a 6-sided polygon, such as the convex hexagon shown below:

    ________
   /        \  
  /          \
 /            \
 \            /
  \          /
   \________/

But another time, it should print out a visually different polygon with 6 sides, for instance, maybe a concave hexagon like the following:

________
\      /
 \    /
  \  /
  /  \
 /    \
/______\

Finally, as a last example, if n=3, it may print out an isosceles triangle:

    / \
   /   \
  /_____\

However, another call with the same attribute should print out another kind of triangle, maybe like the following right triangle:

    /|
   / |
  /__|

EDIT: To fulfill @CatsAreFluffy's request, here is an example of an ASCII nine-sided polygon:

    ___
   /   \
  /     \
 /       \
 \       /
  \     /
   \   /
   /   \
  /     \
 /       \
 \       /
  \     /
   \   /
    \ /
     v

NOTE: These are all just examples. Your polygons can be drawn in any style, as long as they meet the guidelines shown below.

Guidelines:

  • Each number of sides, from 3-10, should have at least 2 different shapes associated with it.

  • The program should print out a random shape from the shapes associated with each number of sides each time the program is executed with a specific number of visually distinguishable sides in the range 3 -> 10 given as an argument.

  • The sides of the each polygon can be any length, such that every shape able to be drawn by the entire program has at least one side with the same length as all the others. For instance, a triangle should have at least one side with the same length as one of the sides of a parallelogram. So should the square, pentagons, rectangles, etc. with the parallelogram, and also with each other. As a reference, in the examples given in the challenge sections, each shape has at least one side with a length of 3 slashes.

  • Standard loopholes apply.

R. Kap

Posted 2016-03-25T19:02:27.163

Reputation: 4 730

For your square and hourglass, you have the top overhanging the sides, but for the parallelogram and hexagon the top is "inside" the sides. Is that intentional? Can submissions choose either style, as fits their design? – AdmBorkBork – 2016-03-25T19:37:35.223

@TimmyD Those are just examples. Submissions can choose any style they want, as long as the submissions meet the guidelines given. – R. Kap – 2016-03-25T19:38:52.747

I think you mean hexagon, not pentagon for your n = 6 example. – DoctorHeckle – 2016-03-25T19:39:11.953

@DoctorHeckle Yes, you're right. I meant hexagon. – R. Kap – 2016-03-25T19:39:37.487

Can the sides overlap themselves? – Blue – 2016-03-26T02:03:07.370

@Blue Actually, now that I think about it, yes they can. Like I said in my post, they can be any style as long as the program follows the guidelines given. – R. Kap – 2016-03-26T03:33:57.560

Can we take # of program runs from input? Would make testing on online interpreters easier (as persistent data requires file io) – CalculatorFeline – 2016-03-26T03:42:25.857

@CatsAreFluffy For testing you can do whatever you want, as long as in the final version of the code, the input is a specific number of sides in the range 3 => 10 including 3 and 10. With that said, I wish you good luck! :) – R. Kap – 2016-03-26T03:49:02.927

Can I have an example of a 9-sided ASCII polygon? – CalculatorFeline – 2016-03-26T03:52:08.570

@CatsAreFluffy Okay. Please look at the edit. – R. Kap – 2016-03-26T04:14:02.160

@R.Kap That last example isn't ascii. – Conor O'Brien – 2016-05-17T20:37:22.243

@CᴏɴᴏʀO'Bʀɪᴇɴ Now it should be. :) – R. Kap – 2016-05-17T20:48:01.710

Can I print a filled polygon instead of a wireframe? If I can, then I may be able to do it eith resterization. – Bálint – 2016-05-19T20:05:09.903

@Bálint Yeah, sure, that's fine, as long as I can distinguish between different sides. – R. Kap – 2016-05-19T20:06:38.197

Answers

9

Java, 1887 1866 bytes

Try in on Ideone

Saved 21 bytes due to unneeded "public" headers (Thanks to @Bálint!)

Not exactly a golfing challenge, but hey, why not?

I feel Java might actually be the best language for this challenge because no esolang could handle this, and many others don't have as good list manipulation (although Java's takes way more bytes).

Golfed:

import java.util.*;public class A{public static void main(String[]args){System.out.print((new P()).b(Integer.parseInt((new Scanner(System.in)).next())).s());}}class P{S p;public S b(int w){p=new S(w);int j=-1,k=-1,f=(w%2)*2,t,y,x;for(x=0;x<w/2-2+w%2;x++){t=r();y=r();if(j==t|k==y|t==y){x--;continue;}g(t,true,2);g(y,false,2-f);f=0;j=t;k=y;}while(1>0){t=r();y=r();if(w<4&t<1&y<1)continue;if(j==t|k==y|t==y|j==y){x--;continue;}g(t,true,3);g(y,false,3+(w<4?0:(w%2)*2));break;}return p;}void g(int w,boolean b,int h){if(w<1)p.u(h,b);else if(w<2)p.r(h,b);else p.l(h,b);}int r(){return (int)(Math.random()*3);}}class S{List<List<Character>>q,a;int h,s,u,o,e,r,b,t,g,n,m,x,y;public S(int d){s=d;h=s+s%2-1;u=h;o=h;b=s>3?(int)(Math.random()*3*s)+1:0;q=new ArrayList<List<Character>>();a=new ArrayList<List<Character>>();for(x=0;x<h;x++){q.add(new ArrayList<Character>());a.add(new ArrayList<Character>());}i(0,q);i(0,a);e=1;r=1;t=0;g=0;n=0;m=0;}public String s(){String p="";for(x=0;x<e+b+r;x++)p+=x>t+(s<4?1:0)&x<e+b+g?'_':' ';p+="\n";for(y=0;y<h;y++){for(x=0;x<e;x++)p+=y>h-2&x>n?'_':q.get(y).get(x);for(x=0;x<b;x++)p+=y>h-2?'_':' ';for(x=0;x<r;x++)p+=y>h-2&x<m-1?'_':a.get(y).get(x);p+="\n";}return p;}void i(int i,List<List<Character>>z){for(List<Character>l:z)l.add(i,' ');if(z==q){e++;if(i<=t)t++;if(i<=n)n++;}else{r++;if(i<=g)g++;if(i<=m)m++;}}void u(int v,boolean i){if(i){u-=v;for(y=0;y<v;)q.get(u+y++).set(t,'|');}else{o-=v;for(y=0;y<v;)a.get(o+y++).set(g,'|');}}void l(int v, boolean i){if(i){x=v-t;while(x-->0)i(0,q);t=x>0?0:t-v;u-=v;for(y=0;y<v;)q.get(y+u).set(t+y++,'\\');}else{x=v-g;while(x-->0)i(0,a);g=x>0?0:g-v;o-=v;for(y=0;y<v;)a.get(y+o).set(g+y++,'\\');}}void r(int v,boolean i){if(i){t+=v;y=t;while(e<=y)i(e,q);t=y-1;u-=v;for(y=0;y<v;)q.get(u+y).set(t-y++,'/');}else{g+=v;y=g;while(r<=y)i(r,a);g=v<1?g:y-1;o-=v;for(y=0;y<v;)a.get(o+y).set(g-y++,'/');}}}

Must be in file called A.java (for obvious reasons). To run:

  1. In the terminal, type javac A.java
  2. Then, if it gives you no errors, type java A
  3. Finally, type the number of sides. This program actually supports side lengths up to 65536

As you can see in the example output below, the corners tend to be more open, and the sides not as smooth, as compared to the polygons in the examples. Also, it cannot produce a square, but still follows the official guidelines. If there are any problems I can change the answer to fix them.

Sample output:

3

  / |
 /  |
/___|


4
   ____    
  /    \   
 /      \  
/________\ 


5
   _________ 
  /         |
 /          |
/           |
\           |
 \ _________|


6
  ____________    
 |            \   
 |             \  
 |              \ 
 /               |
/_______________ |


7
 _____________________  
\                     / 
 \                   /  
  \                 /   
   |               /    
   |              /     
   \              \     
    \ _____________\    


8
 _______________  
\               / 
 \             /  
  \           /   
   |          \   
   |           \  
   /            | 
  /____________ | 


9
 __________  
\          / 
 \        /  
  \      /   
   |    /    
   |   /     
   /   \     
  /     \    
  |      |   
  |_____ |   


10
   ____     
  /    \    
 /      \   
/        \  
|         / 
|        /  
\        |  
 \       |  
  /      \  
 /________\ 

EDIT: Finally! the ungolfed code is here! It's a bit long, but you probably already guessed that...

I will get to the explanation soon.

import java.util.*;
public class ASCII_Polygon_Driver
{
   public static void main(String[] args)
   {
      System.out.print(P.b(Integer.parseInt((new Scanner(System.in)).next())));
   }
}
class P
{
   static S p;
   public static S b(int w)
   {
      p = new S(w);
      int l1=-1,l2=-1,f=(w%2)*2,r1,r2,x;
      for(x=0;x<w/2-2+w%2;x++)
      {
         r1=r();
         r2=r();
         if(l1==r1){x--;continue;}
         if(l2==r2){x--;continue;}
         if(r1==r2){x--;continue;}
         g(r1,true,2);
         g(r2,false,2-f);
         f=0;
         l1=r1;
         l2=r2;
      }
      while(true)
      {
         r1=r();
         r2=r();
         if(w<4&r1<1&r2<1)continue;
         if(l1==r1|l2==r2|r1==r2|l1==r2){x--;continue;}
         g(r1,true,3);
         g(r2,false,3+(w<4?0:(w%2)*2));
         break;
      }
      return p;
   }
   static void g(int w,boolean b,int h)
   {
      if(w<1)p.goUp(h,b);
      else if(w<2)p.goRight(h,b);
      else p.goLeft(h,b);
   }
   static int r()
   {
      return (int)(Math.random()*3);
   }
}
class S
{
   public List<List<Character>> area1;
   public List<List<Character>> area2;
   private int wid1;
   private int wid2;
   private int spcb;
   public int hght;
   private int top1;
   private int top2;
   private int bot1;
   private int bot2;
   private int mid1;
   private int mid2;
   public int sides;
   private int x;
   private int y;
   public int y1;
   public int y2;
   public S(int numSides)
   {
      sides = numSides;
      hght = sides+sides%2-1;
      y1=hght;
      y2=hght;
      spcb = sides>3?(int)(Math.random()*3*sides)+1:0;
      area1 = new ArrayList<List<Character>>();
      area2 = new ArrayList<List<Character>>();
      for(x=0;x<hght;x++)
      {
         area1.add(new ArrayList<Character>());
         area2.add(new ArrayList<Character>());
      }
      insertCollum1(0);
      insertCollum2(0);
      wid1 = 1;
      wid2 = 1;
      top1 = 0;
      top2 = 0;
      bot1 = 0;
      bot2 = 0;
   }
   public String toString()
   {
      String out ="";

      for(x=0; x<wid1+spcb+wid2; x++)
      {
         out+=x>top1+1&x<wid1+spcb+top2?'_':' ';
      }
      out+="\n";
      for(y=0; y<hght; y++)
      {
         for(x=0; x<wid1; x++)out+=y>hght-2&x>bot1?'_':area1.get(y).get(x);
         for(x=0; x<spcb; x++)out+=y>hght-2?'_':' ';
         for(x=0; x<wid2; x++)out+=y>hght-2&x<bot2-1?'_':area2.get(y).get(x);
         out+="\n";
      }
      return out;
   }
   private void insertCollum1(int index)
   {
      for(List<Character> line : area1)
      {
         line.add(index,' ');
      }
      wid1++;
      if(index<=top1)top1++;
      if(index<=bot1)bot1++;
   }
   private void insertCollum2(int index)
   {
      for(List<Character> line : area2)
      {
         line.add(index,' ');
      }
      wid2++;
      if(index<=top2)top2++;
      if(index<=bot2)bot2++;
   }
   /*private void setChar1(int x, int y, char character, List<List<Character>> which)
   {
      which.get(y).set(x,character);
   }*/
   public void goUp(int howMany, boolean is1)
   {
      if(is1)
      {
         y1-=howMany;
         for(y=0;y<howMany;)
         {
            area1.get(y1+y++).set(top1,'|');
         }
      }
      else
      {
         y2-=howMany;
         for(y=0;y<howMany;)
         {
            area2.get(y2+y++).set(top2,'|');
         }
      }
   }
   public void goLeft(int howMany, boolean is1)
   {
      if(is1)
      {
         x = howMany-top1;
         while(x-->0)insertCollum1(0);
         top1 = Math.max(0,top1-howMany);
         y1-=howMany;
         for(y=0;y<howMany;)
         {
            area1.get(y+y1).set(top1+y++,'\\');
         }
      }
      else
      {
         x = howMany-top2;
         while(x-->0)insertCollum2(0);
         top2 = Math.max(0,top2-howMany);
         y2-=howMany;
         for(y=0;y<howMany;)
         {
            area2.get(y+y2).set(top2+y++,'\\');
         }
      }
   }
   public void goRight(int howMany,boolean is1)
   {
      if(is1)
      {
         top1+=howMany;
         y=top1;
         while(wid1<=y)insertCollum1(wid1);
         top1=y-1;
         y1-=howMany;
         for(y=0;y<howMany;)
         {
            area1.get(y1+y).set(top1-y++,'/');
         }
      }
      else
      {
         top2+=howMany;
         y=top2;
         while(wid2<=y)insertCollum2(wid2);
         top2=howMany<1?top2:y-1;
         y2-=howMany;
         for(y=0;y<howMany;)
         {
            area2.get(y2+y).set(top2-y++,'/');
         }
      }
   }
}

Blue

Posted 2016-03-25T19:02:27.163

Reputation: 1 986

And, to be honest, I am actually not experienced in Java whatsoever. I am more a Python person. With that said, when I ran your code in my Mac's Terminal, I got this error: A.java:1: cannot find symbol symbol : class Shetring location: class S. Maybe you can fix it soon as I cannot since I am not experienced in that language. At least not yet. – R. Kap – 2016-03-27T02:16:37.047

@R.Kap That's a weird error. When I ran it on my computer (Windows) and on Ideone (online compiler, link on answer), it worked fine. What version of Java are you using? EDIT-- oh, I forgot to tell you how to run it. I'll edit my answer. – Blue – 2016-03-27T11:01:33.340

I finally got it to work in my Terminal, and I have to say, amazing job! It does everything according to the guidelines, and still works perfectly! Great job! :) – R. Kap – 2016-03-27T17:47:33.873

Do you need the methods to be public? Default isn't enough? – Bálint – 2016-05-19T20:06:27.427

@Bálint good catch; u, r and l don't need to be public – Blue – 2016-05-19T20:09:55.770

Also, if you only use Scanner from java.util, then you can do new java.util.Scanner instead of importing it (I can't really tell, as the code is really, really messy) – Bálint – 2016-05-19T20:13:50.163

@Bálint no, I use ArrayList as well – Blue – 2016-05-19T20:14:22.887

t=0;g=0;n=0;m=0 can be t=g=n=m=0 – Bálint – 2016-05-19T20:15:27.297

@Bálint I didn't know you could do that! (BTW I'm on mobile, so I can't test until I get to my computer) – Blue – 2016-05-19T20:20:15.977

You can also get the input as arguments, and create a function instead of a whole program. – Bálint – 2016-05-19T20:21:07.810

How many possible shapes would you say this can output for each input integer in the range 3=>10? – R. Kap – 2016-05-19T20:28:43.720

@R.Kap there are 3^(n-2) different side patterns for n>3, 6 for n=3 – Blue – 2016-05-19T20:39:17.367

Instead of Integer.parseInt((new Scanner(System.in)).next()) you can do new Scanner(System.in).nextInt()). – R. Kap – 2016-06-24T09:04:02.743

And, instead of while(true) you can do for(;;). – R. Kap – 2016-06-24T09:05:51.080