Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Everybody loves geometry. So why don't we try and code golf it? This challenge involves taking in letters and numbers and making shapes depending on it.

The Input

The input will be in the form of (shapeIdentifier)(size)(inverter).

But what are shapeIdentifier, size, and inverter?

The shape identifier is the identifier for the type of shape you will be making with *s. The following are the shape identifiers:

  • s - Square
  • t - Triangle

The size will be between 1-20, and it is the size of the figure.

The inverter is whether or not the shape will be upside down, which is denoted by a + or a -. Do note: s3- == (equals) s3+ because squares are symmetric. However, t5- != (does not equal) t5+.

Trailing whitespace is okay in the output but leading whitespace is not.

Output Examples

Input: s3+
Output:
***
***
***

Input: t5+

Output:
  *
 ***
*****

Input: t3-
Output:
***
 *

Special Notes

The triangle input will always be an odd number, so the triangles will always end with 1 * at the top.

The size of the triangle is the size of the base if the inverter is + and is the size of the top if the inverter is -.

share|improve this question
3  
As someone who is taking Geometry right now, (and studying for a Geometry final), I can say with 100% certainty: Geometry is absolutely, not fun at all... D: – Ashwin Gupta Jan 22 at 3:28

15 Answers 15

up vote 9 down vote accepted

Pyth, 40 36 34 32 bytes

-1 byte by @isaacg

JstPz_W}\+zjl#m.[J*\*-J*}\tzyd;J

A semicolon inside a lambda is now the lambda variable's global value, a feature that saves one byte.

                         Implicit: z = input
JstPz                    J = size.
_W }\+z                  Reverse if "+" in z
j l# m                J  Join the nonempty lines in map lambda d:... over range(J)
      .[J            ;   Pad the following with spaces (;) to length J
         *\*               "*", this many times:
            -J*}\tzyd        J if "t" not  in z,
                             otherwise the correct number for a triangle.

Try it here.

Test suite.

share|improve this answer
1  
Way too long, yet beating Japt by 15 bytes? I can't wait to see how this will be golfed :) – ETHproductions Jan 21 at 20:52
    
Nice solution! You can save a byte by replacing qez\+ with }\+z, because + can only appear in the last position. – isaacg Jan 22 at 8:01

Pyth, 38 bytes

JsPtzj?}\szm*\*JJ_W}\-zm.[J*\*hyd;/hJ2

Test suite

Basically as straightforward as it gets. I wish I could combine some of the logic for the two shapes, but currently it's separate.

share|improve this answer

JavaScript (ES6), 142 146 147

Edit 1 byte saved thx @ETHproductions Edit 2 bytes sve thx @user81655

i=>([,a,b]=i.match`.(.+)(.)`,Array(l=i<'t'?+a:-~a/2).fill('*'.repeat(a)).map((r,i)=>l-a?(' '.repeat(i=b<'-'?--l:i)+r).slice(0,a-i):r).join`
`)

Test (run in FireFox)

F=i=>(
  [,a,b]=i.match`.(.+)(.)`,
  Array(l=i<'t'?+a:-~a/2).fill('*'.repeat(a))
  .map((r,i)=>l-a?(' '.repeat(i=b<'-'?--l:i)+r).slice(0,a-i):r)
  .join`\n`
)

function test() { O.textContent=F(I.value) }

test()
Input: <input id=I oninput="test()" value="t11-"/>
<pre id=O></pre>

share|improve this answer
    
\d -> ., since there's guaranteed to be exactly one non-digit before and after – ETHproductions Jan 22 at 0:30
    
@ETHproductions right, thanks – edc65 Jan 22 at 0:34
    
Nice. I think this is the optimal algorithm in JS, can't find a shorter one. – ETHproductions Jan 22 at 1:52
    
i.match(/.(.+)(.)/) -> i.match`.(.+)(.)` – user81655 Jan 22 at 2:59
    
@user81655 nice hint, thanks – edc65 Jan 22 at 7:57

Python 2, 106 bytes

s=raw_input()
n=int(s[1:-1])
for i in[range(1,n+1,2),n*[n]][s<'t'][::2*('+'in s)-1]:print('*'*i).center(n)

The output is a perfect rectangle, with each line padded with trailing spaces, which I'm assuming is okay based on the comments in the OP.

Note: I'm still never sure whether input is allowed in Python 2 for problems like these...

share|improve this answer

Japt, 62 60 55 52 51 bytes

V=Us1 n;U<'t?Vo ç*pV):0oV2 £S²pY iY'*pV-X})·z2*!Uf-

Try it online!

The first thing we need to do is figure out how big our shape needs to be. This is pretty simple:

      // Implicit: U = input string, S = space
V=    // Set variable V to
Us1   // everything after the first char of U,
n;    // converted to a number. This turns e.g. "12+" into 12.

Now we organize the shape of the output:

U<'t?      // If U comes before "t" lexicographically (here, if the first char is "s"),
Vo         //  make a list of V items,
ç*pV)      //  and set each item to V asterisks.
:0oV2      // Otherwise, create the range [0, V) with steps of 2 (e.g. 7 -> [0,2,4,6]),
£       }) //  and map each item X and index Y to:
S²pY       //   Repeat 2 spaces Y times. This creates a string of Y*2 spaces.
iY'*pV-X   //   At position Y in this string (right in the middle), insert V-X asterisks.
·          // Join with newlines.

By now, we have taken care of the size and shape of the output. All that's left is the rotation. Triangles are currently pointed up, so we need to flip them if the third char is +:

!Uf-    // Take the logical not of U.match("-").
        // If U contains "-", this returns false; otherwise, returns true.
2*      // Multiply by two. This converts true to 2, false to 0.
z       // Rotate the list 90° that many times.
        // Altogether, this turns the shape by 180° if necessary.

And with implicit output, our work here is done. :-)

share|improve this answer

Python 2, 235 193 167 157 Bytes

Update:

Made some significant optimizing by using list comprehensions and str.center(). I have the feeling I can do some more tho, gonna hava a fresh look at it later.

Update 2

Saved 10 Bytes with the suggestions of Sherlock9. Thanks a lot! :)

d=raw_input()
x=int(d[1:-1])
o="\n".join("*"*x for i in range(x))if d<"t"else"\n".join(("*"*i).center(x)for i in range(x,0,-2))
print o[::-1]if"+"in d else o

Old answer

d=raw_input()
x=int(d[1:-1])
if "s" in d:
 for y in range(x):
    o+="*"*x+"\n"
 o=o[:-1]
else:
 b=0
 while x+1:
    o+=" "*b+"*"*x+" "*b+"\n"
    x-=2
    b+=1
 o=o[:-1]
 if d[-1]=="+":
    o=o[::-1]
print o

Pretty straighforward approach. Writing line per line in a string which I output in the end. Triangles are always drawn inverted and get reversed if needed. The fact that you can multiply a string with an Integer saved me a lot of bytes!

I will try to golf that down a bit more later, would appreciate suggestions in the meantime, since I am not that much exprienced with it yet.

edit: Golfed it down a lot with the help in the comments and stealing the size-calculation from one of the other python-answers. I think thats the most I can do with this algorithm.

share|improve this answer
    
How did you count? When using wc this gives me a byte count of 235. Am I wrong? – Bruce_Forte Jan 21 at 22:16
1  
This is indeed 235 bytes. Golfing advice: Use tabs instead of two spaces, which is valid in Python 2 and will shave off 5 bytes. – Doorknob Jan 21 at 22:22
    
Also you don't need to use raw_input, using input saves you 4 bytes. Further you don't need the brackets in the second line, this and not using the variable x at all (using if"s"in d) saves you another 9 bytes. – Bruce_Forte Jan 21 at 22:34
2  
@DenkerAffe when counting in window, subtract 1 byte for each newline - newlines are 2 bytes in windows, but 1 byte in other environments – edc65 Jan 22 at 8:36
1  
First, you can remove the [] brackets in each of the join function calls. Second, if d<"t"else is shorter and works because "s3+"<"t"<"t3+" in Python. Third, else"\n".join and .center(x)for. No space. It isn't required. Fourth, print o[::-1]if"+"in d else o where I rearranged things for two bytes (one space between ] and if and another between if and "+". – Sherlock9 Jan 25 at 20:37

JavaScript, 220 bytes.

q=s=>+s.slice(1,s.length-1);f=s=>s[0]=="s"?("*".repeat(q(s))+"\n").repeat(q(s)):Array.apply(0,Array(-~(q(s)/2))).map((_,n)=>(s[s.length-1]=="-"?~~(q(s)/2)-n:n)).map(n=>(" ".repeat(q(s)/2-n)+"*".repeat(n*2+1))).join("\n")

Run with f(input here)

Try it here!

The squares has trailing newlines, but the triangles don't. Explanation:

q=s=>+s.slice(1,s.length-1);                                                                                                                                                                                                 Define a function, q, that takes returns the argument, without the first and last character, casted into an integer.
                            f=s=>                                                                                                                                                                                            Define a function, f, that takes one argument, s. (This is the main function)
                                 s[0]=="s"?                                                                                                                                                                                  If the first character of s is "s" then...
                                           ("*".repeat(q(s))     )                                                                                                                                                           Repeat the "*" character q(s) times.
                                           (                +"\n")                                                                                                                                                           Append a newline to that
                                                                  .repeat(q(s))                                                                                                                                              Repeat that q(s) times.
                                                                               :                                                                                                                                             Else... (the first character of s isn't "s")
                                                                                Array.apply(0,Array(          ))                                                                                                             Create an array of length...
                                                                                Array.apply(0,Array(-~(q(s)/2)))                                                                                                             floor(q(s)/2)+1
                                                                                                                .map((_,n)=>                                   )                                                             Map each element, _ with index n to...
                                                                                                                .map((_,n)=>(s[s.length-1]=="-"?              ))                                                             If the last element of s is "-" then...
                                                                                                                .map((_,n)=>(s[s.length-1]=="-"?~~(q(s)/2)-n  ))                                                             floor(q(s)/2)-n
                                                                                                                .map((_,n)=>(s[s.length-1]=="-"?            : ))                                                             Else...
                                                                                                                .map((_,n)=>(s[s.length-1]=="-"?             n))                                                             Just n
                                                                                                                                                                .map(n=>                                        )            Map each element into...
                                                                                                                                                                .map(n=>(" ".repeat(q(s)/2-n)                   )            Repeat " ", q(s)/2-n times.
                                                                                                                                                                .map(n=>(                   )+"*".repeat(n*2+1)))            Append "*", repeated 2n+1 times.
                                                                                                                                                                .map(n=>(" ".repeat(        )+"*".repeat(n*2+1))).join("\n") Join with newlines
share|improve this answer
    
The length of your first line is 338 characters. It takes me one monitor and a half to display. – isanae Jan 21 at 21:09
3  
@isanae It says 220 here. – Loovjo Jan 21 at 21:17
1  
I won't click on a random tinyurl link, but check again. In any case, try avoiding scroll bars in code boxes, it makes it much harder to read. – isanae Jan 21 at 21:20
1  
@Loovjo I think he means the first line of the explanation. I usually indent my explanation rather than this style for JavaScript answers so you don't need to scroll to see half of it. – user81655 Jan 22 at 2:52
    
@user81655 Yes, I meant in the explanation. Now I understand the confusion! – isanae Jan 23 at 4:34

Python 2, 157 132 bytes

def f(s):
 S=int(s[1:-1])
 for n in([range(1,S+2,2),range(S,0,-2)]['-'in s],[S]*S)['s'in s]:
  print "{:^{S}}".format('*'*n,S=S)

First attempt firgured that the +/- on the end was optional, getting rid of that let me shave off a bunch

The idea here is to make a list which can get thrown into a generic output. Hardest part was separating out the length from the input.

share|improve this answer
    
For getting the length I used x=int(d[1]if len(d)<4 else d[1:3]) with d being the input string. Thats 5 Bytes shorter than your solution. You are still way ahead of my python-answer tho, gotta try to understand what you did there and beat you next time! :) – DenkerAffe Jan 22 at 9:11
1  
Actually x=int(d[1:-1])is a lot shorter for that, just saw it in the other python answer. – DenkerAffe Jan 22 at 9:28
    
@DenkerAffe, for whatever reason I remember the inverter being optional, so that wouldn't work, but I guess I just made that up – wnnmaw Jan 22 at 16:37

Retina, 102 85 bytes

Byte count assumes that the source code is encoded as ISO 8859-1.

\d+
$0$*:¶
^((\w)+):(:+)
$1$2$3$2¶$0
m`s$|:t

)`(.+)¶-(\D*)
-$2¶$1
m`^.

G`.
T`ts:` *

Try it online.

I'll try to golf this some more later.

share|improve this answer
    
Notepad++ says that your code is 89 bytes, not 85. I've used the ISO-8859-1 encoding, and went on Edit > EOL Convertion > UNIX/Linux Format, to use \n instead of \r\n. Base64 of the content: XGQrCiQwJCo6wrYKXigoXHcpKyk6KDorKQokMSQyJDMkMsK2JDAKbWBzJHw6dAoKKWAoLispwrYtKFx‌​EKikKLSQywrYkMQptYF4uCgpHYC4KVGB0czpgICo= (direct copy from Notepad++). Weirdly enough, any online solution gives me 85 bytes... Hum... – Ismael Miguel Jan 22 at 16:23
    
@IsmaelMiguel There's gotta be something off with how Notepad++ counts the . They are definitely a single byte in ISO 8859-1 (with value 182). – Martin Ender Jan 22 at 16:26

Seriously, 54 bytes

,#i's=`≈;'**@½≈";#dXdXεj' +"£n`@`≈;'**n`@Iƒ('-=WXa0WXü

Try It Online

,#i                                                    Take input, push chars separately
   's=                                   Iƒ            IF the first char is "s":
                                `      `@                run the quoted function
                                 ≈;'**n                  make list of n strings of n *'s
      `                       `@                       ELSE run the quoted function:
       ≈;                                                make two copies of int n
         '**                                             use one to make string of n *'s
            @½≈                                          cut the other in half (e.g. 5->2)
               "           "£n                           run n/2 times the quoted function:
                ;#                                        copy the string as list of chars
                  dXdX                                    discard the last 2 *'s
                      εj                                  join back into string
                        ' +                               prepend a space
                                           ('-=WX 0WX  IF the third character is "-":
                                                 a       invert the stack
                                                     ü pop and print the entire stack

@Mego: See that #dXdXεj? STRING SLICING????

share|improve this answer

MATL, 48 bytes

' *'jt4Y2m)U1$l't'Gm?2MQ2/:1L3$)R!P!R'+'Gm?P]]Q)

Uses current version (10.1.0) of the language/compiler.

The code accepts input characters in any order: all s11+, 11s+ and even 1+s1 would be valid input strings.

Try it online!

Explanation

' *'        % push string. Will be index into for to final result
j           % input string
t           % duplicate
4Y2         % predefined literal string '0123456789'
m           % logical index of digits in input string
)           % index into input string to obtain substring with digits
U           % convert to number
1$l         % generate square of ones with that size
't'         % push character 't'
G           % push input string
m           % true if input string contains 't'
?           % if so...
  2M        % push argument of call to function `l`, i.e. square size
  Q2/       % add 1 and divide by 2. Call result T
  :         % generate vector [1, 2, ... T]
  1L        % predefined literal representing Matlab's `:` index
  3$)       % two dimensional index. Transforms square into rectangle
  R         % remove (set to zero) lower-left corner
  !P!       % flip horizontally
  R         % remove lower-left corner. This gives inverted triangle
  '+'       % push character '+'
  G         % push input
  m         % true if input contains '+'
  ?         % if so...
    P       % flip vertically
  ]         % end if
]           % end if
Q           % add 1. This gives array of values 1 and 2
)           % index string ' *' with this array to produce char array
            % implicitly display that char array
share|improve this answer

ES6, 178 172 159 bytes

s=>(p=s.match(/d+|./g),u=n=+p[1],m=n+1>>1,t=' '.repeat(n)+'*'.repeat(n),v=s<'t'?0:p[2]<'-'?(u=m,1):-1,[...Array(s<'t'?n:m)].map(_=>t.substr(u,u,u+=v)).join`
`)

This works due to an interesting observation I made. If you repeat n spaces and n asterisks you get (e.g. for n=5) this:

     *****

Now, take substrings with the same start and length:

     |*****| (5)
    | ***| (4)
   |  *| (3)

These substrings are exactly the strings we need for t5.

Edit: Saved 6 bytes thanks to @edc65.

Edit: Saved 13 bytes thanks to hiding the u+=v in the third argument of substr thus allowing me to simplify the initialisation.

share|improve this answer
    
@ThomasKwa Huh, after I'd fixed the t handling code it turned out that w and u became equivalent and that saved me enough bytes to take me back down to 178! – Neil Jan 22 at 0:47
    
[,b,c]=s.match and later s<'t'... should save some bytes (Firefox only) – edc65 Jan 22 at 0:53
    
@edc65 Just not saving the match in s allows me to use s<'t' which saved me 6 bytes, thanks. – Neil Jan 22 at 8:41

C, 259 bytes

#define x(y);)putchar(y)
#define m(n)for(n=0;n++<
#define T {m(q)i x(32);m(q)s-i*2 x(42);puts("");}
main(q,v,i,s)char**v;{s=atoi(v[1]+1);if(*v[1]=='s')m(i)s*s x(42)&&!(i%s)&&puts("");else if(strchr(v[1],'+'))for(i=s/2+1;i-->0;)T else for(i=-1;i++<s/2+1;)T}

ungolfed

main(q,v,i,size)char**v; // neat way of declaring variables
{
    size=atoi(v[1]+1);
    if(*v[1]=='s')
    {
        for(i=0;i++<size*size;)
        {
            putchar(42); // returns 42 (true)
            if(!(i%size))
                puts("");
        }
    }
    else if(strchr(v[1],'+')) // if finds plus sign
    {
        for(i=size/2+1;i-->0;) // iterate the height of the triangle
        {
            for(q=0;q++<i;)putchar(32); // conveniently i is the number os spaces before each line
            for(q=0;q++<size-i*2;) putchar(42);
            puts("");
        }
    }
    else for(i=-1;i++<size/2+1;) // does the same as above but inverted order
    {
        for(q=0;q++<i;)putchar(32);
        for(q=0;q++<size-i*2;)putchar(42);
        puts("");
    }
}

Suggestions and critique are very welcome.

share|improve this answer

Ruby, 99

->s{n=s[1,2].to_i
n.times{|i|d=(s.ord-115)*(s[-1]<=>?,)*(n-1-i*2)
d<1&&puts((?**(n+d)).center(n))}}

Calculates a square or triangle of height n and average width n by verying the slope of the sides (so the calculated triangle width is 2n-1 at the base, 1 at the tip.) But it only prints those rows which do not exceed n characters.

ungolfed in test program

f=->s{                         #take a string as an argument
  n=s[1,2].to_i                #take 2 characters starting at index 1 and convert to a number for the size
  n.times{|i|                  #iterate through n rows    
    d=                         #calculate how many stars "MORE THAN" n we need on a row
    (s.ord-115)*               #ascii code for 1st character of string - 115 : s-->0, t-->1
    (s[-1]<=>?,)*              #compare last character of input with comma character - --> +1 + --> -1
    (n-1-i*2)                  #row number * 2: 0 at centre, positive above it, negative below it
    d<1&&                      #only output if d is nonpositive (i.e we need less than n or exactly n stars)
    puts((?**(n+d)).center(n)) #print n+d stars, centred in a field of n characters padded by whitespace
  }
}

f[gets.chomp]
share|improve this answer

Jolf, 37 bytes, noncompeting

I added functions after this challenge was posted, so this cannot be considered for acceptation. This is encoded in ISO-8859-7. Try all test cases here.

onFiΒ€ioSgiγ?='sn―sΒ'*―TΒ1'*?='-SZiγγ

Part 1: parsing the string

onFiΒ€ioSgi
on          set n to
  Fi         the first entity of i (the shape identifier)
    Β       set Β (beta) to
     €i      the "inside" of i (in this case, the size) as a number
       oS   set S to
         gi  the last entity of i (the inverter)

Part 2: obtaining the result

γ?='sn―sΒ'*―TΒ1'*
γ                 set γ (gamma) to the result of the following expression
 ?='sn             if n is the character s,
      ―sΒ'*         then return a pattern "s" (a square) made with "*"s
           ―TΒ1'*    otherwise, return a pattern "T" (triangle) that is centered and
                     has a scale factor of 1, made with "*"s

Part 3: inverting the result

?='-SZiγγ
?='-S     if S is a "-"
     Ziγ   return γ, inverted across its lines
        γ  otherwise, return γ untouched
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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