23
\$\begingroup\$

For golfing practice, I have been doing the assignments in my girlfriend's Intro to Python class. I found that for this assignment, there were multiple strategies that came very close in character count, and I'm sure people here can find even better ways. Although I am most interested in ways to do this in Python, I would like to know the most golfed this program can get, therefore this is code golf and shortest answer wins.

The Rules:

The assignment is outlined below. The user should be asked to input twice, although the prompts don't have to say anything, and can be in a different order.

Standard loopholes apply.


Assignment 3: Arrows

Write a program that prompts the user for a number of columns, and them prints the pattern as seen below. You can assume that the user will supply positive numbers. Your program should handle both left and right arrows. Here are a few sample runnings:

How many columns? 3
Direction? (l)eft or (r)ight: r
*
 *
  *
 *
*
How many columns? 5
Direction? (l)eft or (r)ight: l
    *
   *
  *
 *
*
 *
  *
   *
    *
\$\endgroup\$
  • 23
    \$\begingroup\$ This looks like homewo... oh, nevermind. \$\endgroup\$ – TessellatingHeckler Oct 6 '15 at 19:08
  • \$\begingroup\$ Are trailing spaces on each line permitted? \$\endgroup\$ – lirtosiast Oct 6 '15 at 19:20
  • \$\begingroup\$ @ThomasKwa yes. \$\endgroup\$ – aks. Oct 6 '15 at 19:22
  • \$\begingroup\$ Can we use control characters to move the cursor, as in this question? \$\endgroup\$ – lirtosiast Oct 6 '15 at 19:26
  • \$\begingroup\$ @ThomasKwa Sure... although I'm honestly not sure what that means and I'm interested in seeing it in action. \$\endgroup\$ – aks. Oct 6 '15 at 19:30

18 Answers 18

8
\$\begingroup\$

Pyth, 23 bytes

May or may not be valid, based on the answer to this comment. Regardless, I found this neat, and, if it is invalid, the other Pyth answers are also invalid. ;) Well, it's valid, because I apparently missed the blatantly obvious. :/

EDIT: I WON!!!! YESSS!!!! First time ever! :D

j+_J_Wqz\r.e+*dkb*\*QtJ

Live demo.

\$\endgroup\$
  • 1
    \$\begingroup\$ m+*\ d\*Q instead of that enumerate thingy. Saves 2 bytes. \$\endgroup\$ – Jakube Oct 11 '15 at 9:30
7
\$\begingroup\$

Pyth, 27

j<tQ_Wqz\l++Jm+*\ d\*Q_PJtJ

Try it online

The basic idea here is to build one string that, for say 5, looks like this:

*
 *
  *
   *
    *
   *
  *
 *
*
 *
  *
   *
    *

And then flip it upside down if we get l as our input. Then we take all but the last input-1 lines of this string and print it out.

\$\endgroup\$
7
\$\begingroup\$

Python 2, 81 79 bytes

c=input()
r=1
l=0
exec"print' '*(%sabs(c-r))+'*';r+=1;"%("c+~"*input())*(2*c-1)

Might still be golfable, but we'll see :)

\$\endgroup\$
  • 2
    \$\begingroup\$ Nice idea with having the inputs be variables l and r. I hadn't realized the input is eval'ed in the same environment as the code. \$\endgroup\$ – xnor Oct 7 '15 at 2:41
4
\$\begingroup\$

Pyth, 30 28 27 bytes

VtyQ+*+*tQJqz\r_WJ.a-hNQd\*

Try it online.

Apparently I'm currently tied with FryAmTheEggman with a completely different approach. (I think that one is ingenious.)

Example

$ python pyth.py spa.p
r
3
*
 *
  *
 *
*

$ python pyth.py spa.p
l
5
    *
   *
  *
 *
*
 *
  *
   *
    *

Explanation

 tyQ                              (columns * 2) - 1
V                               loop N through range(the above)
        tQ                                columns - 1 (maximum number of spaces)
       *                                multiplied by
           qz\r                           1 if direction == "r" else 0
          J                               also save that 1 or 0 to J
      +                               plus
                  .a-hNQ                    abs(N - columns + 1)
               _WJ                      negate that if direction == "r"
     *                  d           that many spaces
    +                    \*       add the star and print
\$\endgroup\$
  • \$\begingroup\$ @Pietu1998 I still am interested in a basic description of what you're doing. I see you only have 1 loop and no map or lambda... \$\endgroup\$ – aks. Oct 6 '15 at 19:21
  • \$\begingroup\$ @aks. I added an explanation. \$\endgroup\$ – PurkkaKoodari Oct 6 '15 at 19:38
4
\$\begingroup\$

PowerShell, 91 85 102 Bytes

$c=(Read-Host)-1;if(!$c){"*";exit}(@(0..$c+($c-1)..0),@($c..0+1..$c))[(Read-Host)-eq'l']|%{" "*$_+"*"}
  • Gets the columns, stores it in $c. We subtract one because each column also has an * and we're only interested in how many spaces are required.
  • If the entered value was a 1, print * and exit - rest of the script doesn't make a difference.+
  • The next section first gets the direction and tests whether it's -equal to l, then creates an array based on indexing into an array of dynamically generated arrays based on the value of $c. Magic. Essentially, this is how many spaces per line we need.
  • For example, for 5 r this collection would hold (0,1,2,3,4,3,2,1,0).
  • Takes the array and pipes it into a Foreach-Object % loop, where we output a string of X number of spaces, then the *

Example usage:

PS C:\Tools\Scripts\golfing> .\simple-printing-arrows.ps1
6
r
*
 *
  *
   *
    *
     *
    *
   *
  *
 *
*

Edit - removed variable $e by piping the collection directly
Edit2 - correctly accounts for 1 column, now

+ If it's still mandatory to take input for direction for 1-column arrows (I contend it is not), we can swap the positioning of the Read-Host and lose a couple more bytes by re-introducing the $d variable, for 106:

$c=(Read-Host)-1;$d=Read-Host;if(!$c){"*";exit}(@(0..$c+($c-1)..0),@($c..0+1..$c))[$d-eq'l']|%{" "*$_+"*"}
\$\endgroup\$
  • \$\begingroup\$ Try putting 1 column, and left - you get a 2-column right arrow. Try putting 1 column and right - you get a 'Specified argument out of the range of valid values' error. I thought your 85 would be possible to beat by avoiding the doubled-up-ranges. But I can't even get close. Accounting for a 1 column arrow, I'm currently at 112 chars. >_< \$\endgroup\$ – TessellatingHeckler Oct 7 '15 at 1:52
  • 1
    \$\begingroup\$ @TessellatingHeckler Thanks - corrected. \$\endgroup\$ – AdmBorkBork Oct 7 '15 at 2:11
  • 1
    \$\begingroup\$ That's pushed yours up to 102 and mine is down to 102. I can't bare to stare at this any longer, but there must be one more I can delete... :D \$\endgroup\$ – TessellatingHeckler Oct 7 '15 at 2:29
4
\$\begingroup\$

TI-BASIC, 75 65 57 54 50 47 Bytes

Thanks to @ThomasKwa for the correct byte calculation and golfing 10 bytes.

Tested on my TI-84+ Silver Edition.

First TI-BASIC submission, golfing suggestions welcome (I don't know many tricks yet). If name plays a factor in memory shown, this one's was 3 characters instead of 1 (I looked at the byte count on my calculator itself). This program is limited by the output function's restrictions (I think to arrows of length 4), but I could probably switch to text, which displays graphically if that is too low of a length.

Prompt L,Str1
Str1="R
For(I,1,2L-1
Output(I,(1-2Ans)abs(I-L)+AnsL+1,"*
End

Note that this also doesn't clear the screen or pause it.

I really feel like the equation I'm using can be golfed more. It also feels so wrong to exclude the ending quotation mark.

\$\endgroup\$
  • \$\begingroup\$ @ThomasKwa Thanks! I'll do that now. \$\endgroup\$ – cole Oct 7 '15 at 0:53
  • 2
    \$\begingroup\$ Second: Ans is free, because you don't use it for input and Output( doesn't modify Ans. Use it, and get rid of the variable A. You can assign using -2(Str1="R; no need for a conditional. \$\endgroup\$ – lirtosiast Oct 7 '15 at 1:09
  • 1
    \$\begingroup\$ @ThomasKwa thanks for the tips, looks like I've got a ways to go in TI-BASIC. \$\endgroup\$ – cole Oct 7 '15 at 2:14
  • 3
    \$\begingroup\$ Third: There's really no need to multiply the value by -2. Just do Str1="R for the second line. That makes the fourth line Output(I,(1-2Ans)abs(I-L)+AL+1,"*, which nets you 4 more bytes. But wait, there's an idiom for (1-2Ans)—it's cos(πAns), which saves one byte, plus one more because we get the open parenthesis for free! \$\endgroup\$ – lirtosiast Oct 7 '15 at 3:12
  • 1
    \$\begingroup\$ Becoming proficient in golfing in any language requires only practice; you'll get there. \$\endgroup\$ – lirtosiast Oct 7 '15 at 3:13
2
\$\begingroup\$

Python 2, 89 bytes

c=input()-1
d=raw_input()>'l'
for j in range(2*c+1):print' '*(d*c-(2*d-1)*abs(c-j))+'*'

Works almost identically to my Pyth answer, just calculating the correct number of spaces on the fly.

\$\endgroup\$
2
\$\begingroup\$

PowerShell, 104 102 97 bytes

# 97 version:
$o=@(($c=(read-host)-1))[(read-host)-eq'l'];($j=2*$c)..0|%{' '*[Math]::Abs($o++%($j+!$j)-$c)+'*'}

3
r
*
 *
  *
 *
*

# Previous 102 version:
$o=@(($c=(read-host)-1))[(read-host)-eq'l'];(2*$c)..0|%{
' '*[Math]::Abs($o++%(2*($c+(!$c+0)))-$c)+'*'}

NB. if you want to run it again, open a new PowerShell, or rv o to reset the variable state.

Compared to how terse the others are, this hurts. [Hurts less at 97 than it did at 122]. Two parts to it, neither of them very surprising; reads a number of columns, uses an array-index-ternary-operator-substitute to get an offset, and runs through a wave function starting at the offset (and a tweak so it doesn't fall over doing mod 0).

(And ouch did I spend ages on that wave function, unable to spot my misunderstanding, and typing all the it's-not-LISP-,honest parens).

\$\endgroup\$
  • 2
    \$\begingroup\$ That's bloody brilliant. \$\endgroup\$ – AdmBorkBork Oct 7 '15 at 3:02
2
\$\begingroup\$

Python 2, 98 89 bytes

f=[' '*n+'*'for n in range(input())]
if'l'==input():f=f[::-1]
print'\n'.join(f+f[-2::-1])

A little more lengthy.


Usage

$ python2 test.py
3
"l"
  *
 *
*
 *
  *
\$\endgroup\$
  • \$\begingroup\$ Also apparently broken. NameError: name 'l' is not defined, NameError: name 'd' is not defined. \$\endgroup\$ – TessellatingHeckler Oct 7 '15 at 2:00
  • \$\begingroup\$ Check the usage. @TessellatingHeckler \$\endgroup\$ – Zach Gates Oct 7 '15 at 2:20
  • \$\begingroup\$ Ahh, clever. But your 1-column arrows have two arrow heads. (I think you could golf it further by not storing i and d at all, just using range(P()) and if P()=='l'...) \$\endgroup\$ – TessellatingHeckler Oct 7 '15 at 2:26
  • \$\begingroup\$ Thanks for the suggestions! I also fixed the double arrow heads. @TessellatingHeckler \$\endgroup\$ – Zach Gates Oct 7 '15 at 2:55
  • \$\begingroup\$ Can't test atm, but you could probably do something like f=[...][::2*('r'>input())-1] actually \$\endgroup\$ – Sp3000 Oct 7 '15 at 3:09
2
\$\begingroup\$

Perl, 85 bytes

($-,$_)=<>;$,=$/;@}=map$"x$_.'*',0..--$-;@}=reverse@}if/l/;print@},map$}[$--$_],1..$-

Usage:

perl 59874.pl <<< '6
r'
\$\endgroup\$
  • 4
    \$\begingroup\$ I like how you name your scripts something you'll recognize them by later... \$\endgroup\$ – mbomb007 Oct 6 '15 at 20:39
  • \$\begingroup\$ @mbomb007 haha! You know, I don't actually name my scripts that, but I thought it was best to name something simple for usage instructions... simplearrows2.pl doesn't seem as good! :P \$\endgroup\$ – Dom Hastings Oct 7 '15 at 4:47
2
\$\begingroup\$

PHP, 156 Bytes

<?for($c=1+fgets(STDIN);--$c;$s[-$c]=$t[]=sprintf("%{$c}s","*"));arsort($s);$a=fgetc(STDIN)==r?$s+$t:$t+$s;array_splice($a,count($a)/2,1)?><?=join("
",$a);

Creates two arrays, like this:

$t = [
    0 => "  *"
    1 => " *"
    2 => "*"
]
$s = [
    -1 => "*"
    -2 => " *"
    -3 => "  *"
]

then uses array union $s+$t or $t+$s to combine them and array_splice to remove the element in the middle. Finally output using <?=join()

\$\endgroup\$
  • \$\begingroup\$ with CLI arguments instead of STDIN my code would be 8 bytes shorter ;) \$\endgroup\$ – Fabian Schmengler Oct 9 '15 at 14:03
2
\$\begingroup\$

Python 2, 111 109 104 bytes

Pretty simple solution. I'm sure it can be golfed more. For those who don't know, ~x+n is the same as n-1-x.

n=input()
r=range(n)
r+=r[-2::-1]
for i in[r,[~x+n for x in r]]['r'>raw_input()]:print"*".rjust(i+1," ")

Try it online

Edit: This was golfed into the last line:

if'r'>d:r=[~x+n for x in r]
for i in r:print"*".rjust(i+1," ")
\$\endgroup\$
2
\$\begingroup\$

Matlab, 109 105 96 bytes

Thanks to @beaker for saving me 9 bytes.

x=eye(input(''));if(input('','s')<114),x=fliplr(x);end
x=x*10+32;disp(char([x;x(end-1:-1:1,:)]))
\$\endgroup\$
  • \$\begingroup\$ You can save 9 bytes if you replace the two lines inserting the ascii codes with x=x*10+32; \$\endgroup\$ – beaker Oct 9 '15 at 0:48
  • \$\begingroup\$ @beaker Very clever, thanks! \$\endgroup\$ – Luis Mendo Oct 9 '15 at 10:13
1
\$\begingroup\$

Ruby, 118 bytes

2.times{l,d=gets.split;l=l.to_i;a=(d=="r"?(0..l-1):(l-1).downto(0)).to_a;(a+a[0..-2].reverse).each{|x| puts "#{' '*x}*"}}

2.times{ -- twice, of course...

l,d=gets.split; -- get the input

l=l.to_i; -- change length to an integer

a=(d=="r"?(0..l-1):(l-1).downto(0)).to_a; -- create an array from the range of 0 to the length

(a+a[0..-2].reverse).each{|x| puts "#{' '*x}*"} -- iterate, turn into the strings to make the arrows

Not exactly the greatest golf ever, but, hey.

\$\endgroup\$
1
\$\begingroup\$

PowerShell, 98 94 Bytes

$c=(Read-Host)-1;$d=Read-Host;if($c){$c..0+1..$c|%{if($d-eq'r'){$_=$c-$_}' '*$_+'*'}}else{'*'}

If I could find a way to put the Read-Host for direction inside the foreach-object loop but only prompt for it once I might be able to save a few bytes.

Edit: 94 bytes. Instead of testing for left, test for right (simplifies the loop).

Original 98 byte:

$c=(Read-Host)-1;$d=Read-Host;if($c){0..$c+($c-1)..0|%{if($d-eq'l'){$_=$c-$_}' '*$_+'*'}}else{'*'}
\$\endgroup\$
  • \$\begingroup\$ Resetting the $_ variable -- tricksy Hobbit. Very clever, and I learned something today. \$\endgroup\$ – AdmBorkBork Oct 7 '15 at 12:55
  • \$\begingroup\$ @TimmyD Very tricksy. And then switch the if statement to save even more. \$\endgroup\$ – Jonathan Leech-Pepin Oct 7 '15 at 13:29
0
\$\begingroup\$

><>, 60 bytes

i"1l"i=&-:&*&:?!\:1-:}c0.
~/?:<-$?&::&;!?l<oao"*"
1/  \o" "-

2 wasted bytes on the bottom line, how irritating!

Due to how input works in ><>, it's not possible to 'wait' for input - the i command checks if an input character is available on STDIN. If there is, it pushes the ASCII value of that character, and pushes -1 if not.

This means that, in order to use this program, the number and direction must already be ready on STDIN, e.g. 3r for a size 3 arrow pointing to the right. I'm not sure if that disqualifies this entry, let me know your thoughts :o)

I'll also write up a description if anyone wants one.

\$\endgroup\$
  • \$\begingroup\$ In a sense it does wait for input if you try to run it in a shell, so I think that's fine. I'm more concerned with the fact that this expects the input to be a single digit though (unless I'm meant to input : for 10?) \$\endgroup\$ – Sp3000 Oct 7 '15 at 13:11
  • \$\begingroup\$ An excellent point, I hadn't thought about input over 9. Back to the drawing board! \$\endgroup\$ – Sok Oct 7 '15 at 13:28
  • 1
    \$\begingroup\$ I've left a comment on the main question for a clarification, just in case \$\endgroup\$ – Sp3000 Oct 7 '15 at 13:30
0
\$\begingroup\$

PHP, 154 bytes

It looks really repetitive, but it does the desired:

$c=$argv[1];$b=l==$argv[2]?1:0;$a=$b?$c:-1;function a($a){echo strrev(str_pad('*',$a))."\n";}while($b?--$a:++$a<$c)a($a+1);while($b?++$a<=$c:1<$a--)a($a);

Runs from command line like:

php arrow.php 5 l
php arrow.php 5 r
\$\endgroup\$
-1
\$\begingroup\$

Python, 88 Bytes

Edited

n=input()-1
x=raw_input()>'l'
for i in range(2*n+1):print" "*(n*x+(-1)**x*abs(n-i))+"*"
\$\endgroup\$

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.