ゆるめ

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

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


始まりは 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 の方で紹介したいと思います。

ぐー🏠⛳

ライトニングトークというものを生で見たことがないのですが、その状態を逆手に取って、何も知らないまま想像でライトニングトークを語ったらおもしろいのではないかとふと思い立って、トークしました。

f:id:pacochi:20190321072815j:plain:w400
Google Home でいかに短く指示を伝えるかという話です。

前述の通り音が出ますのでご注意ください。

音声をつけたら好きなタイミングでクリックができなくなってしまったので、元のスライドも公開しておきます。

これがもう総合的にとてもとても難しくて、さらっとネタを用意してスライド書いて過不足なくスピーチする皆様がいかにすごかったかをしみじみ実感しました。

後から思ったのですが、短くするコツなんかも入れた方が良かったかもしれませんね。ここで補足しておくと、「亭主関白になりきる」みたいな感じでしょうか。

私だけはてなブログにスターがつけられなくなった原因と対処法

Mastodon ブーム以来ずっとそちらの方にいたのですが、ここ最近観測範囲で書かれる Advent Calendar のはてなブログ利用率が高く、一周してはてなに戻ってきた感じがあります。

戻ってきたのはいいのですが、SSL 化の影響か、はてなブログの記事にスターがつけられなくなっていて、とても不便を感じました。

f:id:pacochi:20181216235751p:plain
ログインしているのにログインしていないと言われる

また、サードパーティー Cookie を有効にしているのですが、上部のバーでも無効になっていますと言われてしまいました。

f:id:pacochi:20181216235937p:plain
サードパーティー Cookie が無効になっていますが出る

他の方は難なくスターをつけているので、私の側で何か余計なことをしているのかなと思い、その線で検証していきました。

原因は、Ghostery の「強化された追跡防止」という機能によってその辺の情報がせき止められていたことによるものでした。

f:id:pacochi:20181217000341p:plain
盾マークが強化された追跡防止、六件ブロックされている

盾マークをクリックして灰色にしてからリロードすると、上部のバーもはてなスターも復活しました。

信頼するサイトに入れるほどすべてのはてなブログを信頼している訳ではないので、スターをつける時だけ盾を外してつけようかと思っています。

カスタム絵文字備忘録

追記: 気軽にコピーして大丈夫な絵文字は /hen.acho.co/emoji/ にまとめています。

Mastodon およびその周辺で暮らしているうちに、自作のカスタム絵文字が蓄積されてきました。当エントリは各絵文字の成り立ちや思い出を、主に未来の私のために残しておく目的で作成されました。

続きを読む

またよろしくね Firefox Developer Edition

以前の記事Firefox Developer Edition から別のビルドへ乗り換えた旨を書きましたが、そのちょっと後に Firefox Developer Edition が復活していたみたいです。今さっき気付きました。欲を言えばもっと早く気付きたかったところですが、今気付けて良かったです。
rockridge.hatenablog.com
野良アドオンもまた使えるということで、早速戻りました。

でも、何故かそのままだとアップデートに失敗し、インストーラを落として上書きインストールしても同じ状態だったので、もっと直接落とせるところから落としてきて、インストールしました。

前と同じく、特に移行作業はしていません。Sync で前の子がなかなか消えなかったりしたら消したりする作業が必要になるかもしれませんが、今のとこ何もしていません。

452バイトテトリス

先日 7行テトリスのことを話題にしている人を見かけて、懐かしくなって巡ってきました。

7行テトリス482バイトテトリス6行テトリス464B tetris、と辿ったところで行き止まりになって、新しいものを見つけられなかったので、自分で書くことにしました。

デモページで動作の確認ができます。コードは以下の通りです。

ES201X を取り入れつついじったら、452バイト (Shift_JIS、LF で保存時) になりました。

<pre id=D><script>onkeydown=e=>K=e.which-38,Z=X=B=[],(Y=f=>{C=[A=12]
K&B.some((p,n)=>Z[h+(K+6?p+K:C[n]=p*A-(p/9|0)*145)])?0:K+6?h+=K:t?B=C:0;B.map(
q=>X[f|=Z[A+h+q],h+q]=1);if(f||1-B)for(Z=X,X=[l=228],B=[~[10,23,-3,-14,A][t=++t%
7],0,1,t-6?-A:2];l--;h=5)for(l%A?l-=l%A*!Z[l]:(P+=f++,K=l+=A);--K>A;)Z[K]=Z[K-A]
for(K=i=0,h+=A,S=P;i<240;)S+=X[i]|(X[i]=Z[i]|=++i%A<2|i>228)?~-i%A?'■':`
■`:'_';D.innerHTML=S;Z[5]||setTimeout(Y,i-P)})(h=K=t=P=0)</script>

80字越したら改行を入れるルールがあるみたいなので、それに準じました。

<pre id=D><script>onkeydown=e=>K=e.which-38,Z=X=B=[],(Y=f=>{C=[A=12]
K&B.some((p,n)=>Z[h+(K+6?p+K:C[n]=p*A-(p/9|0)*145)])?0:K+6?h+=K:t?B=C:0
B.map(q=>X[f|=Z[A+h+q],h+q]=1)
if(f||1-B)for(Z=X,X=[l=228],B=[~[10,23,-3,-14,A][t=++t%7],
0,1,t-6?-A:2];l--;h=5)for(l%A?l-=l%A*!Z[l]:(P+=f++,K=l+=A);--K>A;)Z[K]=Z[K-A]
for(K=i=0,h+=A,S=P;i<240;)S+=X[i]|(X[i]=Z[i]|=++i%A<2|i>228)?~-i%A?'■':`
■`:'_';D.innerHTML=S;Z[5]||setTimeout(Y,i-P)})(h=K=t=P=0)</script>

…と思っていたのですが、元々は 79文字 * 7行という制約だったみたいです。見逃していた記事があって、そこから判明しました。そちらに準じた場合は 451バイトになります。

改行も活用するため、セミコロンが外せそうな部分は積極的に外しています。

以下はテキストエディタの機能で JavaScript の部分のみそれっぽく整形したものです。

手を入れた部分のみコメントしています。他の方の書いた部分は他の方の解説をご覧になってください。

// "event" って変数が firefox になかったから JavaScript 内にしまった
onkeydown = e => K = e.which - 38,
// B を最初から配列扱いするため初期化時の判定方法を変更、副作用で [] 内での宣言が NG に
// "" とか 0 とかになる変数なら宣言できるけど今のとこ空配列
Z = X = B = [],
// いつも思うけどアロー関数ほんとぐっと縮まるね
// この f は初回以外は undefined だけど宣言済み変数として便利に使える
(Y = f => {
	// 上で追い出された A の宣言ここで
	// Array.prototype にくっついてるメソッド使うから Y で代用はできなかった
	C = [A = 12];
	// some() で接触フラグ作り、元のアルゴリズムには手を入れてない
	// 接触してた時はすぐ引き上げるから C が未完成になるけど問題ない
	K & B.some(
		// (p, n) の n 外に出して ++ とかしてみたけど、宣言と初期化で手間取って長くなった
		// n が外に出せれば (,) の三文字が削れてつよい
		(p, n) => Z[h + (K + 6 ? p + K : C[n] = p * A - (p / 9 | 0) * 145)]
	) ? 0 : K + 6 ? h += K : t ? B = C : 0;
	// f = undefined でもいいように |= にした
	// q => (式,式) だと () いるから [] 内にお邪魔させた
	B.map(q => X[f |= Z[A + h + q], h + q] = 1);

	// B を最初から配列にしたから判定長くなった
	// 1 - [] ⇒ 1 - "" ⇒ 1 - 0 で 1、1 - [1,1] ⇒ 1 - "1,1" ⇒ 1 - NaN で NaN
	if (f || 1 - B)
		for (Z = X, X = [l = 228], B = [~[10, 23, -3, -14, A][t = ++t % 7], 0, 1, t - 6 ? -A : 2]; l--; h = 5)
			// 設置判定時必ず 1 になってるから k の代わりに f 使うことにした
			// あと c 宣言する暇なかったから K 使い回した
			for (l % A ? l -= l % A * !Z[l] : (P += f++, K = l += A); --K > A; )
				Z[K] = Z[K - A];

	// K と i ここでリセット
	for (K = i = 0, h += A, S = P; i < 240; )
		// <pre> だから \n に、改行コード一文字にしてテンプレートリテラル使うとさらに一文字減
		S += X[i] | (X[i] = Z[i] |= ++i % A < 2 | i > 228) ? ~-i % A ? '■' : `
■` : '_';

	// innerText は何故か firefox でキー反応が悪くなるから無理だった
	// <body onload=""> も何故かキー反応が鈍ったから採用できなかった、採用できたら 3バイト縮む
	D.innerHTML = S;
	Z[5] || setTimeout(Y, i - P)

})(h = K = t = P = 0)

新しめの書き方を利用したアルゴリズムなんかでまだまだ縮まる余地が存分にあるので、つよい方々の登場が待たれます。


あと、せっかくなのでブックマークレットにしておきました。なんだかんだでいっつもせっかくしてる感じがします。
T⃞T⃞R⃞S⃞ - Hatena::Let


あとゴルフつながりで、先日 Hatena::Let で Fork して遊んだものも載せておきます。スターがたくさんなのは、たくさん更新してその度に更新箇所にスターをいただいたからで、ブツそのものは通常通りです。
Zalgolf ('unuse strict') - Hatena::Let