http://qs321.pair.com?node_id=292544

devslashneil has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,
Recently to pass some time, my friend and i organized a game of golf.
The problem which we set out to solve, was to write a script which takes two arguments (grid coordinates starting from bottom left) and then creates the following patterns.
Pattern created with the coordinates 5,5:
444444444 433333334 432222234 432111234 432101234 432111234 432222234 433333334 444444444
Pattern created with the coordinates 2,3:
666666667 555555567 444444567 333334567 222234567 111234567 101234567 111234567 222234567
etc.
My solution to this problem was:
#!/usr/bin/perl for($y=9;$y>0;$y--){print abs$ARGV[1]-$y>abs$ARGV[0]-$_?abs$ARGV[1]-$y +:abs($ARGV[0]-$_)for(1..9);print"\n"}
However i assume a lot of people could do it in a lot less so if anyone is interested in passing a little bit of time, i would love to see some better solutions :)

Neil Archibald
- /dev/IT -

Replies are listed 'Best First'.
Re: ASCII Pattern - Golf
by JamesDotCom (Initiate) on Sep 19, 2003 at 00:41 UTC

    Also, what he didn't mention is that it stemmed from an argument between PHP and Perl (don't bother preaching, i know the advantages and disadvantages of each, and use both ;)).

    Anyway, this was the PHP solution I came up with.

    #!/usr/bin/php4 -q <? for($i=1;$i<10;$i++){for($n=1;$n<10;$n++){echo max(abs($i-(10-$argv[2] +)),abs($n-$argv[1]));}echo"\n";} ?>

    Not counting the #! line or the <?'s, I was the winner by about 4 characters I think (keeping in mind there was a time limit on the competition).

    Since we basically had the same idea for the algorithm I guess all it really came down to was the length of php/perl's syntax. I have also since seen much much smaller perl answers but I think I would be very hard pressed to make the php solution any smaller.

    - James

Re: ASCII Pattern - Golf
by cLive ;-) (Prior) on Sep 19, 2003 at 02:31 UTC
    Here's an amended version of your attempt that weighs in at 9 characters less:
    #!/usr/bin/perl @q=@ARGV;for($y=9;$y--;){print abs$q[1]-$y>abs$q[0]-$_?abs$q[1]-$y:abs +($q[0]-$_)for(1..9);print$/}

    .02

    cLive ;-)

Re: ASCII Pattern - Golf
by kvale (Monsignor) on Sep 19, 2003 at 00:42 UTC
    Dropping the /usr/bin/perl line, this drops 12 strokes off your loop:
    $x=shift;$y=10-shift;for$a(1..9){for(1..9){$c=abs$y-$a;$d=abs$x-$_;pri +nt$c>$d?$c:$d}print"\n"}

    -Mark

      And getting rid of the for loops appears to take another 10 strokes off.
      $x=shift;$z=10-shift;map{$t=abs$z-$_;print map($t>abs$x-$_?$t:abs$x-$_ +,1..9),$/;}0..9
        You can get 4 more with shift vs pop. + 1 for a useless ;.
        $z=10-pop;$x=pop;map{$t=abs$z-$_;print map($t>abs$x-$_?$t:abs$x-$_,1.. +9),$/}1..9
        (I also fixed a bug.)
Re: ASCII Pattern - Golf
by glwtta (Hermit) on Sep 19, 2003 at 02:13 UTC
    well, this looks like right output:

    ($a,$b)=@ARGV;for($y=9;$y>0;$y--){$c=abs$b-$y;print$/,map{$d=abs$a-$_;$c>$d?$c:$d}(1..9)}

    without cheating it's a few characters longer.

      Let's knock another 4 characters off :)
      ($a,$b)=@ARGV;for($y=9;$y--;){$c=abs$b-$y;print$/,map{$d=abs$a-$_;$c>$ +d?$c:$d}(1..9)}

      .02

      cLive ;-)

      Ahh i really like that one, i was thinking of doing it a similar way but i couldn't get it producing the right output, i also thought of using sort($a-$_,$b-$y)[0]; to get the greatest but couldn't get that working.

      Neil Archibald
      - /dev/IT -
Re: ASCII Pattern - Golf (Russ: 83)
by Russ (Deacon) on Sep 19, 2003 at 02:39 UTC
    I can get 83:
    $i=9;do{print((map{(sort map{abs}$_-$ARGV[0],$i-$ARGV[1])[-1]}1..9),"\ +n")}while--$i

    Russ

      Okay, now 77 (if you don't miss the trailing newline):
      $i=9;do{print"\n",map{(sort abs$_-$ARGV[0],abs$i-$ARGV[1])[-1]}1..9}wh +ile--$i

      Russ

        74 :)
        $i=9;do{print$/,map{(sort abs$_-$ARGV[0],abs$i-$ARGV[1])[1]}1..9}while +--$i
Re: ASCII Pattern - Golf
by davido (Cardinal) on Sep 19, 2003 at 01:02 UTC
    How about this (untested):

    $!/usr/bin/perl @A=map{abs}@ARGV;for($y=9;$y>0;$y--){print$A[1]-$y>$A[0]-$_?$A[1]-$y:( +$A[0]-$_)for(1..9);print$/}

    Basically all I did was eliminate the redundant use of 'abs', and shortened the name of ARGV. Oh, and used $/ instead of "\n" to save two keystrokes. It's about 15 keystrokes shorter, I believe.

    UPDATE:

    Many apologies for bungling my untested attempt. As you pointed out, the abs wasn't exactly redundant. I just read precidence wrong. Actually, it was redundant, but its parameters weren't. In the spirit of "do it once and once only" I broke the common functionality out into a subroutine. And as before, I used $/ instead of "\n". The following IS tested, works, and saves you ten keystrokes (for 98 total, plus the shebang line).

    sub a{abs$ARGV[shift]-pop}for($y=9;$y;$y--){print a(1,$y)>a(0,$_)?a 1, +$y:a(0,$_)for 1..9;print$/}

    Dave

    "If I had my life to do over again, I'd be a plumber." -- Albert Einstein

      I just tested that, and it doesn't seem to work. The abs calls wern't really redundant because you needed to test the greater value displaced from 0, so when you have two negative values -5 < -4 but you still want -5 returned. :)

      UPDATE: Well done with the update, it works nicely when i tested it, i liked the use of the sub too, i only wish the game of golf had a longer time limit so i could have played around with some of these ideas for longer,

      Neil Archibald
      - /dev/IT -
Re: ASCII Pattern - Golf
by halley (Prior) on Sep 19, 2003 at 19:19 UTC
    I wanted to go on a completely different tack using s///, but couldn't get anywhere near as brief a method.
    $_=('x'x9 .$/)x9; substr($_,10*(9-$ARGV[1])+$ARGV[0]-1,1)=0; for$a(0..8){for$b(0,8,9,10){s/(?<=$a.{$b})x|x(?=.{$b}$a)/$a+1/esg}} print;
    Useless but interesting digression: ...

    --
    [ e d @ h a l l e y . c c ]