@JAPH[5]

Hi everyone, I'm back. School is crazy. I hope to keep writing blog posts, but they'll probably be infrequent. Here's some music:


Sadly, this is the only JAPH of mine I have left to share; we use C++ exclusively at school, so I haven't written anything new in Perl lately. Let's take a look:

@a='u';map{$x=push@a,chr(ord(@a[$x-1])+$_)}(
-43,42,-1,-18,-65,79,-1,-6,12,-2,-13,-21,-48
,82,-13,-69,76,-11,7,3,-8,15,-13,-57);for (0
..12){$_*=2;@a[$_,$_+1]=@a[$_+1,$_]}print@a;

Lots of numbers. 24, by my count, which is pretty close to that 25 character string we're so familiar with now. We can probably assume, then, that each number will be transformed to an ASCII value and printed. With that in mind, here's the properly formatted code:

@a = 'u';
map {$x = push @a, chr(ord(@a[$x - 1]) + $_)}
   (-43,42,-1,-18,-65,79,-1,-6,12,-2,-13,-21,
    -48,82,-13,-69,76,-11,7,3,-8,15,-13,-57);
for (0..12) {
    $_ *= 2;
    @a[$_, $_ + 1] = @a[$_ + 1, $_];
}
print @a;

The heart of this JAPH is the map function. In the expression block, we see that $x is being assigned to the result of pushing a new value onto @a. push?, as you might have guessed, simply adds the new value to the end of the array, and the documentation tells us it returns the new number of elements in the array. @a[$x - 1] seems to be calling the last element (not the penultimate element!), but in the first iteration, $x hasn't been initialized yet! That means its value is 0, so how can calling @a[-1] be valid? As it turns out, this is a handy feature of Perl; a negative array index means, "start at the end and count backwards." Since the array starts with only one element, any index, positive or negative, will return 'u'.

Now we can see what the significance of the numbers in the array are: they are the difference in ASCII value between the last element of the array and the new element we want to add. So the next character added to the array will be 'u' - 43 = 'J', then 'J' + 42 = 't', then 't' - 1 = 's'...
These letters should look very familiar. The final step is to arrange them properly, which is done with a for loop. The loop skips every other element, and swaps adjacent elements. I'll admit there's probably a cooler way to do this (with regex, for example), but my regex is pretty rusty at the moment. I'll update it once I figure out how. :)

@JAPH[4]

Let's look at two of my JAPHs and go golfing. Here's some music.


Here's the first one:

@x = (-198,481.830,-268.83,64.690,-5.67,19,137.4,-75.910,18.1,-1.546,
-614,1364,-829.6,196.68,-15.92,-612,1425.7,-901.96,221.74,-18.54,-91,
370.75,-236.85,61.75,-5.625);for$a(0..4){for$b(0..4){for$c(0..4){$_+=
@x[$c+5*$a]*($b+1)**$c} print chr; $_ = "Just another Perl hacker,"}}

Yeesh. A huge array followed by a triple nested for loop. Let's deconstruct it:

@x = (#numbers...);
for $a (0..4) {
    for $b (0..4) {
        for $c (0..4) {
            $_ += @x[$c + 5*$a] * ($b+1)**$c;
        }
        print chr;
        $_ = "Just another Perl hacker,"
    }
}

Now we can start figuring out the loop logic. Using order of operations, $b+1 is first raised to the $cth power. This result is then multiplied by a particular value in our array of numbers, and added to $_. This sequence runs five times, with the array index increasing by 1 each time. The result is passed to the second for loop, where it is converted to an ASCII character and printed. $_ is then redefined, but clearly this is a misdirection, because the for loop would cause the new value to be printed no less than 25 times. This line does serve a function though; in a numerical context, a string is equal to 0, so this line is necessary to reset the value of $_.
After one character is printed, $b is incremented and the process runs again. After five characters are printed, $a is incremented and the index shifts by 5.
What do all these loops accomplish? Well, they're actually creating polynomials. Inspired by this post about curve fitting "Hello World," I set about mapping a JAPH curve. I didn't really know what I was getting myself into. Mapping 11 characters is hard enough -- 25 is bordering on insane. So instead, I created five fifth degree polynomials, each mapped to five characters. I used Excel to create the functions, then did some hand-tweaking to reduce the character count (though you'll notice I padded the first line with some trailing zeros). Placing all the parameters into a single array was necessary to bring the JAPH below Usenet's 4 line, 80 character signature limit, as well as providing a challenge. We can optimize it a bit by defining @a=0..4, and by changing the last statement to $_=$\.

On to the next one!

@: =('Jowl','anomaly','Oreo','habits'); @;=
(3960,127575,9123,18537);$\=',';for(@:){@:[
$.]=(eval'++@:[$.];'x@;[$.]);$.++}print"@:"

First we see that two arrays are created: one contains strings, and the other contains numbers. $\ is the output record separator, i.e. what will be appended to every print statement. Inside the for loop, there are two tricks happening: the eval plus x trick, and the string pre-increment trick.
The eval trick arose from my frustration that there wasn't a simple "repeat this statement x times" function. The only thing close was x, which will repeat a string. So I simply changed the statement to a string and repeated it, then evaluated it. Hence the statement here is evaluated @;[$.] times.
The magic pre-increment is a quirky aspect of Perl. Essentially it allows you to increment characters (not ASCII values). After reaching z, the increment "carries" to the next letter. So in this JAPH, the strings are being incremented to their proper values. Unfortunately the carry system means that it takes a huge number of pre-increments to change a string even slightly (observe that nearly 130,000 increments are needed to change just the last four letters of 'anomaly'). This is why the original strings are so close to their targets.

I revisited this JAPH after brushing up on my golfing technique and now it looks rather embarrassing. Here's the updated version:

@:= (Jowl, anomaly, Oreo, habits);
for (0..3) {eval'++@:[$_];'x(3960,
127575,9123,18537)[$_]}print"@:,";

I was surprised to find that quotes weren't required for the array, but I'm not complaining. Changing the output record separator was actually unnecessary; I just tacked on a , to the print statement. I also changed the for loop to use (0..3), which eliminates the need for a loop variable. Not sure what I was thinking when I told it to use @:. I also eliminated the @; array. These optimizations shave off 27 characters, and the code also executes 0.2 seconds faster on my machine.

Happy golfing!


EDIT: Rearranging the loop allows us to omit the brackets:

@:=(Jowl, anomaly, Oreo, habits);
eval'++@:[$_];'x(3960,127575,9123
,18537)[$_] for(0..3);print"@:,";

@JAPH[3]

Let's do a few simple ones. I found some music to listen to as we go.


$_='x"Just ";"x\"another \";\'x\\"Perl \\";x\\"hacker,\\"\'"';
s/x/print/g; eval eval eval;

Pretty straightforward. We see that print is being substituted for x in the $_ string. eval? is then used to tell the interpreter to treat the string like code. Can you see why multiple evals are required? It's a bit of a brain twister. Keep in mind that eval only returns the last thing it evaluated. Here's a hint: Using just print eval returns:

Just print"another ";'print"Perl ";print"hacker,"'

and print eval eval returns:

Just another print"Perl ";print"hacker,"

There's a good explanation of it here if you're stuck.



Next up we have:

$Old_MacDonald = q#print #; $had_a_farm = (q-q:Just another Perl hacker,:-);
s/^/q[Sing it, boys and girls...],$Old_MacDonald.$had_a_farm/eieio;

This rather humorous JAPH by merlyn makes extensive use of q, which can be used to define strings. Placing q in front of a special character, like # or %, causes it to behave like '. If the character is a bracket, then the string will also end if the opposite bracket is matched. Note that - and : are used in tandem to create the :-) emoticon that Larry Wall is so fond of.
On the first line we see that two strings are defined. The second line contains a substitution regex, which matches the beginning of the string. What string? Well, $_ of course. But $_ is blank (or undefined, rather), so its value is simply set to the latter half of the regex.
The replacement is a string followed by a comma followed by a concatenation. The key is the e modifier, which evaluates the resulting string. Note that two are necessary here, because just one results in:

print q:Just another Perl hacker,:

The other modifiers are just for comedic effect. I get the feeling that it was this combination of modifiers that inspired the JAPH in the first place.



Okay, okay, one more.

@a=split(/(\d)/,"4Hacker,2another3Perl1Just");
shift(@a);%a=@a;print"@a{1..4}";

We've seen split before; here it's splitting the string whenever it matches a digit. Then shift? is applied to the resulting array, because the first element will be blank. Next, the array is converted to a hash. This means that the words and their corresponding numbers will be paired up as hash values and keys. So the final print statement prints the strings that correspond to the numbers 1 through 4.

That was a little brief because I don't have a great grasp of hashes yet :/
Next time I'll cover my most recent JAPH and we'll do some golfing.

@JAPH[2]

This is a special JAPH. It's special because it was the first one I ever made. It's essentially a variant on the first two, but I'm still proud of it. Let's check it out.

@;=split//,'0;oP2S@!\0cP4D9&V@hA#a;(n Just another Perl hacke
'; foreach (@;) {pop@;; print chr ((@;. (100 + ord))% 86+32)}

Right away, your eyes are drawn to-

wait a minute

Now that I've said I made it, it sounds like I'm being really smug about how great it is. Just try to forget that it's mine.

Anyway, right away we see the JAPH text, but something's wrong - it's missing an r. So we might want to treat this as just a red herring, meant to throw us off the real trail.
Let's try rearranging the code, keeping in mind that ; ends a line and . concatenates strings (don't be confused by @;, it's just an array named ;).

@; = split //, '0;oP2S@!\0cP4D9&V@hA#a;(n Just another Perl Hacke';
foreach (@;) {
    pop @;;
    print chr((@; . (100 + ord))%86 + 32)
}

That's much cleaner, but now the output is:

j?=>@+89>2/<@p/<6@2+-5/&#060

Yeesh. What went wrong? Well, when we rearranged the code, we accidentally removed a character -- the newline after line 2. Somehow, that dramatically altered the output. Let's look at what's actually going on here.
The first line uses split?, which splits a string into an array using a specified delimiter. Here, there is no delimiter specified between the slashes, so the string is simply being converted to an array.
Next we have a foreach loop that operates on the array foreach? operates on arrays, applying the loop statements to successive elements. There is no loop variable specified, so $_ is used by default. $_ will be set to sequential values of the array @; as the loop iterates (i.e. 0, ;, o, etc.).
The first statement of the for loop is pop?, which returns the last value of an array and then removes it. So each time we go through the loop, the array becomes smaller. This reveals quite a bit about the nature of the JAPH. If we examine the initial string, we see that it is 50 characters long (don't forget the newline), so only 25 characters will be processed before the loop ends. We also see that our suspected red herring is in the latter half of the string, so it will be popped off before it reaches the loop.

Finally we get to the real meat of the JAPH. The chr function is relatively straightforward; it converts ASCII values to their corresponding characters. Inside the parentheses, @; is being appended to 100 + ord. In a string context, @; simply returns its own size, so as the loop iterates it will equal 50, 49, 48, etc. ord is the inverse of chr; it returns the ASCII value of a character. I don't think I have to explain what variable it's operating on. The result of the concatenation is then modulated by 86 and added to 32, and the final number is converted to a character and printed.

These numbers may seem arbitrary, but they were all chosen for a reason. 32 serves as the lower bound because it was the lowest ASCII value required (a space). Similarly, 86 + 32 was the upper bound because I knew the highest value would be 118 (u). And 100 had to be added to ord because of a problem introduced by the concatenation: after c, the ASCII values become 3 digits instead of 2, so the result of the concatenation jumps from 5099 to 50100. This meant that some target values were unreachable, i.e. there was no character that could be used in the string that would result in the proper output. Preemptively adding 100 meant there there was never a large jump.

I'll be honest: after setting up the formula, I essentially sat down and brute-forced my way through creating the gibberish string. There are worse ways to spend an hour.

@JAPH[1]

Okay boys and girls, time for another JAPH. This one will be a little trickier, but conceptually very similar to the previous one. Here it is:

$_="krJhruaesrltre c a cnP,ohet";
$_.=$1,print$2 while s/(..)(.)//;

Like we've seen before, this JAPH makes use of the $_ variable. You'll find that JAPHs or otherwise obfuscated/optimized code love using the $_ variable because it allows you to use functions like print and regex substitutions without having to pass in an argument.

The first line is a string of gibberish, but again there are some clues as to its true nature: the J and P are capitalized, there's a comma present, and there are 27 characters in total.

Wait, 27? Just Another Perl Hacker, only has 24. So there is more to this JAPH than just a simple reordering.
Looking at the second line, we see the .= operator. . is the string concatenation operator, so .= works just like += in that it's simply shorthand for $_ = $_ . . Here it appears that we are concatenating $_ and $1, which is another special variable in Perl. $[digit] contains the result of a regex pattern. If you look at the end of the line, you'll see a regex with two subpatterns, (..) and (.). So $1 matches the first one and $2 matches the second. We'll figure out what those patterns actually mean later.

Next comes a comma, which seems rather strange, because normally we would expect a semicolon. The comma operator? evaluates the left side, ignores the return value, and then evaluates and returns the statement on the right side.
The right side in question is a print statement and a while loop. Actually, it's a do while loop, because the conditional comes after the loop body. And the conditional in this case is a regex! This regex will return 1 if there's a match and 0 if there isn't. So this loop will terminate only when the regex doesn't match anything. So what exactly is the regex looking for?

In fact, it's not just looking. This is a substitution regex (as denoted by s), so whatever it finds will be replaced by what's between the second and third slashes, which is nothing. So its more of a deletion than a replacement.
Alright, enough stalling. What is being replaced or deleted or whatever? Well, in regex, a . matches any character. So the first subpattern matches groups of two characters, and the second subpattern matches any single character. So lets step through and see what this code is actually doing.

First, the regex will match krJ and delete it. Then kr will be appended to the end of the string, and J will be printed. On the second iteration, hru will be deleted, hr will be appended, and u will be printed. Do you see now why the concatenation is necessary? It essentially allows the regex to "loop" around the string. And you might be able to see why our gibberish string has 27 characters, too. Here's what happens to $_ as the code runs, with $2 enclosed in pipes:


kr|J|hruaesrltre c a cnP,ohet
hr|u|aesrltre c a cnP,ohetkr
ae|s|rltre c a cnP,ohetkrhr
rl|t|re c a cnP,ohetkrhrae
re| |c a cnP,ohetkrhraerl
c |a| cnP,ohetkrhraerlre
 c|n|P,ohetkrhraerlrec
P,|o|hetkrhraerlrec  c
he|t|krhraerlrec  cP,
kr|h|raerlrec  cP,he
ra|e|rlrec  cP,hekr
rl|r|ec  cP,hekrra
ec| | cP,hekrrarl
  |P|,hekrrarlec
,h|e|krrarlec c
kr|r|arlec c,h
ar|l|ec c,hkr
ec| |c,hkrar
c,|h|krarec
kr|a|recc,
re|c|c,kr
c,|k|rre
rr|e|c,
c,|r|r
rc|,|

 ////
 ///
 //
 /

Pierce the heavens.

@JAPH[0]

I like Perl JAPHs. If you don't know what a JAPH is, the answer is only a google away. Not even a full google. More like half a google.
In this ongoing series, I'll be deconstructing JAPHs. I'm no Perl monk, so I'm starting simple and working up. After all, the best way to learn is to teach (unless you know absolutely nothing, of course...)

$_ = "wftedskaebjgdpjgidbsmnjgc";
tr/a-z/oh, turtleneck Phrase Jar!/; print;

The first line defines the default variable $_ as a string of gibberish. But we can see immediately that the string has 25 characters - the same number as Just another Perl Hacker,. So we can safely assume that some operation will be performed on this string that transforms it into the well-known JAPH.
The second line uses the transliteration operator?, which, like many operators, operates on $_ by default. The transliteration operator essentially remaps letters. In this context, a-z specifies a range of characters, so the entire alphabet is being remapped.

original: abcdefghijklmnopqrstuvwxyz
remapped: oh, turtleneck Phrase Jar!

So all instances of a in $_ will be replaced by o, b will be replaced by h, and so on. Note that our gibberish string doesn't use y or z, so a-w would work just as well. The result of the transliteration is, of course, Just another Perl hacker,, which is subsequently printed (yes, print will also operate on $_ by default).

That was pretty long-winded for just two lines, but JAPHs are usually designed to be difficult to understand. That's what makes them so interesting!

Theme: Esquire by Matthew Buchanan.