Self-reproducing Spiral
Tom Phoenix
rb-pdx-pm at redcat.com
Tue Jul 16 00:18:18 CDT 2002
On Mon, 15 Jul 2002, Tyler F. Creelan wrote:
> "This self-reproducing code prints a turning spiral filled with it's own
> code."
Well, the whole spiral is just a single-quoted string. Just after that
string is assigned to $_, the code at the bottom is the engine:
s;\s;;g;eval
The engine strips out the whitespace and evals that code. (The eval
operator, used like this, compiles and runs whatever Perl code is found in
$_. Using eval on a string is a bad idea in general, unless you totally
understand why it's a bad idea.)
Of course, that code looks like this without the whitespace:
$q="\47";while($;=$z+=.5){%c=$r=0;$/="";while(20+$z>($;+=.05)){$c{int$_+26+2*($r+=.02)*sin$;}{1-$_+10+int$r*cos$;}=1for(0..1)}$t=reverse;$/.=`clear`."#!/usr/bin/perl\n\$_=$q\n";for$y(1..20){$c{$_}{$y}?$/.=chop$t:($/.="\40")for(0..53);$/.="\n"}print"$/$q;s;".chr(92)."s;;g;eval\n"}
So I'll put the whitespace back, in the right places, by using B::Deparse
with a command like this: perl -MO=Deparse source >deparsed , then I'll
fix up one extra long line to get this:
$q = q['];
while ($; = $z += 0.5) {
%c = ($r = 0);
$/ = '';
while (20 + $z > ($; += 0.05)) {
foreach $_ (0 .. 1) {
$c
{int $_ + 26 + 2 * ($r += 0.02) * sin($;)}
{1 - $_ + 10 + int($r * cos($;))}
= 1;
}
}
$t = reverse;
$/ .= `clear` . "#!/usr/bin/perl\n\$_=$q\n";
foreach $y (1 .. 20) {
foreach $_ (0 .. 53) {
$c{$_}{$y} ? ($/ .= chop $t) : ($/ .= ' ');
}
$/ .= "\n";
}
print "$/$q;s;" . '\\' . "s;;g;eval\n";
}
Here, let me annotate that:
$q = q[']; # A single quote. The actual source uses
# neither single quotes nor whitespace.
while ($; = $z += 0.5) {
# Although $; is one of Perl's internal variables, it's
# being used here as an ordinary one. Pretend it's
# $semi if you'd rather. It is an angle expressed in
# radians. Of course, the while loop is a decoy; it's
# an infinite loop. This program runs until you break
# out of it. $z is an initial rotation parameter.
%c = ($r = 0);
# This is erasing the contents of %c, although it's an
# odd way to do it. %c is being used to hold a picture of
# the spiral. (Not a normal use of a hash!) The value of
# $c{$x}{$y} will be true if the spiral intersects
# position $x, $y. $r is the radius of the spiral.
# $x ranges from 0 to 53, $y from 1 to 20.
$/ = '';
# This is another internal variable being used for the
# author's own purposes. This one is collecting the
# output as one big multi-line string.
while (20 + $z > ($; += 0.05)) {
foreach $_ (0 .. 1) {
$c
{int $_ + 26 + 2 * ($r += 0.02) * sin($;)}
# That's the X-coord in the spiral picture. The
# constant 26 is half of the width of the
# spiral, roughly.
{1 - $_ + 10 + int($r * cos($;))}
# That's the Y-coord; 10 is half of the height.
= 1;
}
}
$t = reverse;
# That reverses $_ (which holds this program's source,
# remember?) storing the resulting string into $t. It's
# being reversed so that chop() will remove characters
# in the proper order.
$/ .= `clear` . "#!/usr/bin/perl\n\$_=$q\n";
# The output of clear (external command being run in
# backticks) is your system's "clear screen" code.
foreach $y (1 .. 20) {
foreach $_ (0 .. 53) {
$c{$_}{$y} ? ($/ .= chop $t) : ($/ .= ' ');
# Either a space or some code, depending upon
# the spiral table, %c. It would be better,
# if you must use the ternary op, to write
# that like this:
# $/ .= $c{$_}{$y} ? chop $t : ' '
}
$/ .= "\n";
}
print "$/$q;s;" . '\\' . "s;;g;eval\n";
# That outputs the engine at the bottom, spoiling
# the look of the spiral.
}
The author of this code missed a number of opportunites to improve it
(although whether my changes would be improvements is a matter of debate).
In fact, a number of features make me wonder whether the author wrote it
originally for Perl 4, working around the lack of references by using
something like "$_!$y" as a hash key. (As far as I can see, this code
should work fine in Perl 4 with that mod. But I don't keep Perl 4 around
for testing.)
If I've missed anything, I hope someone else will jump in. Hope this
helps!
--Tom
TIMTOWTDI
More information about the Pdx-pm-list
mailing list