Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

3-D Stereogram, Self replicating source.

by Toodles (Monk)
on Oct 15, 2001 at 05:30 UTC ( #118799=obfuscated: print w/ replies, xml ) Need Help??

My challenge for myself was to create a script that would generate 'stereogram's, those images of static that would show a 3-d image if you relaxed your eyes properly (Remember the Sailboat in MallRats? That's the one). This sounded easy enough, and it was. To up the difficulty, I wanted the SOURCE to that script to be a stereogram. That was a little more difficult. For bonus points, the image this script creates is not only a stereogram, but contains its own source, so it could be run again, generating another self modifying, runnable source in the design of a stereogram. After much fidgeting, here it is. .

#!/usr/bin/perl # Copyright (c) Marcus Post, <marcus@marcuspost.com> # # # # $_=q,my(@f|@c|x$_=q.my(@f|@c|x$_=q.my(@f|@c|x$_=q.m(@f||@c|x$_=q.m(@f| +|@c|xx @w);@a=@f=<DAT%@w);@a=@f=<DAT%@w);@a=@f=<DAT%@w;@a=@f=<DAAT%@w;@a=@f=< +DAAT%% A>;seek(DATA|0!A>;seek(DAA|0!!A>;seek(DAA|0!A>;seek(DAA|0!!A>;seek(DAA +|0!!AA |0);@c=<DATA>;Y|0);@c<DATA>;Y||0);@c<DATA>Y||0);@c<DATA>Y|||0);@c<DATA +>Y|||| until(($_=pop(zutil(($_==pp(zuttil(($_==p(zuttil(($_==p(zutttil(($_==p +(zuttt @c))=~/^_/){};Qc))=~/^_/){};Qc)))=~/^_/{};Qc)))=~/^_/{};Qc))))=~/^_/{} +;Qc))) unshift(@a|$_)xnshift(@a|$_)xnshhift(a|$_)xnshhift(a|$_)xnshhiift(a|$_ +)xnshh ;for(1..3){pri%;for(1.3){pri%;ffor1.3){pri%;ffor1.3){pri%;ffor11.3){pr +i%;fff nt(shift(@c));!nt(shft(@c));!ntt(hft(@c));!ntt(hft(@c));!ntt(hftt(@c)) +;!nttt }for(@f){my($sY}for@f){my($sY}for@f){my($sY}for@f){my($sY}for@f){mmy($ +sY}foo );split//;$_=sz);splt//;$_=sz);splt//;$_=sz);splt//;$_=sz);splt//;$_== +sz);ss hift(@c);$_=~sQhift(c);$_=~sQhift(c);$_=~sQhift(c);$_=~sQhift(c);$_=~s +QQhiff /(.{15}).*/\1/x/(.{15})*/\1/x/(.{15})*/\1/x/(.{15})*/\1/x/(.{15}})*\1/ +xx/(.. ;@w=split//;fo%;@w=split/;fo%;@w=split/;fo%;@w=split/;fo%;@w=spllit;fo +%%;@ww r(@_){$w[$s+15!r(@_){$w[$s15!r(@_){$w[$s15!r(@_){$w[$s15!!(@_){$$w[s15 +!!!(@@ -$_]=(($w[$s]eY-$_]=(($w[$s]YY-_]=(($w[$s]YY-_]=(($w[$s]YY-_]=((($[$s] +]YY-__ q"|")?".":$w[$zq"|")?".":$w[$zq|")?"."::$[$zq|")??."::$[[$z|")???.::$$ +[[$z|| s]);$s++;}for(Qs]);$s++;}for(Qs];$s++;}}or(Qs];$$s+;}}orr(Qs]$$s++;}}o +rr(Qss 1..75){unless(x1..75){unless(x1.75){unnlss(x1.775){uulsss(x1.75){uuuls +ss(x11 $w[$_]ne''){$w%$w[$_]ne''){$w%$w$_]nee''{$w%$$w$_]nn''{{$w%$$w_]nnn''{ +{$w%$$ [$_]=$w[($_-1)![$_]=$w[($_-1)![$_=$w[[($_-)![$_==w[[($$_-)![$__w[[[($$ +_-)![[ ];}}print(joinY];}}print(joinY];}prinnt(joinY;}prinntt(joinY;}pinnntt( +joinYY ""|@w);print"\z""|@w);print"\z""|w);;print"\z"|w);;pprint"\z"|w;;pppri +nt"\zz n";}print@a;,;#n";}print@a;.;#n";priint@a;.;#n;priintt@a;.;#n;piinntt@ +a;.;## y!|zY\!%x!,Q!;#y!|zY\!%x!.Q!;#y!zY\!!%x!.Q!;#!zY\!!%x!!.Q!;#!z\!!!%x!! +.Q!;## s{Q.*\n}[]g;#<>s{Q.*\n}[]g;#<>sQ.*\nn}[]g;#>sQ.*\nn}[]]g;#>sQ.\nnn}[]] +g;#>ss eval;#EndFini!$eval;#EndFini!$eal;#EEndFin!$eal;;##nddFin!$ea;;###nddF +in!$ee __DATA__ 000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000 000000000000110000000110000000000000000011100000000000000000 000000000001110000001110000000000000000111110000000000000000 000000000011110000011110000000000000001111111000000000000000 000000000011110000011110000000000000001111110000000000000000 000000000011110000011110000000000000001111100000000000000000 000001111111111111111111111110000000001111100000000000000000 000011111111111111111111111100000000000111100000000000000000 000111111111111111111111111000000000000111100000000000000000 000000000011110000011110000000000000000111100000000000000000 000000000011110000011110000000000000000111100000000000000000 000000000011110000011110000000000000000111100000000000000000 000000000011110000011110000000000000000011100000000000000000 000001111111111111111111111110000000000011100000000000000000 000011111111111111111111111100000000000011100000000000000000 000111111111111111111111111000000000000001100000000000000000 000000000011110000011110000000000000000001100000000000000000 000000000011110000011110000000000000000001100000000000000000 000000000011110000011110000000000000000000000000000000000000 000000000011100000011100000000000000000000000000000000000000 000000000011000000011000000000000000000011110000000000000000 000000000000000000000000000000000000000111111000000000000000 000000000000000000000000000000000000000111110000000000000000 000000000000000000000000000000000000000011110000000000000000 000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000

Tips: You can modify the DATA field to create your own images, just make sure it its the same dimensions as the original. The digit indicates the depth of that 'pixel', with 3 being closer to the viewer than 1. You can go up to '9', but really it gets hard on the eyes with anything higher than 3. Don't use a number larger than the position in the string; i.e., the first column should always be 0's, never use 1's until the second column, etc. Failure to follow this rule will still create an accurate image, but it will not be a valid perl file. Just relax, and adjust your eyes so the four '#' at the top merge. For those who cant see the image, the source posted here is the famous O'Reilly camel, but when run, will generate a she-bang image like the one shown in the DATA portion.

Comments welcome. I could have tried to obfu this up more, but after spending 12 hours or so working on getting it right, my eyeballs hurt. Happy Coding!

Toodles (Updated: Code Cleanup) (Addundum: When downloaded, the server looks like it adds a few blank lines at the bottom of the code. Remove them for best results. There should be EOF after the last row digits in the DATA section)

Comment on 3-D Stereogram, Self replicating source.
Download Code
Re: 3-D Stereogram, Self replicating source.
by stefan k (Curate) on Oct 15, 2001 at 16:41 UTC
    A b s o l u t e l y I m p r e s s i v e!!

    Regards... Stefan
    you begin bashing the string with a +42 regexp of confusion

Re: 3-D Stereogram, Self replicating source.
by tommyw (Hermit) on Oct 15, 2001 at 17:13 UTC

    Wurble! I'm amazed: I've never been able to see sterograms, but the useful hint about making the hashes merge resolved this one fine!

    And then there's the complexity of the code. Wow!

Re: 3-D Stereogram, Self replicating source.
by JungleBoy (Scribe) on Oct 15, 2001 at 22:00 UTC
    That loud *thump* you just heard was my jaw hitting the floor.
    I am absolutely amazed. I think the Wayne's World standard of "I"m not worthy" fits well here.
    Congrats.
Re: 3-D Stereogram, Self replicating source.
by Hero Zzyzzx (Curate) on Oct 15, 2001 at 23:16 UTC

    Umm, that's amazing. Very cool. Can you give up a little bit about how this sucker works?

    -Any sufficiently advanced technology is
    indistinguishable from doubletalk.

      My cursory examination is that the general idea is to have the real program along the left edge, and then the rest of the line contains repeated copies of that, modified to show the image.

      In the last 3 lines before the DATA, you can see that since the real line ends with a # so everything after that is ignored.

      The rest of the program works the same way, but is obfuscated by using different characters. Everything between the first 2 commas is a string. The bottom part, which cannot be cloaked the same way hence the major hint in the form of #'s, processes the text string thus:

      tr[|zY!%x][,Q]; s[Q.*\n][]g; eval;
      Which basically changes |,Y,or% into , and changes z,!,or x into Q (more on that next), and throws away a few other letters, which give him padding that can be anywhere including in the "real" code.

      |'s etc. become commas. They were escaped out so that the q could use them to delimit the string

      . The Q, previously z,!,x (or already Q), turns into the new comment character -- everything starting from a Q or z is removed. Having four choices makes it less obvious that each "real" part of a line ends in this.

      Note that such ender character forms a solid vertical stripe in the 14th column, so this code could have processed it by taking 14 chars and throwing away the rest. It's just a matter of changing the last 3 lines. Those lines are shorter than 13 chars, but garbage can be added after # and it works just the same, making the real code in the first "column" that gets replicated and munged to hold the image. Having no image in the topmost line simplifies things, and should be there for a border anyway. —John

        That's a good analysis of the code. I just have one correction. tr[|zY!%x][,Q];
        You said that this changes | Y % into , and z ! x into Q. Actually, it changes | into , and z Y ! % x into Q. When a translation specifies more characters on the left than on the right, the last character on the right is used for all the extras. (With the /d modifier, the extras are deleted from the target string instead.)

        perlop explains the tr/// operator in greater detail.

        Your analysis is entirely correct, with the exception of the tr/// oversight someone else already pointed out. If anyone wants to see the de-mangling of the string, start up the perl debugger
        perl -d filename.pl
        and 'W'atch $_
        W $_
        and step by step down towards the eval with the 'n' command. It should be obvious as soon as you see the line of Q's. Next it removes everything from the Q's to end of line. You'll be left with:
        my(@f,@c,@w);@a=@f=<DATA>;seek(DATA,0,0);@c=<DATA>; until(($_=pop(@c))=~/^_/){};unshift(@a,$_);for(1..3) {print(shift(@c));}for(@f){my($s);split//; $_=shift(@c);$_=~s/(.{15}).*/\1/;@w=split//;for(@_) {$w[$s+15-$_]=(($w[$s]eq",")?".":$w[$s]);$s++;} for(1..75){unless($w[$_]ne''){$w[$_]=$w[($_-1)];}} print(join"",@w);print"\n";}print@a;
        With decent space, comments, and more meaningfull variable names...This is for education only; wont work unless in proper shape, with DATA available.
        my(@f,@c,@w); @a=@f=<DATA>; #Read everything from __DATA__ onward into #array @f and @a seek(DATA,0,0); #Seek to begin of source file @c=<DATA>; #Read it all into @c , #!, DATA, and all until( ($_=pop(@c)) =~ /^_/ ){}; #This removes one line at a time from the end # of the source copy in @c, until the line # removed begins with an underscore (i.e. __DATA__ #Now, all that remains in @c is the actuall code; #all __DATA__ and the __DATA__ marker itself have #been removed. unshift(@a,$_); # $_, which still contains the string "__DATA__" we #removed from @c, gets placed at the beginning of @a. We # now have @c, which contains everything in the file up to # the last eval line, @a, which contains the "__DATA__" line # and all of the DATA, and @f which contains just the DATA # contents for(1..3){ #Just do this three times print(shift(@c)); #pop of the top three lines of source and #print them. e.g., "#!/usr/bin/perl", copyright notice, and } # the four hashmarks to align your eyes. for(@f){ # once for each line of DATA my($s); #Remember, 'my' will undef the scalar out everytime # this is reached. Could just as easily be $s=0; split//;#Split it up into an array byte-by-byte. If the #string was "1234", @_ would equal ('1', '2', '3', '4' +) $_=shift(@c); #Grab the next line of code.... $_=~s/(.{15}).*/\1/; #Chop off everything after 15 charachters +. @w=split//; #Split up those 15 charachters into a 15 element a +rray #and put into @w for(@_) # For each letter of the current line pulled from DATA +... {$w[$s+15-$_]=(($w[$s]eq",")?".":$w[$s]); #Err, thats a big one. Remember, the closer the the vi +ewer #you want that character to be, the closer together th +e #charachters that make up that plotted character have +to #be. Also, I am trapping ','s here, because if one fin +ds #its way into the jumble, it'll throw off the quoting +and #ruin the script. Most people won't notice the differe +nce #between the two when staring unless they know to look +. I #would have preffered to use 'ell' and 'one', but cant + use #them as quoting characters. $s++; #and go down the line one by one. } for(1..75){ #the images are 75 charachters wide. For each one. +.. unless($w[$_]ne'') { #If no charachter was put there.. +. $w[$_]=$w[($_-1)]; #put in a copy of the one t +o #the left } } print(join"",@w); # Print out our line we just made. print"\n"; #goto next line, Lather, rinse, repeat. } print@a; #Finally, print the __DATA__ label, and original DATA content +s
        Things I should have done differently: The first my(...) was totally unneeded. I didn't use strict or -w, so this should have gone out the window. I should have used if instead of unless where possible. 4 wasted charachters each. $s-=$s or $s^=$s would have been more fun than my($s) and done the same thing Since the charachters in the DATA section get added in a numeric scalar context, that means that anything not a digit equates to 0. So, instead of bunches of 0's, I could do anything, even making harder to read the data some like this smiley: Feel free to try it.
        __DATA__ llllllllllllllllllllllllllllllllllllllllllllllllllllllllllll llllllllllllllllllllllllllllllllllllllllllllllllllllllllllll llllllllllllllllllllllllllllllllllllllllllllllllllllllllllll llllllllllllllllllllllll1111111lllllllllllllllllllllllllllll lllllllllllllllllll111111111111111111lllllllllllllllllllllll lllllllllllllllll1111111111111111111111lllllllllllllllllllll lllllllllllllll11111ll111111111111ll11111lllllllllllllllllll llllllllllllll111111ll111111111111ll111111llllllllllllllllll lllllllllllll1111111ll111111111111ll1111111lllllllllllllllll llllllllllll11111111ll111111111111ll11111111llllllllllllllll llllllllllll11111111ll111111111111ll11111111llllllllllllllll lllllllllll111111111ll111111111111ll111111111lllllllllllllll lllllllllll1111111111111111111111111111111111lllllllllllllll llllllllll1111l11111111111111111111111111l1111llllllllllllll lllllllllll111ll111111111111111111111111ll111lllllllllllllll lllllllllll1111ll1111111111111111111111ll1111lllllllllllllll llllllllllll1111ll11111111111111111111ll1111llllllllllllllll llllllllllll11111lll1111111111111111lll11111llllllllllllllll lllllllllllll11111lllll1111111111lllll11111lllllllllllllllll llllllllllllll111111llllllllllllllll111111llllllllllllllllll lllllllllllllll11111111llllllllll11111111lllllllllllllllllll lllllllllllllllll1111111111111111111111lllllllllllllllllllll lllllllllllllllllll111111111111111111lllllllllllllllllllllll llllllllllllllllllllllll1111111lllllllllllllllllllllllllllll llllllllllllllllllllllllllllllllllllllllllllllllllllllllllll llllllllllllllllllllllllllllllllllllllllllllllllllllllllllll llllllllllllllllllllllllllllllllllllllllllllllllllllllllllll

        Edit: chipmunk 2001-11-12

Re: 3-D Stereogram, Self replicating source.
by John M. Dlugosz (Monsignor) on Oct 16, 2001 at 03:21 UTC
    I rarely vote on Obfus, instead concentrating on good answers to questions. But you got my ++ here. I hope it makes it to the top of the best nodes ever! Utterly stupendus. This may be your second post, but I dare say you'll make history with this one. Start practicing for your Saint-ly duties...

    --John

Re: 3-D Stereogram, Self replicating source.
by earthboundmisfit (Chaplain) on Oct 17, 2001 at 00:04 UTC
    If you copy and paste from Netscrape 4.x, you'll need to strip the leading spaces on each newline to get the script to do it's magic.

    Very cool, Toodles. Kudos.

Re: 3-D Stereogram, Self replicating source.
by higle (Chaplain) on Oct 17, 2001 at 02:13 UTC
    This has to be the most abso-freakin'-lutely awesome, mind boggling thing that I've ever seen done with any programming language.

    s/(Toodles)/\1 is a GENIUS/g;

    higle
      strfry@argc:~> perl -Mstrict -we 'my$i="Toodles";$i=~s/(Toodles)/\1 is + a GENIUS/g;print "$i\n";' \1 better written as $1 at -e line 1. Toodles is a GENIUS
      <G> (i can't see stereograms well, but the #! in the __DATA__ looked pretty cool. )

      -- strfry()
      perl -Mstrict -we '$;=qq.rekcalsxlrePxrehtonaxtsuJ.;$;=~s>x>qq|\x20|>eg;$_=qq.\x0a.;print scalar reverse$;;END{print};'
Re: 3-D Stereogram, Self replicating source.
by cab (Beadle) on Oct 17, 2001 at 13:33 UTC
    OHMYGOD!!! This is some serious obfu! Dropped me right off my stool. I'm not worthy!!!! /cab
Re: 3-D Stereogram, Self replicating source.
by spartan (Pilgrim) on Oct 17, 2001 at 22:17 UTC
    wow.

    If I could have voted more than once, I would have. I forgot how much I actually like looking at stereograms.

    Very funny Scotty... Now PLEASE beam down my PANTS!
Re: 3-D Stereogram, Self replicating source.
by Anonymous Monk on Oct 22, 2001 at 00:50 UTC
    I believe in miracles!
Re: 3-D Stereogram, Self replicating source.
by awkmonk (Monk) on Mar 21, 2003 at 09:41 UTC

    I feel truly humbled. How you got this to work is beyond me. I've been writing some code to do this with bmp files etc and I just can't believe you managed it in plain text.

    Wow.

Re: 3-D Stereogram, Self replicating source.
by vacant (Monk) on Nov 16, 2003 at 22:59 UTC
    Out Effing Standing! I am going to study this code until I understand it even if I have to join a monastery.
Re: 3-D Stereogram, Self replicating source.
by dynamo (Chaplain) on Aug 19, 2007 at 21:46 UTC
    I am humbled.

    I am speechless.. It's lucky I'm typing.

    There is this crazy undefinable thing I love so much about perl culture - and this is one of the best examples I have EVER seen.

    GREAT job, man.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: obfuscated [id://118799]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (6)
As of 2014-11-28 21:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My preferred Perl binaries come from:














    Results (200 votes), past polls