jsでズンドコキヨシのコードゴルフ(87byte)

  • 68
    いいね
  • 26
    コメント
この記事は最終更新日から1年以上が経過しています。

元ネタ
http://qiita.com/shunsugai@github/items/971a15461de29563bf90

n番煎じネタですが、コードと工夫したことの紹介です。
実行環境はchrome 49です。

レギュレーション

  • 'ズン'または'ドコ'を等確率で出力する。
  • 直近の出力が'ズンズンズンズンドコ'だった場合、'キ・ヨ・シ!'を出力して処理を停止する。
  • 各出力において、改行の有無は問わない。

コード

元コード95byte

for(c=console,n=0;n!=30;)
  n=(n+Math.random())*2&31,c.log(n&1?'ズン':'ドコ');
c.log('キ・ヨ・シ!')

その後、強い人達と自分で87byteまで短縮

現在最短87bytefujitanozomu

for(n=3;n-64;console.log(n-64?(n|=2*Math.random())&1?'ドコ':'ズン':'キ・ヨ・シ!'))
  n<<=6

(※見やすさのために改行、インデントを入れました)

工夫

長い名前のエイリアス

c=console

consoleは2度出てきて長いのでcという短縮名を用意します。
console.logを短縮してもいいのですが、実行環境によっては、関数のthisコンテキストが変わってしまう事に起因するエラーが起こるため、このようになってます。

追記

そもそもconsole.logを1箇所にまとめることで更に短縮

判定をビット列で

n!=30

ズン1, ドコ0としてズン ズンズン ズンドコの判定は

0b11110 = 30 というビット列が現れるかどうかで判定できます。

ビット列でパターンを記憶する

n=(n+Math.random())*2

値を左ビットシフトさせながら最下位に新しいビットを追加していきます。
ビットシフトの演算子は<<2文字なため、今回は掛け算で代用しています。
n*2でビットシフトを、Math.random()*2で新しく0or1を詰めていきます。

直近の5ビットだけ取り出す

&31

0b11111=31との論理積を取ることで直近の5ビットだけ取り出せます。
また、二次的な効果として、Math.random()で得られる小数を整数に丸めることが出来ます。

カンマ演算子

n=(n+Math.random())*2&31,c.log(n&1?'ズン':'ドコ');

カンマ演算子は、繋がれた複数の式を評価し、最後の値を返します。
これを用いることで、for文の中身全体が1つの式として書くことが出来、for文のカッコ({})を省略できます。

3項演算子

n&1?'ズン':'ドコ'

最後に追加された1ビットを見ながら、ズンorドコを出力します。

強い人達の工夫

評価方法を変える(cympfh)

jsでは数値型をbooleanにキャストすると、

  • 0NaNFalse
  • その他の通常の数値はTrue

とキャストされる。

そこで

n!=30

n-30

にする。 1byte短縮。

順序を変える(cympfh)

c.log(n&1?'ズン':'ドコ')

の位置をfor文の更新式の位置に持ってくる。
for文の更新式は、for文の中身実行後に実行されるため実行順序は変わらない。
これによりカンマ演算子が削れる。 1byte短縮。

代入の位置を変更(liburari)

c=consoleの位置を移動させることで、カンマ演算子を削除

1byte短縮

ズンドコを入れ替える(srd7)

ズンドコを入れ替えると、探索すべきパターンは0b00001=1となる。
そのため、パターンマッチが、n-31からn-1に変更できる。

ただし、n-1では初期状態によっては誤検出を起こしてしまうため、
初期状態をn=3にする必要がある。(コメント参照)

1byte短縮

オーバーフローさせる

n<<=6

jsのビット演算は、32bitのビット演算により処理される。
そのため、1bitシフトではなく6bitシフトにすると、
ちょうど「ズンズンズンズンドコ」の5セットで5*6=30bitとなり、直近の5回の出力の記録のみを保持できるようになる。
最後だけがドコだった場合、つまり n = 1<<6 = 64 の時が、終了のタイミングである。

最後に

悪かった。俺が悪かった。
もっと短い書き方がアレばぜひ教えて下さい。