JavaScript
ECMAScript
ネタ
クソコード

雨ニモマケズンドコキヨシ

今回紹介するコードはこちらです。

const poem =
`雨ニモマケズ
風ニモマケズ
雪ニモ夏ノ暑サニモマケヌ丈夫ナカラダヲモチ
慾ハナク
決シテ瞋ラズ
イツモシヅカニワラツテイル
一日ニ玄米四合ト味噌ト少シノ野菜ヲタベ
アラユルコトヲ
ジブンヲカンジョウニ入レズニヨクミキキシワカリ
ソシテワスレズ
野原ノ松ノ林ノ蔭ノ小サナ萱ブキノ小屋ニイテ
東ニ病気ノコドモアレバ行ッテ看病シテヤリ
西ニツカレタ母アレバ行ッテソノ稲ノ束ヲ負ヒ
南ニ死ニサウナ人アレバ行ッテコハガラナクテモイヽトイヒ
北ニケンクヮヤソショウガアレバツマラナイカラヤメロトイヒ
ヒドリノトキハナミダヲナガシ
サムサノナツハオロオロアルキ
ミンナニデクノボートヨバレ
ホメラレモセズ
クニモサレズ
サウイフモノニワタシハナリタイ

南無無邊行菩薩
南無上行菩薩
南無多宝如來
南無妙法蓮華経
南無釈迦牟尼佛
南無浄行菩薩
南無安立行菩薩`;

((phrase, next) =>
   (next = (rnd, ...prev) => {
      if ((rnd = Math.random() < 0.5)) {
         console.log(phrase[0][12] + phrase[0][2]);
      }
      else {
         console.log(phrase[1][6] + phrase[1][5]);
         if (prev.every(v => v)) {
            console.log([phrase[0][17], phrase[0][14], phrase[0][19]].join('・')
               + decodeURI(encodeURI('Ihatov').split('%').filter((v, i) => [0, 1, 2, 9].includes(i)).join('%')));
            return;
         }
      }
      next(...prev, rnd);
   })(...[, , , , , ])
)(poem.match(/.+/g).filter((v, i) => /i/.test(' by Kenji Miyazawa'[i])));

「雨ニモマケズ...」で始まる宮沢賢治の有名な詩ですね。イーハトーヴ(Ihatov)は、宮沢賢治の童話などの中に登場する理想郷と言われています。

さて、このコードは何をするプログラムなのでしょうか。
実際に試してみましょう。

実行結果

ズン
ドコ
ドコ
ズン
ドコ
ズン
ズン
ドコ
ドコ
ズン
ドコ
ズン
ドコ
ズン
ズン
ドコ
ドコ
ズン
ズン
ズン
ズン
ドコ
キ・ヨ・シ!

Σ(゜Д゜;)
な、なんと、あの名作からズンドコキヨシ...

というわけですが、以下に解説っぽいものを載せるので、暇な人は見ていってください。

まず

const poem = `...`

poemに詩を丸ごと代入しています。

((phrase, next) =>
   ...
)(poem.match(/.+/g).filter((v, i) => /i/.test(' by Kenji Miyazawa'[i])));

即時実行のアロー関数です。
引数を見てみましょう。match(/.+/g)で、poemを改行で分割した配列にしています。
次にfilterで必要なものを選り分けています。/i/.test(' by Kenji Miyazawa'[i])は、文字列' by Kenji Miyazawa'のインデックスiの文字が'i'の時にtrueになります。
つまり、filterで返されるのは、元の配列の8番目と11番目の要素で、引数phrase['ジブンヲカンジョウニ入レズニヨクミキキシワカリ', '東ニ病気ノコドモアレバ行ッテ看病シテヤリ']になります。この中にズンドコキヨシに必要な片仮名が全て揃っています。
一方、引数nextは省略されているので、今の時点ではundefinedとなっています。

続いて

(next = (rnd, ...prev) => {
   ...
})(...[, , , , , ])

nextに関数を代入すると同時に、それを実行しています。これを利用して再帰をします。
rndundefinedprevは要素数4のundefinedの配列になっています(配列リテラルの最後のコンマは無視されることに注意)。

ここからはよくあるズンドコキヨシです。

if ((rnd = Math.random() < 0.5)) {
   console.log(phrase[0][12] + phrase[0][2]);
}
else {
   console.log(phrase[1][6] + phrase[1][5]);
   if (...) { ... }
}

まずrndをランダムなBoolean値で上書きしています。先程のphraseを使って、trueならば'ズン'falseならば'ドコ'を出力します。
'ドコ'の場合は

if (prev.every(v => v)) {
   console.log(...);
   return;
}

prevの要素が全てtruthyな場合、すなわち4回'ズン'を出力していた場合(prevの要素数は下で説明する理由から常に4になります)、'キ・ヨ・シ!'を出力して終了します。
console.logの引数が少し複雑になっています。

[phrase[0][17], phrase[0][14], phrase[0][19]].join('・')
      + decodeURI(encodeURI('Ihatov').split('%').filter((v, i) => [0, 1, 2, 9].includes(i)).join('%'))

前半部分は単に['キ', 'ヨ', 'シ'].join('・')となっているだけです。
複雑なのは後半部分です。
まず、encodeURI('Ihatov')の結果は'%EF%BC%A9%EF%BD%88%EF%BD%81%EF%BD%94%EF%BD%8F%EF%BD%96'です。それを'%'splitして、filterで0・1・2・9番目の要素を取り出して、更に'%'joinしています。したがって、decodeURI('%EF%BC%81')となり、これは文字'!'です。
ズンドコキヨシの形跡を残さないために、かなり工夫しました。

最後は、再帰の部分です。

next(...prev, rnd);

prevの初期値は要素が4つの配列でした。ということは、次の呼び出しではnext(prev[0], prev[1], prev[2], prev[3], rnd)となります。nextの引数の宣言は(rnd, ...prev)でしたから、新しいrndは元のprev[0]であり、新しいprevは配列[prev[1], prev[2], prev[3], rnd]となります。つまり、prevの要素数を維持したまま要素を1つずつシフトして、常に直近の4つだけがprevに格納されるようになっています。

そういうわけで、このコードでズンドコキヨシが実行できるのです。

let poem =
`雨ニモマケズ
風ニモマケズ
雪ニモ夏ノ暑サニモマケヌ丈夫ナカラダヲモチ
慾ハナク
決シテ瞋ラズ
イツモシヅカニワラツテイル
一日ニ玄米四合ト味噌ト少シノ野菜ヲタベ
アラユルコトヲ
ジブンヲカンジョウニ入レズニヨクミキキシワカリ
ソシテワスレズ
野原ノ松ノ林ノ蔭ノ小サナ萱ブキノ小屋ニイテ
東ニ病気ノコドモアレバ行ッテ看病シテヤリ
西ニツカレタ母アレバ行ッテソノ稲ノ束ヲ負ヒ
南ニ死ニサウナ人アレバ行ッテコハガラナクテモイヽトイヒ
北ニケンクヮヤソショウガアレバツマラナイカラヤメロトイヒ
ヒドリノトキハナミダヲナガシ
サムサノナツハオロオロアルキ
ミンナニデクノボートヨバレ
ホメラレモセズ
クニモサレズ
サウイフモノニワタシハナリタイ

南無無邊行菩薩
南無上行菩薩
南無多宝如來
南無妙法蓮華経
南無釈迦牟尼佛
南無浄行菩薩
南無安立行菩薩`;

((phrase, next) =>
   (next = (rnd, ...prev) => {
      if ((rnd = Math.random() < 0.5)) {
         console.log(phrase[0][12] + phrase[0][2]);
      }
      else {
         console.log(phrase[1][6] + phrase[1][5]);
         if (prev.every(v => v)) {
            console.log([phrase[0][17], phrase[0][14], phrase[0][19]].join('・')
               + decodeURI(encodeURI('Ihatov').split('%').filter((v, i) => [0, 1, 2, 9].includes(i)).join('%')));
            return;
         }
      }
      next(...prev, rnd);
   })(...[, , , , , ])
)(poem.match(/.+/g).filter((v, i) => /i/.test(' by Kenji Miyazawa'[i])));

分かりやすいコードを書くのにもある程度の技術が要りますが、意図的に分かりにくいコードを書くのも難しいものですね。

皆さんも、カモフラージュしたコードを書いてみませんか。頭の体操になりますよ。
あ、くれぐれも仕事ではやらないように...