ゆるめ

ゆるめなのは公開範囲です。

きごるふ(記号プログラミング + コードゴルフ)


始まりは orumin さん*1のトゥートが読めなかったので、書けるトゥートを何気なくぶつけたあたりです。以下使用環境および言語は Firefox 67.0b18 の Web コンソールにばちばち打ち込んだ JavaScript だと思ってください。



そこへ id:unarist さんがこちらのコードを括弧だらけにした上、戻り値も括弧だったら面白いんじゃないか的発想で乗ってきました。

({[[]](){[]}}[[]]())

これは、ES2015 からオブジェクトの中で関数を書く時に { 関数名 () {} } のような省略形で書けるようになった*2のと、{ "": 0 } のように空文字列でもプロパティを作れること、そしてブラケット表記法で書かれたプロパティは文字列に変換されること*3と、[] を文字列化すると ""(空文字列)になることのコンボで成り立っています。

しかし、アロー関数で簡潔文体*4を使った時以外は、関数内で明示的に return を書かないと戻り値が発生しないので、せっかく書いた [] が無駄になってしまっています。


記号だけで return 付きの関数を 500 字以内で記述するのは直感的に無理そうな気がするという旨の発言が以下です。

過去に何度か Mastodon 1 トゥート(500字)プログラミングで遊んでいて、記号のみで文字列を出力した際に骨が折れたなという記憶に基づいて発言しました。実際は記号であれば何でもいいゆるい縛りだったので、変数を使いまくって八文字の出力を達成していました。

ちなみに何らかの括弧(実質 [] 固定ですが)を返すコードは、括弧のみ縛りをしなければ、私が書いたものにちょっと手を入れて

({[[]]:()=>([])})[[]]()

で達成できます。なんなら

(()=>([]))()

でもいいし、ぶっちゃけ

[]

が一番短いのですが、今回は括弧でこさえた関数の戻り値も括弧だったら面白いねというテーマなので、括弧を返す関数を括弧で構築していきます。可能であれば 1トゥート 500字以内に収めたいですが、直感が無理だと言っているのでその辺はそこまでこだわりきらないことにして、なるたけ近づける、程度でいきます。

本当は元のコードのように純粋な括弧縛りでいきたかったのですが、どうしても + は使わざるを得なかったので、そこだけ勘弁してください。

参考にした記事[]()+= の六文字縛りで、特にゴルフ要素なくのびのびと記述していて、[](){}<>+ で 500字以内が目標という今回のレギュレーションとは少し違っていたので、自分で工夫を凝らす必要がある場面がいくつかあり、楽しかったです。


まず骨組みとして

(function(){}['constructor'])('return[]')()

というものを組み、"constructor""return[]" という文字列を記号で置き換え、function(){} もそれに相当する何かに置き換えていくという方向になりました。

これは記号のみで JavaScript を書く際に現状ほぼ必ず通る道なのですが、Function("return[]") のような書き方で作り出した文字列をコードとして実行することができる(eval 相当)ため、そして 任意の関数.constructor を参照すると Function になっているため、まずは "constructor" という文字列の獲得を目指すのです。

ちなみに 任意のオブジェクト(数値でも文字列でもなんでも).constructor が関数になっているため、任意の何か.constructor.constructor が組めれば eval を得たも同然になります。今回はゴルフも兼ねているのでそちらは使いませんでしたが、同じ文字列で一気に問題を解決していく様はとても爽快ですね。

あと、細かいことですが、"return[]" のように括弧類で始まる式を構文に書く際にはスペースが省略できる場合があるので、とりあえず削ってみて実行してみると良いかもしれません。for(i of[]) なども過去にゴルフで使いました。


置き換えるにあたって、はじめに "文字列"[添字] で使う文字を切り出していく際の添字用数字を捻出しました。以下が今のところ最短です。

+[] // 0
++[[]][+[]] // 1
++[++[[]][+[]]][+[]] // 2
++[++[++[[]][+[]]][+[]]][+[]] // 3
++[++[[]][+[]]][+[]]<<++[[]][+[]] // 4
++[++[++[[]][+[]]][+[]]<<++[[]][+[]]][+[]] // 5
++[++[++[[]][+[]]][+[]]][+[]]<<++[[]][+[]] // 6
++[++[++[[]][+[]]][+[]]][+[]]<<++[++[[]][+[]]][+[]] // 12

"[object Object]" の "c" を参照する際、一つ目の "c"(5) より二つ目の "c"(12) を参照した方が 3<<2 で短くなるのではと試してみましたが、5 の方が文字数が少なくなったので実際は使っていません。


それから、文字列の素材を用意しました。

{}+[] // "[object Object]"
[][[]]+[] // "undefined"
(+[]+[]>[])+[] // "true"
([]>[])+[] // "false"
{[[]](){}}[[]]+[] // "[[]](){}" (function)

これはコピペして実行するとエラーになる({} がオブジェクトのくくりではなくブロックのくくりとして解釈されるため、文法エラーになる)ので、試したい場合は適宜 () を補って実行してください。


これらを組み合わせて、以下の文字を生成しました。

((+[]+[]>[])+[])[+[]] // "t"
((+[]+[]>[])+[])[++[[]][+[]]] // "r"
(([]>[])+[])[++[++[++[[]][+[]]][+[]]][+[]]] // "s"
({}+[])[+[]] // "["
({}+[])[++[[]][+[]]] // "o"
({}+[])[++[++[++[[]][+[]]][+[]]<<++[[]][+[]]][+[]]] // "c"
({}+[])[++[++[[]][+[]]][+[]]<<++[[]][+[]]] // "e"
([][[]]+[])[++[++[++[[]][+[]]][+[]]][+[]]] // "e"
([][[]]+[])[+[]] // "u"
([][[]]+[])[++[[]][+[]]] // "n"
({[[]](){}}[[]]+[])[++[++[[]][+[]]][+[]]] // "]"

これもスクラッチパッドにそのまま貼り付けるとエラーが起きるので、行末に ; を補うか、一行ずつコンソールに入力して実行する形にしてください。

最初は "[object Object]" の方から "]"(14)を取ってこようかと思っていたのですが、14 という数字が半端なく、そして果てしないので、関数を一つ作ってそれを文字列化させ、そこに関数名として含まれる "]"(2)を取ってくる方向に変えました。

function(){} はたった今 "]" の取り出しに使った {[[]](){}}[[]] をもう一度そのまま使うことにしました。元のコードからだいぶ変わり果ててしまったコードの中で、元のコードの根幹がこうして別の形で現れてくるのは、なかなかにドラマチックですね。


これらを組み合わせてできたのが以下のコードです。

({[[]](){}}[[]][({}+[])[++[++[++[[]][+[]]][+[]]<<++[[]][+[]]][+[]]]+({}+[])[++[[]][+[]]]+([][[]]+[])[++[[]][+[]]]+(([]>[])+[])[++[++[++[[]][+[]]][+[]]][+[]]]+((+[]+[]>[])+[])[+[]]+((+[]+[]>[])+[])[++[[]][+[]]]+([][[]]+[])[+[]]+({}+[])[++[++[++[[]][+[]]][+[]]<<++[[]][+[]]][+[]]]+((+[]+[]>[])+[])[+[]]+({}+[])[++[[]][+[]]]+((+[]+[]>[])+[])[++[[]][+[]]]])(((+[]+[]>[])+[])[++[[]][+[]]]+({}+[])[++[++[[]][+[]]][+[]]<<++[[]][+[]]]+((+[]+[]>[])+[])[+[]]+([][[]]+[])[+[]]+((+[]+[]>[])+[])[++[[]][+[]]]+([][[]]+[])[++[[]][+[]]]+({}+[])[+[]]+({[[]](){}}[[]]+[])[++[++[[]][+[]]][+[]]])()

実行結果は [] になります。今試しに Google Chrome でも実行してみましたが、想定した実行結果になりました。


残念ながらというかやはりというか、578文字から縮められず、1 トゥート内には収まりきらなかったのですが、最初に Mastodon で出した 739文字のコード(

({[[]](){}}[[]][({}+[])[++[++[++[+[]][+[]]][+[]]<<++[+[]][+[]]][+[]]]+({}+[])[++[+[]][+[]]]+([][[]]+[])[++[+[]][+[]]]+[([]>[])+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+({}+[])[++[++[++[+[]][+[]]][+[]]][+[]]<<++[+[]][+[]]]+[(++[+[]][+[]]>[])+[]][+[]][++[+[]][+[]]]+([][[]]+[])[+[]]+({}+[])[++[++[++[+[]][+[]]][+[]]<<++[+[]][+[]]][+[]]]+({}+[])[++[++[++[+[]][+[]]][+[]]][+[]]<<++[+[]][+[]]]+({}+[])[++[+[]][+[]]]+[(++[+[]][+[]]>[])+[]][+[]][++[+[]][+[]]]])([(++[+[]][+[]]>[])+[]][+[]][++[+[]][+[]]]+({}+[])[++[++[+[]][+[]]][+[]]<<++[+[]][+[]]]+({}+[])[++[++[++[+[]][+[]]][+[]]][+[]]<<++[+[]][+[]]]+([][[]]+[])[+[]]+[(++[+[]][+[]]>[])+[]][+[]][++[+[]][+[]]]+([][[]]+[])[++[+[]][+[]]]+({}+[])[+[]]+({[[]](){}}[[]]+[])[++[++[+[]][+[]]][+[]]])()

)から 161文字削れて、個人的には大分健闘したなと思ったので、こうしてブログ記事として仕上げて出すことにしました。

もしこのレギュレーションで 500字まで削れましたらご一報ください。Mastodon の方で紹介したいと思います。