これはKAZOONの不定期日記(チラシの裏)の2015年版です.下に行くほど新しいです. 2015/7/18 ゴリラシャッフル もう7月も後半となるのに,本年最初の日記だ. さて,タイトルのゴリラシャッフルだが,出展はポーンさんのツイート[1]だ. 適宜改行を加えて引用すると,次の通り. > 1,1,2,1,2,3,1,2,3,4……と階段状にディールシャッフルを1回すると、 > ふつうのディールシャッフル1回より周期性がなく、 > ヒンズーシャッフル数回より連続性がなくなり、予測可能性が減じると感じます。 > シャッフルの不備がもろに出るゴリティア用に考えた、ゴリラシャッフルです。 ゴリティア[2]は,ゴリラとバナナの2種類のカードを計36枚使うゲームで, 36枚のカードでゴリラシャッフルの山を作ると,ちょうど8個の山ができる( 8*(8+1)/2 = 36 ). ディールシャッフルでいつも気になるのが,どのように山を結合していくかというところなのだが, ここではとりあえずサイズ8の山をサイズ1の山に乗せ, できたサイズ9の山をサイズ7の山に乗せ,それを……というように, まだ触っていない山の中で一番大きい山と一番小さい山を交互に取っていく取り方を採用してみる. つまり,次のようにシャッフルされる(左が上で右が下にあるカードのIDである). シャッフル前 0123456789abcdefghijklmnopqrstuvwxyz シャッフル後 slfa6310ztmgb742yrunhc85xqkvoid9wpje さて,これではなんとも言えないので,ゴリラとバナナがどのように混ざっていくかを見てみよう. ゴリラとバナナの比は実は自由に選べるのだが,ここではそれぞれ同量で, ゴリラとバナナ各連続18枚の並びが,ゴリラシャッフルを繰り返すとどのようになるかを見てみる. ggggggggggggggggggbbbbbbbbbbbbbbbbbb bbggggggbbbgggggbbbbggggbbbbbbggbbbg bggbggbbgbgbggggbbggbgbgbbggbbgbbbbg bgggbbgbgbbbbbggbgggbgggbgbbbggbbbgg bggbgggbgggbbbbggbgggbgbbbbbbgbbbggg bbgggbgbggggbbgggbbbbbgggbgbbgbgbbgb bbggggbbbggggbgggbbgbbgbbgbggbbgbbbg 最初の6回分を示すと上のようになる. 1回だけだと少々連続部分が残りすぎている気がするが,2回やると程よく混ざっているように見える. 次に,初期状態でゴリラとバナナが交互に並んでいる場合を見てみる. gbgbgbgbgbgbgbgbgbgbgbgbgbgbgbgbgbgb gbbggbbgbbggbbgggbgbbggbbggbggbbgbbg ggggbgbggggggggbbbbbbbbbbgbbbgbbggbg bbbgbgggggbbggbgbbbbbggggbbbbbggggbg bggbggbbgbgbbgbbbbggbggggbbggbgggbbb ggbgbbgbbbgbbbggbgggbbggbbbggggbgbgb gbggggggbggbbbbbgggggbbbbbbbbgbbgbgg この場合はちょうど2回のときは連続部分が目立つ. ちなみに他のシャッフル方法だが, ディールシャッフルとリフルシャッフルは自明だからやらなくてもいいだろう. ヒンズーシャッフルは,ここでは一度に取る枚数が 3,4,5,6枚となる確率がそれぞれ 1/8,3/8,3/8,1/8 になるとして,シミュレートしてみよう. ggggggggggggggggggbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbgggggggggggggggggg gggggggggggggggggbbbbbbgbbbbbbbbbbbb bbbbbbbbbbbbbgbggbbbbggggggggggggggg gggggggggggggbbbgggbggbbbbbbbbbbbbbb bbbbbbbbbbbggbbbbbgggbgggbgggggggggg gggggggggbgggbgbbgggggbbbbbbbbbbbbbb gbgbgbgbgbgbgbgbgbgbgbgbgbgbgbgbgbgb gbgbgbgbgbbgbgbgbgbggbgbgbbgbgbgbgbg gbggbgbgbgbgbgbbbgbgbbgbgbggbgbggbgb bgbggbgbgbggbgbgbbggbgbbbbgbgbgbggbg gbggbgbgbggbbbbbbggbbgbgbgbggbgbggbg bgbgbgggbgbggbggbbgbbbbbbbgbgggbggbg gbgbgggbgbbbbgbgbbbggbggbgggbgbbgbgb まあ,わかってはいたが,全然混ざらん. さて,話をゴリラシャッフルに戻す. ゴリラシャッフルのような決定的なシャッフルは,同じシャッフルを繰り返し用いると,いつか必ず同じ並びに戻ってくる. (異なる並びから同じシャッフルを使って同じ並びになることはない(逆シャッフルが存在する)ため, A,B,Cを並び方のIDとして,A→B→C→B→C…… のような初期状態を含まないループに入ることはない. また,n枚のカードの並び方はn!しかないため,いつかは同じ並びに戻る) ゴリラシャッフルの周期は272で,そこそこ長い. ところで,デッキの中のある特定のカードの動きを追うとすると,ある位置からある位置への移動法は決定的であるため, デッキサイズnに対して,特定のカードの位置の周期は高々nのはずである. ゴリラシャッフルの周期が36よりはるかに大きい272であるのは,異なる周期のグループに分かれるようなシャッフル法だからである. ここで突然グループという話が出てきたが,位置Iのカードが位置Jに移るシャッフルの場合, もともと位置Jにあったカードともともと位置Iにあったカードは,全く同じ経路をたどって一周することになる. そのような同じ経路に属する位置の集合をここではグループとよんだ.グループのサイズと周期は同じ値になる. ゴリラシャッフルの場合,周期1,2,16,17のグループがそれぞれ1つずつある. (最初にシャッフル法を示したとき,wの位置が動いていないことや,2とfが入れ替わっているだけの点に気づいただろうか) したがって,全体の周期は1,2,16,17の最小公倍数である272となる. となると,36枚のデッキを混ぜる決定的なシャッフルの中で,全体の周期が最も長いものとなると, 例えば5を除く素数を下から順に使った周期2,3,7,11,13の5つのグループからなる周期6006のシャッフルだろうか. これが最長になるかについては証明が必要だが,ちょっと考えた範囲ではこれより長いのはできなそうだ. ただし,このようなシャッフルは全体の周期は長いものの,部分的に見ると周期2のグループは交互に入れ替わるだけであるし, そもそもグループを超越した移動は絶対に起こらないという問題があるため,複数のシャッフル法を組み合わせて用いると良い. が,組み合わせ方を決定的に決めると,一連の「合成シャッフル」はひとつの決定的なシャッフルとみなせる点には注意が必要である. できれば素早く拡散できる決定的なシャッフルと,真乱数に近い要素を含むシャッフルを組みわせて用いるのが良いだろう. ちなみに,単に周期が6006であるだけの決定的シャッフルを作るのは簡単である. 1 まず,上から順に2,3,7,11,13枚ずつとって5つのグループに分ける. 2 次に,各グループの一番上のカードを一番下に挿入する. 3 グループの順番を変えないように一つの山に戻す. 以上. これを応用して,11,12,13枚くらいのサイズが互いに素になるような山に分けて, 各山でヒンズーシャッフルを行い,一つの山に戻したあと,カットする. くらいをやるとそこそこのコストでそこそこ混ざるかな. [1] https://twitter.com/pawwn/status/621878062133579776 [2] http://www.moguragames.com/entry/goritia-2/ 2015/8/6 Python 最近Pythonを使っている.拡張性の高さを目指した設計思想を感じるようになり,以前より印象が良くなっている. 特にすばらしいのはnumpyの存在である.その高速性と,ドット積とelement-wiseな(積を含む)演算を自然に記述でき,大変好ましい. True-False型インデックスによるアクセスや, (リストではできない,RubyのArray#values_atのような)複数インデックスのアクセスも可能である. もちろん行列演算に関してはMatlabには劣るものの,入手しやすさを含めた総合評価はかなり高くつけるべきだろう. 他方,不慣れな部分を含め,不満なところも多い. 最も不満なところは,2系と3系がいまだに混在しているところである. (これらは,Rubyでいう1.8系と1.9系程度にギャップがある) もちろん,一部のアプリケーションが古いバージョンのみに対応する状態が続くというのはよい. ところが,初めてPythonに触れようというものがpythonをインストールしようとするとき, 2.7を用いるケースが多そうだという現状がある. これは,例えばAnacondaがデフォルトで2.7に対応した方のダウンロードリンクを示すことや, Cygwinにおいて,2.7のコマンド名がpythonである一方,3.4のコマンド名がpython3であることからの推察である. このような移行圧力の弱さは,両系統がともに広く使われる過渡期の無用な長期化を招くことになろう. その結果,初学者(である私)にとっての情報検索性の低下などの悪影響が引き起こされていると感じられる. 次いで,日本語化された公式ドキュメントのひどさである. __init__の説明などをはじめとした翻訳の酷さはもとより,原文へのリンクの不在が著しい閲読性の悪さを招いている. google検索から公式ドキュメントに到達したあと,原文へたどり着くのに多くのステップを踏む必要がある. また,ドキュメントの各ページに対応バージョンが明示されていないため, 2系について書かれたものなのか,3系について書かれたものなのか,判断するのに時間がかかる. 次に,ようやく言語仕様に触れることになるが,Pythonの最も目立つ特徴であるオフサイドルールである. これは,まったく個人的な話ではあるが,次の二つの理由により,好みに合わない. 第一は,空行を利用しにくいところである. Pythonでは空行は構文上は無視されることになっている. しかし,オフサイドルールの言語において空行を挿入すると,視覚的にブロックの範囲が不明瞭になり,挿入しにくい. 他方,空行の挿入によって可読性が向上するケースが存在し,そのような場合に, 空行の有無のいずれが相対的に優れているか,大変苦しい選択を迫られることになる. 第二は,printデバッグのやりにくさである. 従来,私はいわゆるprintfデバッグを行う際は,適当な行にインデントなしでprintf(に相当する)関数を挿入してデバッグしていた. これにより,複数個所にデバッグ用のprintf関数を挿入した場合に,デバッグ後のprintf関数の除去が容易であった. しかし,Pythonで同様のことを行うと,ブロック構造が崩れてしまうため,できない. インデントをそろえてprint関数を挿入すると,デバッグ後の除去に多少の面倒を生じる. ファイルそのものがモジュールとなり,名前空間を形成する点は,メリットも認められるものの,違和感は大きい. メリットとしては,視覚的に最大級の区切りであるファイルを言語仕様上の区切りとするので,わかりやすいことである. 他方,import文において,ファイル名(パス名)と識別子(モジュール(が代入された変数)名)が同一視されることや, モジュール名とそのモジュールの核となるクラス名が同一である場合の冗長さなどは気になる. クラス名を大文字で始める慣習がない点は,個人的には大きな違和感を覚える. その他は比較的些末であるが,インスタンスメソッドの定義において,selfを仮引数で明示しなければならないのが気に食わない (もちろん,あくまでメソッドの実体は関数であるなどの理由によることはわかっている)とか, 対話形式の際にexitと打って怒られるのがむかつくとか,コロン忘れで怒られるとなぜか腹が立つなどがある. Rubyとの比較でいうと,__END__やcase文の不在がなかなか不満ではある. 2015/8/28 エタン・ブタンの更新 長い間放置してきたが,ようやく重い腰を上げ,Ruby 2.2 への対応に踏み切った. 従来使われていた Ruby 1.8 ではもはや動かないので注意されたい. また,ひと通りのテストはしたものの,一からの書き直しとなったため,細かいバグが残っている可能性が高い. もし見つかった場合はメールや掲示板などで報告いただけるとありがたい. また,今回の書き直しのテストの過程で,昔のブタンにバグが存在していたことが判明した. 毒による死が発生し,かつオーバーキルジャッジが生じたときのみ影響するものだったため,今まで見逃されていたのだ. ブタンオンラインは今回の新ブタンではなく,Ruby 1.8 の旧ブタンが使われているが,このバグは解消した. 2015/9/14 エタン・ブタンの更新 ちょっとしたバグフィックスと,ソートをするかしないか選択するための引数を League.do_it, League.to_html, Prophecy.do_it, Prophecy.to_html に追加した. 2015/10/6 スプラトゥーン使用ブキの変遷 ・カーボンローラー やべえさんちで主に使用したブキ. 高い機動性と低いエイム依存性を持ち,敵陣の敵密度の低い領域を暴れまわるのに向く. WiiU購入後もランクが上がるまでスプラローラー,スプラローラーコラボで我慢し,しばらくのメインブキであった. ・プロモデラーRG 流石にローラーばかり使うのもどうかと思い, シューターにも手を出そうと考えたときに手を出したブキ. エイム力は永遠の課題であるため,高い連射性とトルネードを考慮してこれを選択. その結果,ドハマリし,かなり長い間のメインブキとなった. ナワバリバトルにおいて,トルネードが溜まってはスタート地点に戻ってレーダーを見ながら撃ち, それ以外の時はできるだけ敵が少なく,塗る領域のあるところを転々とする戦いを続けた. トラップも使い所がわかりやすく,非常に趣味の合うブキである. ・いろいろ プロモデラーRGを使い続け,金も十分溜まってきたので,すべてのブキを興味を向く順に購入し,試していった. まず気づいたのは,チャージャーはどうあっても使いこなせないということだった. 他方,意外と気に入ったのがジェットスイーパーである. チャージャーに比べると横にも塗られるため,当てられずとも,牽制の効果が高い. チャージャーでも牽制はできるが,覚悟を決めて突進される確率はチャージャーのほうが高いと感じる. また,この長射程ブキで通路を塗るときの,狭い屋内で槍を振るう不便な感じが面白い. バケットスロッシャーおよび後に登場したヒッセンはカーボンローラーに近く,悪くない. フデ系では最軽量のパブロがもっとも好みであった. ブラスターの中ではホットブラスターカスタムが好ましく,それなりに使用した. 死角への攻撃が可能で,塗り性能もさほど悪くないところがよい. その他のブラスターは癖が強く,使いこなすのは難しそうだ. やや意外なことに,バレルスピナーは悪くなかった. シューターはプロモデラーRGに似ているN-ZAP89と,前述のジェットスイーパーのほか, チェイスボム使いとして.52ガロンデコは嫌いではない. .96ガロン/デコは強いとは思うが,私が使うのは難しかった. ・ダイナモローラー/テスラ プロモデラーRGは火力が低く,私の腕では奇襲を仕掛けたにも関わらず,返り討ちに遭うケースが増えてきた. 基本的に戦闘を避けるべきブキであることは確かだが, ルールに強制されてプレイヤー密度の上がるガチマッチで戦うのは難しい. (そういうこともあって,ガチを避けてきたのも事実ではあるが) そこで代替案を模索した結果,見出されたのがダイナモローラーであった. 広範囲を一撃必殺の威力で攻撃できるダイナモローラーならば,私でも扱える. 機動力を活かして縦横に駆け巡る従前の戦い方はできなくなったが, 後方から味方の足元を塗りつつ牽制し,時に敵を葬る戦い方は思いの外,性に合っていた. ナワバリでは大好きなトルネードのテスラ,ガチではうまく使えないので無印を使用している. 悩みはスプリンクラーもスプラッシュボムもうまく使えていないところ. あとは自陣の塗られていない通路などを塗るのが好きなのだが,ダイナモでそれをやるのは難しいところ. ・サブウェポン これまでメインを中心とした3点セットの話をしてきたが,サブとスペシャルの話もしよう.まずはサブ. 実のところ,どのサブウェポンも全くと言っていいほど使いこなせていない. その中では,使い所を選ばないトラップが好みである. 敵の使うクイックボム,キューバンボムには苦労させられるが,自分が使うのは難しい. 基本的にサブウェポンはインク消費が激しく,インク管理がなっていないところが第一の問題ではある. また,投げるのに慣れていないため,ポムラッシュも難しい. いずれにせよ,投げの練習はしたほうがいいのかもしれないが……. ・スペシャルウェポン スペシャルでは,適当に撃ってるだけでそれなりに役に立つトルネードが好きである. ただ,最近は隠れ方に難があり,構えたところで撃ち殺されることが増えてきた気がする. また,ジャイロを使用していないため,プロモデラーRG使用時に敵の目前でトルネードが暴発することも出てきて, これもダイナモへの移行を考える一つのきっかけとなった. ダイナモではエイム時に手に力が入ってしまうということが少なく,暴発はしにくい. スーパーセンサーは使って損をすることが全くなく,単純にインク回復手段として利用してもよいため,便利である. その他のスペシャルウェポンは,残念ながら全く使えていないといってよい. 特に狙っても外すスーパーショットが難しい.カーボンローラーから離れる原因の一つでもあった. バリアとダイオウイカは効果時間の管理が必要で,なかなか慣れない. そもそもからして,アクションゲームでいろいろ使い分けるというのが苦手なので, サブとスペシャルは頭を使わないものが好きなのだ. スプラトゥーンからは離れるが,EveryExtendが好きだとか,アイテムのあるレースゲームは嫌いで, ウェーブレースのトリックすら苦手だとかいうのもその辺が関係している. ジャンプなどの副アクションを除く,攻撃などの主アクションボタンが2つ以上あるゲームは苦手だ. 簡潔に定義できていない主アクションと副アクションというのが伝わるのかわからないが, スプラトゥーンではR(サブ)とZR(メイン)が主アクションでそれ以外が副アクション. F-ZERO GX ではブースターが主アクションでアクセルとスライドが副アクション. サイドアタックとスピンアタックはタイムアタックでは(自分ルールで)使わないことになっているので無視. Knight of Knights では両手の攻撃が主アクションなので,レジストコンボは良いが,実プレイは苦手(レジスト頼り). Brave Gear では攻撃とスキル切り替えが主アクションなので苦手. 東方妖々夢ではボムが主アクションで低速移動が副アクション.ショットは打ちっぱなしなので非アクション. ウィニングイレブンプレーメーカーではB(パス)が主アクションでA(ドリブル)などが副アクション. シュートも主アクションだが,ヌンチャク振りなのでなんとかなる. 基本的に,移動を補助するものが副アクションになる.副アクションはある程度種類があってもなんとかなるが, もちろん多すぎるとやっぱりダメ.どこまで副アクションになるのかの線引きは不明. 例えばジャンプでも,(スプラトゥーンミニゲームの)イカジャンプや1080SSでは主アクションである. スプラトゥーンのスーパージャンプは主寄りだが,頻度は少ないし敵の前で使っても逃げきれないのでギリギリでアリか. 主2つがダメというのも厳密な話ではないが,1より大きければ基本ダメという感はある. ちなみに加速度センサー操作であるが,ぶん回せばいいプレーメーカーのシュートや振りあげるだけのオフサイドトラップは良いが, 精度の必要なスプラトゥーンのカメラだとか,エキサイトトラックだとかはちょっと……. Wiiリモコンのポイント操作は下手くそながら不快ではないが,加速度センサーものはアレ. コロコロカービィはプレイしたことはないが,多分苦手だろうなあ. そんなこんなでとりとめもなく終了. 2015/12/8 Rubyリファレンスマニュアルについて Ruby の拡張ライブラリを書いているのだが,リファレンスマニュアルの C API 一覧 [1] が結構ひどいことに気づく. void rb_alias(VALUE klass, ID name, ID def) [2] は,「クラス klass に定義されたメソッド name の 本体を実体とする新しいメソッド def を定義します」 とあるが,name と def の関係は逆で,rb_define_alias() や Ruby 上の alias と同様,新しい名前,元の名前の順である. rb_rescue() [3] では,「r_proc(data2) を実行します」とあるが,実際には r_proc(data2, 補足した例外オブジェクト) が実行される. 補足した例外を使いたいけど受け取るにはどうすればいいのかと悩んだ末,rb_rescue() の定義コードを読んだらこの事実が判明した. ちなみにCの引数処理の関係上,実引数より仮引数が多いのは問題であるが,仮引数より実引数が多い分にはそれが読まれないだけなので動くことは動く. また,rb_obj_methods() [4] のように,static だから外からは呼べない関数が載っている. まあ載っている事自体は絶対ダメではないのだが,一覧ページ [1] では static であるかどうかと,obsolete であるかどうかは確認できるべきであろう. C 拡張とは関係ないが,Array#== に関する少しおもしろい事実がわかった. Array#==(other) は,self と other の各要素を == で比較し,全要素が等しければ true を,さもなくば false を返すのであるが, other が Array のインスタンスではない場合はちょっと変わった挙動をする. 問答無用に false,ではなく「other.respond_to?(:to_ary) であれば !!(other==self) を返す」のである. (Array#== の具体的な定義は array.c の rb_ary_equal() にある) つまり,インスタンスメソッド to_ary を定義したクラスは,== の引数が Array オブジェクトの場合の処理を適切に行う必要があるのである. まあ to_ary を定義してあるクラスにとって Array#== がどうなって欲しいかはそのクラスに依存するので, 勝手に self==other.to_ary とせずに, other==self を利用するのは良いが,知らなかったことなので少し驚いた. というかこれ絶対リファレンスマニュアルに明記すべき挙動だぞ. [1] http://docs.ruby-lang.org/ja/2.2.0/function/index.html [2] http://docs.ruby-lang.org/ja/2.2.0/function/rb_alias.html [3] http://docs.ruby-lang.org/ja/2.2.0/function/rb_rescue.html [4] http://docs.ruby-lang.org/ja/2.2.0/function/rb_obj_methods.html 2015/12/16 Cプリプロセッサによるブロック風引数付きマクロ Cのプリブロセッサにおけるマクロは単純な文字列置換操作であることから, Cの関数の引数にはならない,ブロック(の中身)自体などを引数にすることができる. 例えば,Rubyの n.times{|i| BLOCK } のようなことを, #define TIMES(n, i, BLOCK) { int i; for (i=0; iensure_list; \ th->ensure_list = &ensure_list; \ PUSH_TAG(); \ if ((state = EXEC_TAG()) == 0) { \ statement \ } \ POP_TAG(); \ errinfo = th->errinfo; \ th->ensure_list=ensure_list.next; \ (*ensure_list.entry.e_proc)(ensure_list.entry.data2); \ th->errinfo = errinfo; \ if (state) JUMP_TAG(state); \ } こんな感じです.ただ,このままだと rb_thread_t やら GET_THREAD やらの定義がなくてコンパイルできないので, ruby のソースコードから vm_core.h と eval_intern.h およびそれらが #include しているヘッダファイルを #include します. ちなみに GC_ESCAPE(bproc(data1);) は rb_ensure をそのまま使う場合の VALUE old = rb_gc_disable(); rb_ensure( bproc, data1, recover_gc_enableness, old ); とほぼ同じです. 2015/12/26 エタンバグ修正 OrderedTa#league_sortがうまく動かなかったバグを修正 2015/12/29 ヘプタン公開 マーガレット・ヴォイド処理用のRubyライブラリ,ヘプタンをようやく公開しました. 検証が十分とは思えないため,バグを含んでいる可能性があります. バグ発見の際にはぜひご連絡をお願い致します. 2015/12/31 バグ修正 エタン及びヘプタンの細かいバグを修正.