A Geometrical Challenge

23

6

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

intboolstring

Posted 2016-01-21T16:53:12.050

Reputation: 463

3As 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 – 2016-01-22T03:28:01.013

Answers

9

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.

lirtosiast

Posted 2016-01-21T16:53:12.050

Reputation: 20 331

1Way too long, yet beating Japt by 15 bytes? I can't wait to see how this will be golfed :) – ETHproductions – 2016-01-21T20:52:25.483

Nice solution! You can save a byte by replacing qez\+ with }\+z, because + can only appear in the last position. – isaacg – 2016-01-22T08:01:37.173

6

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.

isaacg

Posted 2016-01-21T16:53:12.050

Reputation: 39 268

5

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

Sp3000

Posted 2016-01-21T16:53:12.050

Reputation: 58 729

5

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>

edc65

Posted 2016-01-21T16:53:12.050

Reputation: 31 086

\d -> ., since there's guaranteed to be exactly one non-digit before and after – ETHproductions – 2016-01-22T00:30:26.723

@ETHproductions right, thanks – edc65 – 2016-01-22T00:34:23.363

Nice. I think this is the optimal algorithm in JS, can't find a shorter one. – ETHproductions – 2016-01-22T01:52:07.827

i.match(/.(.+)(.)/) -> i.match\.(.+)(.)`` – user81655 – 2016-01-22T02:59:57.077

@user81655 nice hint, thanks – edc65 – 2016-01-22T07:57:34.663

4

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

ETHproductions

Posted 2016-01-21T16:53:12.050

Reputation: 47 880

4

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.

Denker

Posted 2016-01-21T16:53:12.050

Reputation: 6 639

How did you count? When using wc this gives me a byte count of 235. Am I wrong? – ბიმო – 2016-01-21T22:16:53.940

1This 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 – 2016-01-21T22:22:01.383

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. – ბიმო – 2016-01-21T22:34:17.717

x being an odd number, you could replace while x>=1: by while x+1: saving one byte and adding an infinite loop for users abusing your program :) – ბიმო – 2016-01-21T22:48:32.857

Could x>=1 be x>0? – ETHproductions – 2016-01-21T22:53:57.433

@ETHproductions Yes in fact, that would still be correct. – ბიმო – 2016-01-22T02:18:11.317

Thanks for the great suggestions! I like the x+1 thing a lot :) I have to use raw_input() tho, because input() evaluates the input which fails because there are numbers in there. On the Byte-Count: On Windows I keep getting 251. Used notepad++ and wc to test it. Am I missing something? – Denker – 2016-01-22T08:26:03.337

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 – 2016-01-22T08:36:25.120

1First, 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 – 2016-01-25T20:37:57.317

3

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

Loovjo

Posted 2016-01-21T16:53:12.050

Reputation: 7 357

The length of your first line is 338 characters. It takes me one monitor and a half to display. – isanae – 2016-01-21T21:09:58.653

3

@isanae It says 220 here.

– Loovjo – 2016-01-21T21:17:47.443

1I 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 – 2016-01-21T21:20:19.053

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 – 2016-01-22T02:52:27.793

@user81655 Yes, I meant in the explanation. Now I understand the confusion! – isanae – 2016-01-23T04:34:43.513

3

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.

wnnmaw

Posted 2016-01-21T16:53:12.050

Reputation: 1 618

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! :) – Denker – 2016-01-22T09:11:30.623

1Actually x=int(d[1:-1])is a lot shorter for that, just saw it in the other python answer. – Denker – 2016-01-22T09:28:38.057

@DenkerAffe, for whatever reason I remember the inverter being optional, so that wouldn't work, but I guess I just made that up – wnnmaw – 2016-01-22T16:37:43.200

2

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.

Neil

Posted 2016-01-21T16:53:12.050

Reputation: 95 035

@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 – 2016-01-22T00:47:52.683

[,b,c]=s.match and later s<'t'... should save some bytes (Firefox only) – edc65 – 2016-01-22T00:53:36.453

@edc65 Just not saving the match in s allows me to use s<'t' which saved me 6 bytes, thanks. – Neil – 2016-01-22T08:41:38.060

2

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.

Martin Ender

Posted 2016-01-21T16:53:12.050

Reputation: 184 808

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: XGQrCiQwJCo6wrYKXigoXHcpKyk6KDorKQokMSQyJDMkMsK2JDAKbWBzJHw6dAoKKWAoLispwrYtKFxEKikKLSQywrYkMQptYF4uCgpHYC4KVGB0czpgICo= (direct copy from Notepad++). Weirdly enough, any online solution gives me 85 bytes... Hum... – Ismael Miguel – 2016-01-22T16:23:17.550

@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 – 2016-01-22T16:26:51.300

2

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

quintopia

Posted 2016-01-21T16:53:12.050

Reputation: 3 899

2

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.

EDIT (July 30, 2016): the linked code replaces 1L3$) by Y) to conform to recent changes in the language

Try it online!

Explanation

' *'        % push string. Will be indexed into to obtain 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

Luis Mendo

Posted 2016-01-21T16:53:12.050

Reputation: 87 464

1

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]

Level River St

Posted 2016-01-21T16:53:12.050

Reputation: 22 049

1

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.

Lince Assassino

Posted 2016-01-21T16:53:12.050

Reputation: 111

1

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

Conor O'Brien

Posted 2016-01-21T16:53:12.050

Reputation: 36 228