An instinctive perlgolf attempt ("fizz buzz"!)

M

Michele Dondi

David Flanagan in his book "Java examples in a nutshell" mentions a
game called "fizz buzz"[1] in which two players must enumerate numbers
from 1 to 100 in turns saying 'fizz' if the number is divisible by 5,
'buzz' if it is divisible by 7 and 'fizzbuzz' if it is divisible by
both.

Then he gives a Java program running a version of the game in which of
course there aren't two players but numbers or 'fizz's and 'buzz's are
simply printed to STDOUT. So it was natural (well, for me!) to think
about the same thing[2] in Perl...

So, why not thinking about the shortest way to do it, too?!? Well, my
first idea was something along the lines of

#!/usr/bin/perl -l
print[$_,fizz,buzz,fizzbuzz]->[!($_%7)*2+!($_%5)]for 1..100

that indeed is interesting on its own IMHO, but I was really bothered
by that 'fizzbuzz' thing and OTOH any trick to avoid inserting it as a
literal seemed more expensive.

Eventually this is the best I can do:

#!/usr/bin/perl
print+($_%5?'':fizz).($_%7?'':buzz)||$_,$/for 1..100

(-l is more expensive as of the rules I know for perlgolf, see e.g.
<http://perlgolf.terje.org>).

Anything "better"?


[1] Source code for the book is available online so I guess one should
be able to find easily the program mentioned in this paragraph, if
interested.

[2] Actually the original program prints its output as a space
separated list, but it seems *to me* more perl(golf)-customary to ask
for a newline-separated list instead.


Michele
 
J

Jay Tilton

: David Flanagan in his book "Java examples in a nutshell" mentions a
: game called "fizz buzz"[1] in which two players must enumerate numbers
: from 1 to 100 in turns saying 'fizz' if the number is divisible by 5,
: 'buzz' if it is divisible by 7 and 'fizzbuzz' if it is divisible by
: both.

I remember a version of that game that involved beer.

: So, why not thinking about the shortest way to do it, too?!? Well, my
: first idea was something along the lines of
:
: #!/usr/bin/perl -l
: print[$_,fizz,buzz,fizzbuzz]->[!($_%7)*2+!($_%5)]for 1..100
:
: that indeed is interesting on its own IMHO, but I was really bothered
: by that 'fizzbuzz' thing and OTOH any trick to avoid inserting it as a
: literal seemed more expensive.

: Eventually this is the best I can do:
:
: #!/usr/bin/perl
: print+($_%5?'':fizz).($_%7?'':buzz)||$_,$/for 1..100
:
: Anything "better"?

print+fizz x/0|5$/.buzz x!($_%7)||$_,$/for 1..100
 
J

Jeff 'japhy' Pinyan

False positive on 101, 102, 103, etc. (anything with a '0' in it is
fizz'd). /0|5$/ needs to be /[05]$/, which is only +1 char.
 
U

Uri Guttman

J'P> False positive on 101, 102, 103, etc. (anything with a '0' in it is
J'P> fizz'd). /0|5$/ needs to be /[05]$/, which is only +1 char.

then convert to the % form as with 7 for a tie:


print+fizz x/0|5$/.buzz x!($_%7)||$_,$/for 1..100
print+fizz x/p05]$/.buzz x!($_%7)||$_,$/for 1..100
print+fizz x!($_%5).buzz x!($_%7)||$_,$/for 1..100

uri
 
M

Michele Dondi

: print+($_%5?'':fizz).($_%7?'':buzz)||$_,$/for 1..100
:
: Anything "better"?

print+fizz x/0|5$/.buzz x!($_%7)||$_,$/for 1..100

D'Oh!

Well... not that much "D'Oh" after all: I *did* expect someone to come
up with something "better", just being curious about that
"something"...


Michele
 
G

G Klinedinst

Michele Dondi said:
Then he gives a Java program running a version of the game in which of
course there aren't two players but numbers or 'fizz's and 'buzz's are
simply printed to STDOUT. So it was natural (well, for me!) to think
about the same thing[2] in Perl...
Anything "better"?

I definately am not anywhere near everyone else's level, but thanks
for the fun game late on a Friday. I tried with recursion just for
fun.

#!/usr/local/bin/perl
z(1);
sub z
{
my $a=shift; my $r;
if($a>100){return();}
else{if($a%5==0){$r="fizz"}
if($a%7==0){$r.="buzz"}print $r||$a;z($a+1);}
}


I had use strict, and -w in there but removed it for space reasons.

-Greg
 
M

Michele Dondi

J'P> False positive on 101, 102, 103, etc. (anything with a '0' in it is
J'P> fizz'd). /0|5$/ needs to be /[05]$/, which is only +1 char.

Since the "requirements" (admittedly loosely stated) were to play the
game for 1..100, the code above definitely yields the expected output.

Just don't know wether the author was aware of this (strongly suspect
so!) or if it was a lucky case, but who cares anyway?
then convert to the % form as with 7 for a tie:

print+fizz x/0|5$/.buzz x!($_%7)||$_,$/for 1..100
print+fizz x/p05]$/.buzz x!($_%7)||$_,$/for 1..100
print+fizz x!($_%5).buzz x!($_%7)||$_,$/for 1..100

also,

print+fizz x/0$|5$/.buzz x!($_%7)||$_,$/for 1..100

But then the one with ($_%5) indeed is better. However the good point
IMHO is in using the x operator that is something I hadn't thought of,
struggling with or's that couldn't work because

0 . 0 ? 'true' : 'false'

is 'true'...

Which is also the good point of perl golfing, i.e. not just competing,
not just squeezing the very last charachter off one's code. But using
smartly operators in techniques that may be OK also for non-so-extreme
situations.

BTW:

(-l is more expensive as of the rules I know for perlgolf, see e.g.
<http://perlgolf.terje.org>).

I got that wrong: it is <http://terje.perlgolf.org>


Michele
 
M

Michele Dondi

#!/usr/local/bin/perl
z(1);
sub z
{
my $a=shift; my $r;
if($a>100){return();}
else{if($a%5==0){$r="fizz"}
if($a%7==0){$r.="buzz"}print $r||$a;z($a+1);}
}


I had use strict, and -w in there but removed it for space reasons.

So you have a strict- and warnings- safe perl golf script. But since
you removed 'use strict' and -w (but you surely know that with recent
enough perls it is better to 'use warnings', don't you?), what is the
point having it safe in that sense?

More clearly your attempt is strange in that it shows some golfing
beahaviour along with unnecessary "features", like (just to take an
example)

if($a>100){return();}

whereas it may have been

return if $a>100;

also in a non-perl-golfing context: IMHO the second form is much
clearer since it hasn't any unnecessary annoying punctuation. After
all this is Perl, not C!

However if you really want to try a *recursive* golfing solution, why
don't you adapt Jay Tilton's one?

#!/usr/local/bin/perl
sub z{($_=pop)>100?exit:print+fizz x/0|5$/.buzz
x!($_%7)||$_,$/;z($_+1)}z(1)


Michele
 
G

G Klinedinst

Michele Dondi said:
(but you surely know that with recent
enough perls it is better to 'use warnings', don't you?)

Nope, I didn't know that. The book I have says use the "-w" switch.
More clearly your attempt is strange in that it shows some golfing
beahaviour along with unnecessary "features", like (just to take an
example)

if($a>100){return();}

whereas it may have been

return if $a>100;

also in a non-perl-golfing context: IMHO the second form is much
clearer since it hasn't any unnecessary annoying punctuation. After
all this is Perl, not C!

I agree that the second form is shorter, and since the whole idea was
to do it as short as possible it is better, but if I were to write
this program to actually use I would use the first form b/c it is more
readable to me. BTW, what is golfing( other than a fun sport )?

However if you really want to try a *recursive* golfing solution, why
don't you adapt Jay Tilton's one?

#!/usr/local/bin/perl
sub z{($_=pop)>100?exit:print+fizz x/0|5$/.buzz
x!($_%7)||$_,$/;z($_+1)}z(1)

Because I was trying not to use other people's examples, while I was
writing mine. Plus I don't understand what is going on in it.

Thanks for looking at my program, I will take another shot at it over
lunch if I have time.

-Greg

BTW, the fizz buzz problem I came across on line while looking for
detailed instructions said that one should "fizz" on anything
divisible by 5, or with 5 in the number, and likewise "buzz" on
anything divisible by 7 or with 7 in the number. "Fizzbuzz" would be
the same thing, divisible by 5 & 7 or containing the 5 & 7 anywhere in
the number. Just thought you might be interested in trying that form
too.
 
M

Matt Garrish

G Klinedinst said:
I agree that the second form is shorter, and since the whole idea was
to do it as short as possible it is better, but if I were to write
this program to actually use I would use the first form b/c it is more
readable to me. BTW, what is golfing( other than a fun sport )?

Not the most intuitive name for it, but it does make sense after you read
this quote:

This type of coding competition was named Perl Golf by Greg Bacon because in
both Perl and physical golf the goal is to finish with the fewest
(key)strokes.

Matt
 
M

Michele Dondi

[slighty edited for clarity]
I agree that the second form is shorter, and since the whole idea was
to do it as short as possible it is better, but if I were to write
this program to actually use I would use the first form b/c it is more
readable to me.

Well, readability is subjective of course. I'll repeat myself here:
IMHO the second form is more readable. It is also a typical example of
the natural language principles that are so pervasive in Perl.

You may enjoy reading 'perldoc perlstyle', but of course you're
encouraged to follow your own style. However to stress the point of
view that I'm trying to illustrate, I'll point out that

return if $a>100;

is not by any means the shortest WTDI:

$a>100&&return;

and since in that context return()ing meant to terminate the script,
also

$a>100&&exit;

OTOH I *cannot* understand how "();" can improve readability when you
have *all* these equivalent possibilities (amongst the others):

if($a>100){return();};
if($a>100){return()};
if($a>100){return;};
if($a>100){return();}
if($a>100){return()}
if($a>100){return;}
if($a>100){return}
if($a>100){return};
return if $a>100;
return() if $a>100;
$a>100 and return();
$a>100 && return();
$a>100 and return;
$a>100 && return;
...

BTW: now that I come to think of it, do you know that $a and $b are
not *exactly* generic variables? Consider the following example:

# perl -wMstrict -e '$a=1'
Name "main::a" used only once: possible typo at -e line 1.
# perl -wMstrict -e '$c=1'
Global symbol "$c" requires explicit package name at -e line 1.
Execution of -e aborted due to compilation errors.

Surprised? See 'perldoc perlvar' and 'perldoc -f sort' then...
Because I was trying not to use other people's examples, while I was
writing mine. Plus I don't understand what is going on in it.

A quote:

He "steals".
You "reuse".
I "enhance the value of".
- "Alex" on comp.lang.perl.misc (slightly edited)

(this is a .sig of mine)

As far as "what is going on in it" is concerned, generally I'd
recommend to ask perl to help you with B::Deparse, as in:

# perl -MO=Deparse fizzbuzz.pl
;
foreach $_ (1 .. 100) {
print 'fizz' x /0|5$/ . 'buzz' x !($_ % 7) || $_, $/;
}
fizzbuzz.pl syntax OK
# perl -MO=Deparse,-p fizzbuzz.pl
;
foreach $_ (1 .. 100) {
print(((('fizz' x /0|5$/) . ('buzz' x (!($_ % 7)))) || $_), $/);
}
fizzbuzz.pl syntax OK

but in this case it doesn't make much difference, and in fact the
original code is already quite transparent. All you have to do is to
check the documentation for the operators it uses.
BTW, what is golfing( other than a fun sport )?

Another poster kindly gave you an explanation. You may also consider
giving a peek e.g. into the website I mentioned in the other post.

I'll add just a brief consideration: I am not a golfer and I'm not
really interested in perl golf per se. In it it's officially OK to use
any sort of dirty trick and bad programming technique, but along with
micro optimizations one is forced to search the conceptually simplest
algorithms, and to investigate them. It is an exercise, and just like
obfuscation and writing japhs, can give a helping hand at deepening
one's knowledge of Perl...
BTW, the fizz buzz problem I came across on line while looking for
detailed instructions said that one should "fizz" on anything
divisible by 5, or with 5 in the number, and likewise "buzz" on
anything divisible by 7 or with 7 in the number. "Fizzbuzz" would be
the same thing, divisible by 5 & 7 or containing the 5 & 7 anywhere in
the number. Just thought you might be interested in trying that form
too.

Funny! If I am not mistaken, a number 1..100 is "divisible by 5, or
with 5 in it" iff it has either 0 or 5 amongst its digits, so half of
the problem is actually easier than in the previous case. For the
other half, I can't think of any way to avoid a double pair of parens:

print+fizz x/0|5/.buzz x(/7/|!($_%7))||$_,$/for 1..100

but I've not thought much about it and I'm only a second-rate golfer
anyway!


Michele
--
#!/usr/bin/perl -lp
BEGIN{*ARGV=do{open $_,q,<,,\$/;$_}}s z^z seek DATA,11,$[;($,
=ucfirst<DATA>)=~s x .*x q^~ZEX69l^^q,^2$;][@,xe.$, zex,s e1e
q 1~BEER XX1^q~4761rA67thb ~eex ,s aba m,P..,,substr$&,$.,age
__END__
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top