Self-reproducing Spiral

n/a nforrett at wgz.com
Tue Jul 16 13:01:48 CDT 2002


On Mon, 15 Jul 2002, Tyler F. Creelan wrote:

> Can anyone explain how this (very awesome!) perl code works?

Ok, I think I've redeemed myself. ;-) See attached. 

-- 
Nick


 ,--< Nick Forrette >--------------------------.
 | e-mail: nforrett at wgz.org                    |
 | www   : http://www.drforehead.net/          |
 `---------------------------------------------'

-------------- next part --------------
On Mon, 15 Jul 2002, Tyler F. Creelan wrote:

> Can anyone explain how this (very awesome!) perl code works?
> 
> "This self-reproducing code prints a turning spiral filled with it's own
> code."
> 
> #!/usr/bin/perl
> $_='
>          $q ="\                   47"; wh
>         ile                           ($ ;=
>       $z                +=              .5 ){
>     %c=           $r=0;$/ ="";whi         le(2
>    0+          $z>($;+=.05)){$c{int$       _+ 2
>   6+         2*($              r+= .0       2) *
>  s          in$                   ;}{1       -$_
> +1         0+           int        $r*c       o s
> $         ;}         =1for(0.       .1)        }$
> t        =r         ever se;$        /.        =`
> c        le        ar     `.         "         #!
> /        usr       /bi             n/         pe
> rl       \n\       $_ =$q        \n"          ;
> fo        r$y        (1..20){$c{$_}          {
> $ y       }? $         /.=chop$t            :
>  ($/        . ="                          \4
>  0")         for(0.                    .53)          ;
>    $/.        ="\n"}pri            nt"$/$          q;
>    s; ".         chr(9 2)."s;;g;eval\n           "}

Set $_ to be a rather large string of (poorly) formatted perl code.
 
> ';s;\s;;g;

# Remove all the whitespace from $_

> eval

Evaluate the whitespaceless $_.

Now if we remove the whitespace earlier, and strategicly add some back in to 
clarify the ccdes intent, you get something like this...

$q = "\47" ;
while( $; = $z += .5) {
  %c = $r= 0 ;
  $/ = "" ;
  
  while( 20 + $z > ($; += .05)) {
    $c{int $_ + 26 + 2 * ($r += .02) * sin $;}{1 - $_ + 10 + int $r * cos $;} = 1 for(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"
}

With some added comments, and rewriting the inner while loop, you get 
the following.

# Set $q to ascii octal 47, or the single quote
$q = "\47" ;

# Increment $; and $z by .5. It appears that $; is used to obfusticate things,
# as is $/ (in other words, they could have used normal variables)
while( $; = $z += .5) {
  %c = $r = 0 ;
  $/ = "" ;
  
  # This loop actually constructs the spiral. The hash %c is used to store the
  # legal locations that characters can be stored in the final result. The
  # first key is the Y screen coordinate, the second hash key is the X
  # coordinate. If a character is allowed at that point on the screen, the
  # appropriate hash entry is set to 1.
  while( 20 + $z > ($; += .05)) {
    for (0 .. 1) {
      # Formula for spiral of archimedes: 
      #   x = t cos t
      #   y = t sin t
      # where x and y are rectangular coordinates, and t is time.
      # in this case, $c{Y-coord}{X-coord}, and $; represents time
      # the rest seems to be fudge factor
      $c{int $_ + 26 + 2 * ($r += .02) * sin $;}{1 - $_ + 10 + int $r * cos $;} = 1 ;
    }
  }
  
  # Here is where the magic happens. Remember that $_ was s/\s//g -ified, and
  # then evaled. Now $_ still contains the whitespace stripped code. However,
  # the code that was whitepsace stripped was capable of reconstructing the
  # original spiral (stored in %c). So $t ends up with the reverse of the body
  #  code
  $t = reverse ;

  # This clears the screen and represents the first two lines of replicated
  # code in each iteration of the outer while loop
  $/ . = `clear` . "#!/usr/bin/perl\n\$_=$q\n" ;
  
  
  # Loop over the X/Y coordinates 
  for $y (1 .. 20) {
    for (0 .. 53)
    {
      # if the spiral calculator determined that there should be a character
      # here, chop a character off the end and append it to $/ (which contains
      # the screen clearing, and first two lines of code already. Remember 
      # that $t is the code backwards, so this will be the first character of 
      # the code forwards. If there is not supposed to be a character here,
      # then put a space character in that location.
      $c{$_}{$y} ? $/ .= chop $t : ($/ .= "\40") ;
    }
    $/ .= "\n"
  }
  
  # Here we print out the first two lines, and the spiralized body code, then
  # the last s;\s;; and eval.
  print "$/$q;s;" . chr(92) . "s;;g;eval\n"

  # The outer loop is purely for effect. It has the net effect of making the
  # spiral appear to rotate. However, I found that you have to have a suitable
  # slow machine to actually see the spiraling. Strictly speaking, it is not
  # needed.
}



More information about the Pdx-pm-list mailing list