in reply to Most CPU-consuming JAPH ever!

Today i discussed the code with some colleagues, and i had to give some explanations before they smile. Some things becomes truly obscure only after they are explained. So i decided to give some comments about the code above.

It's magic...

On the line "003" we start with some 100-character string. This string looks like an english phrase (unfortunately a little ugly), but it's magic - try to change or delete any letter, as a result some random string will be printed, and it's unlikely that we get anything meaningful.
Ok, the phrase is long enough and it contains all characters that we need to build JAPH, so we just have to peek them in the right order:

@_ = (83, 27, 81, 64, 73, 46, 63, 52, 77, 93, 72, 23, 43, 37, 7, 16, 4 +0, 89, 15, 6, 26, 98, 4, 97, 31);
And indeed we get exact this numbers in "@_" just before we print the result on the line "030", but how could it happened? If we don't have this numbers in the code, then how could it be possible to get them on the right places in "@_" at the end? It's magic.

The constant $X=44802, defined on the line "005", is also magic - try to change it, we get a random string as program output again.

Let's look at the function "_", which is defined on the line "007".

sub _{$s += ++$n * ord for @_; $n %= @I; $s %= $X};
It is supposed to be called with an array of characters as argument and calculates a kind of checksum for this array, in a some simple way, which is absolutely not magic.
The function takes an ASCII character code with "ord($_)" for each character in the array and multiplies it by the position of this character in the array "++$n" - the results of the multiplications add up in "$s".
So for @I=('a','b','c') the result of calling _(@I) would be 590.

97*1 + 98*2 + 99*3 = 590

And for our initial string "$_" (which gets character by character into "@I" on the line "009"), such checksum should be 467391, but due to "$s %= $X" it couldn't become greater then $X-1 = 44801, so we actually get 467391 % 44802 = 19371 in "$_I" on the line "011".

On the line "013" the array "@_" is initialized.

$_/=$_ for @_ = 1..$_I%34;

There is nothing magical in this line, it was written this way just to confuse the russians. "$_I%34"=19371 % 34 is just a confusing way to write 25 - we need it, while JAPH string is 25 characters long.
"$_/$_" always results to 1 (or "division by zero" error, but there is no zeros in 1..25)
So finally we get an array of 25 elements which are all equal 1.

@_ = (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +, 1, 1, 1, 1);
If we proceed with "print" on the line "030" right now, without entering the loop on the lines "015".."028", the character with index "1" form array "@I" will be written 25 times, resulting in the following string
@I[@_] = eeeeeeeeeeeeeeeeeeeeeeeee
The loop code is also written in a confusing way, otherwise it wouldn't be a JAPH. But if we rewrite it line by line in the way we usually write loops and update elements in arrays, we'll see that the whole procedure is actually very simple.
During every iteration of the outer loop, the inner loop iterates 24 times. So 24 sequent elements of the array "@_" are getting assigned to a sum of its own value and the value of the previous element (the last element of the array is considered to be the previous for the first one), this happens on the line "022". Here "%@I" is equal to "%100" (while "@I" consists of 100 1-character elements), this makes sure that the values in "@_" remain less or equal 99 - so they all could later be used as indexes of the array "@I" (in "print" on the line "030"). The 25-th element of the array "@_" remains unchanged.

So after the first iteration of outer loop, the element with index "0" of the array "@_" remains unchanged and 24 others becomes 2.

Iteration 1: @_ = (1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +2, 2, 2, 2, 2, 2, 2, 2)

which would result in the following output string

@I[@_] = eaaaaaaaaaaaaaaaaaaaaaaaa

After the second iteration the element with index "1" remains unchanged and all others change there values, so we get

Iteration 2: @_ = (3, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4) @I[@_] = vaeeeeeeeeeeeeeeeeeeeeeee

And so on, after index "24" comes index "0" again:

Iteration 0: @_ = (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1) @I[@_] = eeeeeeeeeeeeeeeeeeeeeeeee Iteration 1: @_ = (1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2) @I[@_] = eaaaaaaaaaaaaaaaaaaaaaaaa Iteration 2: @_ = (3, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4) @I[@_] = vaeeeeeeeeeeeeeeeeeeeeeee Iteration 3: @_ = (7, 5, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8) @I[@_] = e errrrrrrrrrrrrrrrrrrrrr ........... Iteration 10: @_ = (23, 14, 78, 94, 68, 42, 58, 22, 13, 12, 24, 24, 24, 24, 24, 24 +, 24, 24, 24, 24, 24, 24, 24, 24, 24) @I[@_] = rsr tciu crrrrrrrrrrrrrrr ........... Iteration 100: @_ = (85, 5, 17, 5, 9, 87, 97, 40, 47, 43, 15, 75, 47, 75, 44, 82, 7 +7, 25, 77, 13, 85, 60, 37, 10, 9) @I[@_] = P i o rlr hurus tit PePbo ............ Iteration 1000: @_ = (15, 9, 59, 68, 84, 96, 78, 8, 35, 63, 76, 34, 39, 87, 79, 20, +41, 56, 82, 91, 47, 33, 38, 4, 53) @I[@_] = hottAorrynsrb o iw ortuen

The output strings become totally random very quickly, and it is hard to believe, that starting with "eeeeeeeeeeeeeeeeeeeeeeeee" and proceeding this way one can ever get anything readable.

But there is something, which make it even more unbelievable.
Let's look at the break condition for the outer loop on line "025"

last if $_I == _@I[@_];

If we comment it out, some random string instead of JAPH will be printed, it means that the outer loop indeed stops iterating at the point where the break condition becomes true and at the same moment the array "@I[@_]" becomes into JAPH.
As discussed before "$_I" is equal to 19371, and what about "_@I[@_]"?
The code "_@I[@_]" calls actually our checksum function "_" for the 1-character array "@I[@_]" - our output string for this iteration.
So when the function "_" is called the last time (before the output was printed), the JASP-string was already in "@I[@_]" array. But if we calculate the checksum for the string "Just another Perl hacker," using algorithm described before we get 29875. 29875 is actually not equal to 19371, then why is the loop stops at this point? Can perl occasionally evaluate "19371 == 29875" as "true" value? ...

No, perl ist absolutely reliable in any case, and "19371 == 29875" is always false! So where is the mistake? Variables "$s" and "$n" in the definition of the function "_" on the line "007" are never initialized (typical YAPH code - no strictness, no warnings and no variable initializations). The value of "$s" is actually what the function "_" returns. So each subsequently call of "_" actually starts with the values from the previous call.
The value returned from the last call of "_" was really 19371, but how it gets there?
Below is the evolution of values "$s" and "$n" during the program run:

After calculating of _@I on the line "011": $s=19371 $n=0 Iteration 1: $s=6098 $n=25 Iteration 2: $s=12778 $n=50 Iteration 3: $s=7504 $n=75 Iteration 4: $s=32145 $n=0 Iteration 5: $s=43630 $n=25 Iteration 6: $s=16452 $n=50 Iteration 7: $s=5600 $n=75 Iteration 8: $s=27784 $n=0 Iteration 9: $s=15712 $n=25 Iteration 10: $s=28150 $n=50 Iteration 11: $s=26454 $n=75 ................ Iteration 101: $s=19938 $n=25 ................ Iteration 1001: $s=31849 $n=25 Just before JAPH-string was printed: $s=19371 $n=0

As it was shown before, after about 100 iterations the string represented by the array "@I[@_]" becomes very random. The value of "$s" starts with 19371 (the checksum of the initial string), then on each iteration some random amount adds up to it, so that the values of $s are randomly distributed in the range between 0 and 44801. It is not very likely that it gets it's original value 19371 on a particular iteration - the chances are about 1/44802. After thousands of iterations this rarely event occurs for the first time. Thankfull and happy we stop looping and just for fun look into "@I[@_]", and what we find there is the JAPH-string!!! Absolute garbage would be printed only one iteration before or one iteration after! Could so much luckiness be supposed? Is it not easier to guess all Lotto numbers?..
Yes, it's magic...