Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris

comment on

( #3333=superdoc: print w/replies, xml ) Need Help??
And at the risk of spoiling the fun by dissecting the camel, here's my attempt at describing what's going on here, because it's a pretty neat trick, and may encourage other ObWriters to experiment on their own. (People who don't want the fun spoiled should tune out now...)

The program basically reads its own source code, and prints out a smaller version of the Camel picture, by reducing the image by 50%. It does this by splitting the code up into 2*2 blocks of characters, figuring out which characters in this block are non-whitespace, and printing out a corresponding character to display the picture. Characters range from a " " (for a 4x4 block of spaces) to "X" (for a 4x4 block of non-whitespace).

The picture is created, stored in an array, and printed out twice (the strings are reversed during the first print, so that the 2nd set of camels are facing the other way). After the picture printout, the O'Reilly disclaimer is printed out.

Here's my annotated version of the code. Note that, since the formatting has been removed and comments added, this code will not work the same as the original. It's just meant for a study aid.

#!/usr/bin/perl -w # camel code use strict; $_=' eval("seek\040DATA,0,0;"); # clever way of seeking to beginning + of program file! foreach (1..3) { # skip the first 3 lines (shebang, use str +ict, and a blank line) <DATA>; } my @camel1hump; # variable def's my $camel; my $Camel; # for each line read, grab the following line (if there is another # one to read), and go through the individual characters, detectin +g # whitespace and nonwhitespace characters. # # If you think of the image as being divided into 2x2 character # blocks, then each char in the block will be assigned a power of # 2 thusly: # # +---+---+ # | 8 | 4 | # +---+---+ # | 2 | 1 | # +---+---+ # # For each block, this while block will add up the corresponding # numbers for each nonwhiteapce char, resulting in a number stored # in $camel1hump from 0 to 15. This number will then be translated # to a ASCII picture character from ' ' (for a value of 0, # indicating 4 whitespace characters) to 'X' (for a value of 15, # indicating 4 nonwhitespace chars). These picture chars will be # stored in the string $camel, to be printed out in a fancy way # below. while (<DATA>) { $_ = sprintf("%-69s", $_); # format string in 69 columns my @dromedary1 = split(//); # split $_ into individual char +s if (defined($_ = <DATA>)) { # get next line and split, @camel1hump=split(//); # if it exists } while (@dromedary1) { # for each char my $camel1hump = 0; # this var will hold the bits my $CAMEL = 3; # this var is the bit # if (defined($_ = shift(@dromedary1)) && /\S/) { # if the n +ext char is a nonspace, $camel1hump += 1<<$CAMEL; # add 1<<3 (8) to our + bit counter } $CAMEL--; # next bit... if (defined($_ = shift(@dromedary1)) && /\S/) { # if th +e next char is a nonspace, $camel1hump += 1<<$CAMEL; # add 1<<2 (4) to our + bit counter } $CAMEL--; # next bit... if(defined($_=shift(@camel1hump)) && /\S/) { # if the n +ext char is a nonspace, $camel1hump += 1<<$CAMEL; # add 1<<1 (2) to our + bit counter } $CAMEL--; # next bit... if(defined($_ = shift(@camel1hump)) && /\S/) { # if the + next char is a nonspace, $camel1hump+=1<<$CAMEL; # add 1<<0 (1) to o +ur bit counter ; } # pick out the proper corresponding text format char for t +he # added-up bits. This could be non-obfuscated as a substr( +) # call. $camel .= (split(//,"\040..m`{/J\047\134}L^7FX"))[$camel1h +ump]; } $camel .= "\n"; } @camel1hump = split(/\n/,$camel); # split the picture into indi +vidual lines # Now we print the picture out. The same block of code is included # twice in the program. The reason the second set of cames is reve +rsed # is because the reverse() function call actually does reverse the + # string in the @camel1hump array, so the second time the strings +are # printed, we get a flipped picture. foreach (@camel1hump) { chomp; $Camel=$_; # a bit of obfuscation which just translates 8 of the formatti +ng chars # to the digits "1" through "8", and then back again. y/LJF7\173\175`\047/\061\062\063\064\065\066\067\070/; y/12345678/JL7F\175\173\047`/; $_=reverse; # reverse the string in $_ (which reverses +it in the @camel1hump array) print"$_\040$Camel\n"; # and print out reversed string, alo +ng with the $Camel copy. } # and do basically the same thing again. Since the strings were re +versed in the preceding # block, they're printed out as flipped images of the camel. foreach (@camel1hump) { chomp; $Camel=$_; y/LJF7\173\175`\047/12345678/; y/12345678/JL7F\175\173\0 47`/; $_=reverse; print "\040$_$Camel\n"; } '; # and that's the end of $_. Whew. ; s/\s*//g; # remove all spacing from $_ ; eval; # display the camels eval("seek\040DATA,0,0;"); # seek back to the beginning of program undef$/; $_=<DATA>; # slurp in all the program into $_ s/\s*//g; # remove space ( ); ; s;^.*_;;; # remove all characters until the final "_", which will b +e the last underscore in "__DATA__" # Now print out the O'Reilly disclaimer. The chars in __DATA__ # are just the ASCII values, coded in octal. (And you thought # the picture data was there!) map { # this map statement eval "print\"$_\""; # prints out each octal character } # that it finds /.{4}/g; # using this pattern match. __DATA__ \124\150\145\040\165\163\145\040\157\146 \040\141\040\143\141\155\145\154\040\151 \155\141\147\145\040\151\156\040\141\163 \163\157\143\151\141\164\151\157\156\040 \167\151\164\150\040\120\145\162\154\040 \151\163\040\141\040\164\162\141\144\145 \155\141\162\153\040\157\146\040\117\047 \122\145\151\154\154\171\040\046\012\101 \163\163\157\143\151\141\164\145\163\054 \040\111\156\143\056\040\125\163\145\144 \040\167\151\164\150\040\160\145\162\155 \151\163\163\151\157\156\056
Whew. Is it lunchtime yet?

Update: Thanks to Erudil for pointing out that the y/// lines, which I thought were purely for obfuscatory (ooh!) purposes, actually serve a purpose. Namely, to translate non-symmetrical characters to their mirror image. "L" and "J" are exchanged, "F" and "7" are exchanged, etc. (Take a close look at the ordering of the characters in those two y/// lines.)

As an example of why this needs to be done, look at the camels' heads:

  .mm.           .mm.
 .XXX^XLmm   mmJX^XXX.

See those "L"s and "J"s? If they hadn't been switched with the y/// code, the picture wouldn't have the dark portions in the right areas, and the picture wouldn't be a mirror image:

  .mm.           .mm.
 .XXX^XLmm   mmLX^XXX.

In reply to Re: camel code (SPOILERS!) by jima
in thread camel code by Erudil

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?

    What's my password?
    Create A New User
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others lurking in the Monastery: (3)
    As of 2021-04-22 04:01 GMT
    Find Nodes?
      Voting Booth?

      No recent polls found