# A Geometrical Challenge

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.

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 -.

-
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

## Pyth, 403634 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.

-
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.

-

# 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>

-
\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...

-

# Japt, 62605552 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. :-)

-

# Python 2, 235193167 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

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.

-
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
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
@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
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
-
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
@isanae It says 220 here. – Loovjo Jan 21 at 21:17
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
@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.

-
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
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.

-
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????

-

# 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
-

## ES6, 178172 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.

-
@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.

-

# 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]
-

# 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
-