ガチャ、オートマトン、オイラー積分 - Analytic Combinatoricsが面白い

Analytic Combinatoricsがめちゃくちゃ面白い。場合の数という離散的なものを数えるのに、連続的世界から生まれた解析学の知見を用いる分野だ。階乗をガンマ関数で表示するだとかいうレベルではなく、マクローリン展開の係数を調べることで場合の数を知るようなことをしている。

オートマトン

ハマった発端は「オートマトン理論再考」(新屋, 2017 *1 )というサーベイ論文。有限状態オートマトンを定めると、そのグラフの形から直接「a_i=出力文字列のうちi文字のもの」のa_i係数とする母関数が構成でき、それをマクローリン展開すると、i文字となる出力の場合の数が直ちにわかるという内容を紹介していた。この結果は文脈自由言語にも拡張でき、生成規則から母関数が機械的に計算でき、その展開係数がi文字の場合の数になっているという。場合の数を数えるのになんとマクローリン展開!一体どういうことなのか。

例えば、[1]中では「正しく対応する括弧の文字列」の集合で構成されるDyck言語

 \displaystyle
  \xrightarrow{R} :
      S = \varepsilon \mid (S)S

を取り上げていた。この規則は、例えば

 \displaystyle
  \varepsilon,\  (  ) ,\   (  (  )  ) ,\   (  )  (  ) ,\   (  (  (  )  )  ) ,\  (  (  )  (  )  ) ,\   (  (  )  )  (  ) ,\   (  )  (  (  )  ) ,\   (  )  (  )  (  ) ,\  \cdots

のような文字列を生成する(\varepsilonは空文字列。また、生成規則中の括弧は文字を表すことに注意)。

さて、上記を見ると、Dyck言語では2文字の場合は1通り、4文字の場合は2通り、6文字の場合は5通り存在する。では、一般の文字数では何通りあるのか?普通、この問に答えるには、漸化式や場合分けなどが沢山必要だろうというイメージがあった。しかし、なんと文脈自由言語の生成規則を機械的に母関数化する操作\Xiを用いて、

 \displaystyle
  \Xi (\xrightarrow{R}):
      S = 1 + zSzS

となり、母関数Sに関する方程式

 {\displaystyle
  z^{2} S - S + 1 = 0, \, \, i.e. \, \, S = \frac{1 \pm \sqrt{1-4z^{2}}}{2z^{2}}
}

がわかり、さらにそれをマクローリン展開すると

 \displaystyle
  S = \sum_{i=0}^\infty C_{i}z^{2i}

と、カタラン数 *2 C_{i}で書けることから、Dyck言語のうち2i文字の場合はC_{i}通りであることがわかるのである。

これを初めて見た時の感想は「あ・・・ありのまま今起こったことを話すぜ・・・!!」だった。あの場合の数の細かい操作が、全て解析的操作に押し込められていた。離散的なものを解析するのに、解析学の知見を使う系の物が好きな上に、複雑な対象が代数的に、かつ機械的に処理できるようなものが昔からかなり好きなのだけど、これはもう驚きの連続で見ているだけで幸せになれた。

一番感動したのは、Kleene Starが母関数の無限等比級数を取る操作に等しいことだ。a^{*}という正規表現にマッチする文字列において、i文字のものは常に1通りだ。したがって、a^{*}の母関数は

 \displaystyle
  \Xi[a^*] = 1 + 1 \cdot z + 1 \cdot z^{2} + \cdots = \frac 1 {1-z}

となることがわかる。

しかし、これだけでは終わらない。なんとこれが一般の場合に拡張できるのである!(a|ba)^{*}という正規表現があったとき(ここではDyck言語における括弧とは意味が異なり、括弧は文字としてカウントしていないことに注意)、なんと

 \displaystyle
  \Xi[(a|ba)^{*}] = \frac{1}{1 - \Xi[(a|ba)]} = \frac{1}{1 - (z+z^{2})}

のようになるのだ。このマクローリン展開の一般項は、なんとフィボナッチ数列になることが、[1]の中で触れられている。つまり、正規表現(a|ba)^*にマッチする文字のうち、i文字のものはi番目のフィボナッチ数通りあるのだ。

また、[1]中では他にも正規言語\iff母関数が有理関数、文脈自由言語\iff母関数が代数関数となることから、言語の母関数の極が無限にあればそれは文脈自由言語や正規言語ではないことがわかるなどの結果が紹介されていた。これは、正規表現でマッチしうる場合の数の性質と、文脈自由言語の性質が、解析学的には有理関数と代数関数の差として表現できるという、もうこれ哲学じゃん!!という内容だった。他にも、まだ読めていないがいわゆる無限の猿定理のフォーマルな証明などを紹介している。

ガチャの数

続いて見かけたのはアイテムコンプに必要なガチャの回数の期待値を厳密に計算する方法 (sxarp, 2017, ブログ記事)。ここではCoupon Collector's Problem を一般化し、異なる確率で得られるクーポンを集めるまでの回数の期待値を、マルコフ連鎖を用いて計算している。

この問題のモデルは重み付き有限状態オートマトンで書けるので、母関数法を用いてもっと簡単に解けないかと論文を探していたら、Math Overflowの質問 から Flajolet, et al., 1992 *3 を見つけた。そこには正規言語の話など見慣れた話題が載っていた。この論文の定理4.1が、問題の期待値を求める式を与えている。

更に、この定理の元となる定理3.1を見ると、どうもKlamkin and Newman, 1967 *4 の Extensions of the Birthday Surprise という論文が出典らしい。

この論文では、所望の期待値を求めるために、なんと道具がガンマ関数の定義式であるオイラー積分にまで発展しているのだ!!

 \displaystyle
  \Gamma(x) = \int_0^\infty t^{z-1}e^{-t}dt

これが、階乗を連続的に扱うためにガンマ関数で表示する、とかいう生半可な使い方ではないのだ。これをどう使うかというと、ある母関数を考えるのに、それに\frac{t^{N}}{N!}をかけた補助的な関数を考え、色々いじったあとに、\frac{t^{N}}{N!}を消去するのにe^{-t}倍してオイラー積分を行うのだ。「え、ここでそれするの!?」と、久々に感動した。最初多項式の話をしていたと思ったら、みるみるうちに話が解析的になっていき、最後にはガンマ関数が出てきて度肝を抜かれた。

この感動は是非元論文を読んで体験していただきたい。4ページで、アイデアもわかりやすいので、非常に読みやすい。

Analytic Combinatoricsスライド

もっとKlamkin and Newmanのような結果を読みたい!この分野は、どうもAnalytic Combinatoricsという名前がついているらしい。そこで、Analytic Combinatoricsで検索すると、Robert Sedgewick のFrom Analysis of Algorithms to Analytic Combinatorics - a journey with Philippe Flajolet *5 という発表スライドを見つけた。スライドを見ると "This talk is dedicated to the memory of Philippe Flajolet" とあり、更に "Philippe Flajolet 1948-2011" とあった。どこかで見覚えのある名前だなと思ったら、なんと [3] の著者だった!!一気に親しみを覚えると同時に少し寂しくなってしまった。どんな方だったのだろうか。

このスライドでは、PSET, MSETなどの生成規則に関する演算と、その母関数表示上での演算の対応規則が書かれており、Nノードある二分木の数え上げなどが行われていた。Kleene Starが1/(1-z)と等価、を更に推し進めたような規則が沢山書いてあるのだ。

中でも心を打たれたのが、 "If you can specify it, you can analyze it" という格言だった。これは、正に「オートマトン理論再考」[1]を読んだ時の感動の源泉そのものだった。オートマトンのグラフ構造や文脈自由言語の生成規則からほぼ直接的に母関数を構成でき、更にその展開係数そのものが場合の数だという、この直接的な関係。機械的・機能的美しさと神秘を兼ね備えた感動をそのまま言い表していて、スライドの著者にとても同意した。

更に、このスライドでは Donald Knuth の The Art of Computer Programming など、Knuth に関して重点的に触れていたり、世界初の機械式コンピュータ "Difference Engine" をデザインした「コンピュータの父」Charles Babbageの言葉を引用していた:

"As soon as an Analytic Engine exists, it will necessarily guide the future course of the science. Whenever any result is sought by its aid, the question will arise - By what course of calculation can these results be arrived at by the machine in the shortest time?" - Charles Babbage, as quoted by R. Sedgewick [4]

なぜKnuthやBabbageのこの言葉を引用していたかというと、スライドによるとAnalytic Combinatoricsによる数え上げによってアルゴリズムの計算クラスを証明したりするらしい。このような美しい理論に実用的な使い道があるとますます嬉しくなる。

Analytic Combinatorics本

そして更に検索していると、Flajolet and Sedgewickの本 Analytic Combinatoricsを発見した。こちらは、826ページにも亘るにもかかわらずオンラインで無料で全ページ公開されている。

p.2 によると、このようなAnalytic Combinatoricsの流れは、1881年Désiré André というフランスの数学者が、隣接する位の数字の大小が毎度交代する整数の場合の数が、\tan xマクローリン展開の係数になっていることを発見したことから始まったという。

更にこの本のp.35では、凸多角形の三角形分割の場合の数がカタラン数で与えられることの直感的説明を紹介している。Dyck言語もカタラン数で与えられるため、三角形分割もDyck言語と同じような規則が存在するはずであると思ってこの本を読む前までしばらく悩んでいたのだが、このような複雑な構造をここまで直感的に説明できるものなのかと思った。

どんどん読み進めていくと、そもそもこの分野を調べるきっかけとなったオートマトンの話などが載っており、目が幸せになりつつ、現在この本を読み進めている途中である。

Babbageから現代まで

先程出てきたBabbageが設計したDifference EngineのレプリカはMountain ViewのComputer History Museumに展示 *6 されている。Charles Babbageは、Wikipediaによると1791-1871年を生きており、Analytic Combinatoricsの幕開けである1881年は彼の没後となる。彼のDifference Engineは、実はBabbageの生前は実装することができず、2002年に初めて実装されたとある。(つまり、Difference Engineはバグが無かったことが、100年以上越しに示されたことになる!)以前博物館を訪れた際そのDifference Engineのレプリカの一つを見たが、改めて、そんな「コンピュータの父」の「アルゴリズムを最小時間で実行することが興味の対象となるだろう」という予想、そしてDifference Engineの黎明期的雰囲気から、Analytic Combinatoricsという大変美しい理論によってアルゴリズムの計算量が測られる現代までの、風が吹くような勢いの変遷を見て、計算機科学に待ち受けるまだ見ぬ面白さにますます大きな期待を僕は寄せている。

CPU対戦型の高難易度版ポケモンWordle「後出しポケモンWordle」を作りました

後出しポケモンWordle
後出しポケモンWordle

qntmさん作のWordleのadversarial版 Absurdleから着想を得て、 ポケモンWordleのCPUとの対戦型の高難易度版「後出しポケモンWordle」を作りました。

このゲームはCPUとの対戦型ゲームになっていて、なるべく正解にたどり着かせたくないCPUと対戦するというルールになっています。 どのような対戦要素があるかというと、通常のポケモンWordleでは予めポケモンの名前が決まっていますが、相手はプレイヤーの 予想を見た上で、 これまでのパネルの結果と 矛盾しない範囲で次々と正解を変え、なるべく少ない情報しか出さないようにパネルの結果を出してきます。 すでに表示された回答やパネルの結果が変わることはありません。

あなたはCPUの戦略を乗り越え、正解に辿り着くことができるでしょうか?

後出しポケモンWordleはこちらで遊ぶことができます:

woodrush.github.io

原作のWordleおよびポケモンWordleと違って、 好きな回数だけポケモンの名前を予想することができます。 正解候補のポケモンはソード・シールドまでに登場する5文字のポケモン、 予想として使えるのはソード・シールドまでに登場する5文字以内の全てのポケモンです。

モード

更に難易度を上げるためのモードが2つあります。

  • ハードモード
    • これまでに得られたヒントに合致するポケモンのみを回答に使用することができるモードです。
  • ウルトラハードモード
    • ウルトラハードモードでは、最初にお題のポケモンがランダムで提示され、 お題のポケモンが正解となるように回答を行います。 お題のポケモンが正解候補からいなくなってしまうとゲーム終了となります。

ポケモンWordle関連記事

平均情報量(エントロピー)最大化に基づいてポケモンWordleの有効な初手を考察する記事を公開しています。

woodrush.hatenablog.com

また、ソースコードを下記のGitHubレポジトリにて公開しています。

github.com

Credits

このゲームはqntmさん作のWordleのadversarial版 Absurdleから着想を得ています。 プログラムはHikaru Ikuta (@woodrush) が書いています。

ポケモン名前当てゲーム「ポケモンWordle」「Pokedle」の初手はどのポケモンが強い?平均情報量最大化による攻略方法と有効初手考察

ポケモン版Wordle、ポケモンWordleのスクリーンショット
ポケモン版Wordle、ポケモンWordleのスクリーンショット

この記事ではポケモン名前当てゲーム「Pokedle」「ポケモンWordle」の有効な初手は何か?という考察を行います。

ポケモン名前当てゲーム「Pokedle」「ポケモンWordle」

つい先日、ポケモン名前当てゲーム「Pokedle」が登場しました。

pokedle.vercel.app

Pokedleはちゅうさん*1が制作*2しているゲームで、9回以内で日本語で5文字のポケモンの名前を当てるというゲームになっています。 このゲームは後に説明するようにWordleというゲームが原作となっています。

このゲームが面白いのは、ただ毎回名前をランダムに当てるのではなく、回答する度にどの文字が正解に近かったのかのヒントが毎回もらえるということです。つまり回答する度にヒントが増え、そのヒントを元に名前を当てる謎解きのようになっていて、いかに上手いポケモンを回答し、良いヒントを引き出せるかがポイントになっています。

そしてその後、ポケモンWordleというゲームが登場しました。

ポケモンWordleはやどさん*3が制作しているゲームで、こちらも10回以内で日本語で5文字のポケモンの名前を当てるというゲームになっています。こちらでは予想回数が10回になっている他、4文字以下のポケモンも予想として使用可能で、更に何回でも挑戦可能なエンドレスモードも遊ぶことができます。

原作:Wordle

このゲームはWordleというゲームが原作になっています。皆さんは最近下記のようなツイートを見たことがあるのではないでしょうか。

この何やら謎な四角のツイートは、最近流行っているWordle *4というゲームの結果ツイートです。

WordleはJosh Wardleさん*5が個人制作している単語当てゲームで、5文字の英単語を6回以内で当てるという内容になっています。 ただ単語を当てるのではなく、単語を予想する度に下記のような情報を得ることができます。

  • 🟩:予想した文字が正しい場所に配置されている。
  • 🟨:予想した文字は単語中に含まれているが、正しい場所に配置されていない。
  • ⬜:予想した文字は単語中のどこにも含まれていない。

アルファベットは全部で26文字あり、5文字の単語を6回予想できるので、上手く予想すれば6回以内でクリアできるようになっている絶妙なゲームバランスになっているというわけです。隠された単語は毎日0時に変わるようになっており、毎晩0時になると多くのWordleの結果ツイートを目にする機会が増えています。

Wordleは個人制作のゲームでありながら、New York Timesに取り上げられたり*6Googleで「Wordle」と検索すると専用のロゴ表示が出るようになるなど、大きな盛り上がりを見せています。

このWordleのポケモン版が「Pokedle」そして「ポケモンWordle」です。

ちなみに私の初回のPokedleの結果はこのような感じ*7で、ポケモンWordleの結果はこのような感じ*8でした。 これまでのポケモン人生の全てが試されているような感じがして、ポケモンマスター魂が燃えるゲームです。

問題設定

さて、ゲームがあるというのなら、一番上手くクリアする方法は何かが気になるというものです。 この記事では、初手に選ぶべき最適なポケモンはどのようなポケモンを考察します。

「最適、最適」と言われたら、何が評価関数なのかを明確にするのが世の情けです。この記事では下記のような問題を考えます。

  • 問題: ポケモンWordle/Pokedleにおいて、全ての正解候補ポケモンがランダムに出題される時、その後の平均の予想回数を最小化すると思われる最初の一手のポケモンは何か?

ただし、この記事で用いるエントロピー最大化の方法はヒューリスティクスに基づく方法なので、真の最適解は得られません。しかし、最適解に近いと思われる近似解は得ることができます。

目次

番外編先行研究 - その日つぶやかれたWordleのパネル列からその日の単語を一発で推定する方法

この記事の趣旨とは異なるのですが、原作であるWordleに関して面白い先行研究があるので紹介します。

なんとBen Hamnerさんはその日につぶやかれたWordleの結果からその日の単語を一発で推定する方法を作り公開しています。 この方法では、twitterからその日のパネルの情報を載せた冒頭で紹介したようなツイートを収集し、その情報を使ってその日の単語を推定します。

https://www.kaggle.com/benhamner/wordle-1-6/notebook

こちらはKaggleで公開されているだけに深層学習に基づいているのかと思いきや、 なんとWordleの全正解候補単語と使用可能単語を用いてWordleのセッションのシミュレーションを多数行い、 正解候補に対するパネルのパターンの出現頻度を単語ごとに計測し、パネルの全組み合わせの頻度のベクトルを特徴として 最近傍探索を含む3つの指標を用いてその日の単語を推定しています。

ポケモンWordleの有効初手の考察 - 準備

以下ではポケモンWordleの初手を考えていきます。 この記事ではエントロピーの最大化による方法で有効な初手を考えます。

この記事で紹介するチャートは平均回答数を真に最少にする最適なものではなく、他のポケモンが真に最適な可能性があります。 しかし、この記事で紹介する方法を参考にすると、「その後の分割を均等にするようなポケモンを選ぶのが概ね良い」というポケモンWordleを攻略する上での一つの方針を得ることができます。

データの収集

まずポケモンWordleの説明によると、下記のようなルールが記されています。

  • お題のポケモンは必ず5文字です
  • 回答には5文字以下のポケモンも入力することができます
  • 回答には剣盾までのポケモンが使えます

ポケモンWordle https://wordle.mega-yadoran.jp/ より引用)

そこで全国ポケモン図鑑順のポケモン一覧 - Wikipedia から該当するポケモンの名前を収集します。回答に使えるポケモンと、正解候補のポケモンの2つのデータを収集します。

また、ニドラン♂・♀、ポリゴン2・Zに必要な「♂・♀・2・Z」がキーボードに存在せず入力できないため、これらのポケモンは除外します。

こうして収集したデータを見ると、正解候補ポケモンは511匹、回答可能ポケモンは847匹となりました。正解候補ポケモンはたまたま2^{9}-1匹になっていますが、今回はその事実は特に使いません。

ポケモンWordleにおけるパネルのフィードバックのルール

ポケモンWordleをプレーしてみた結果、パネルのフィードバックのルールはWordle同様下記のようになっていると思われます。

  • まず回答と正解の両方において位置と内容が一致している文字を全て探し、それらを緑色のパネルとする。
  • 次に位置は合っていないが正解の名前中に含まれている文字を全て探し、それらを黄色のパネルとする。
    • ただし、同じ文字が重複している場合は、緑色+黄色のパネルの枚数が正解単語におけるその文字の文字数以下になるように黄色のパネルを表示する。
    • たとえば「ああいうえ」が正解で「あおああお」と回答した場合、結果は「緑灰黄灰灰」となる。回答に「あ」は3つ含まれているが、正解には「あ」が2つしか含まれていないので、緑色+黄色のパネルの枚数は2枚となっている。
  • 名前中に含まれていないパネルは全て灰色のパネルとする。

この記事では上記のルールに従っていると仮定して初手を考察します。

分割の質

さて、この記事では以下のような方法によって初手を考察していきます。 ここでは回答の結果得られるパネル列をフィードバックのパネルの列と呼ぶことにします。

  1. 正解候補ポケモンと使用可能ポケモンの集合をそれぞれ用意する。
  2. 全使用可能ポケモンでの回答をシミュレーションする。
  3. フィードバックのパネル列によって正解候補ポケモンは分割されるが、 最も質が良い分割 を与えてくれる回答を1匹選ぶ。このポケモンを有効な初手とする。

さて、ここで問題になるのが「最も質が良い分割」とは何か、つまり「分割の質」を測るにはどのようにすれば良いのかという問題です。

まず最初に考えられるのは得られるフィードバックの種類の多さです。回答の結果得られるパネル列の種類が多い方が、多くの場合分けが生じるためより良く絞り込めると考えられます。しかし、例えば同じ4分割でも、(508匹、1匹、1匹、1匹)という分割より(128匹、128匹、128匹、127匹)という分割の方が一般的に性能が良いと言えます。なぜならば、一発で1匹に絞り込める場合を引いたなら良いのですが、508匹のフィードバックを引き当てた場合、ほぼ絞り込んでいないのと同じになってしまうからです。これに対して後者の分割では、どのようなフィードバックが得られた場合でも128匹程度に絞り込めることが確実なので、絞り込みの性能、つまり分割の質は高いと言えます。

分割の質を測るエントロピー

このような意味で分割の質を測るのにエントロピーを使うことができます。以下ではその理由を説明します。

まず、今回興味があるのは全ポケモンの平均回答数を最小化することです。そこで、ある状態から正解に至るまでの回答数の見積もりを計算する方法を考えます。

そのために、次のような仮定を置きます。

  • このゲームでは回答を行うごとに候補数が p \lt 1倍される。

このように考えると、例えば現在の正解候補数が M匹だった場合は、回答するごとに候補数が p倍になっていくので、 M匹になった時点からの残りの手番数の見積もり nは残りの候補数が1となる時のnであるため、

 \displaystyle
\begin{align}
p^n M &= 1 \\
% n \log p &= \log \frac 1 M \\
n &= \frac 1 {\log p} \log \frac 1 M
\end{align}

と見積もることができます。

さて、回答xから得られるフィードバックによって候補が \left( M_1, M_2, \cdots, M_m \right)匹に分割されるとします。 また、 M_iの合計、つまり正解候補数の総数 \sum_i M_i = Nとします。

この時、正解候補ポケモンの選出率が均等だとすると、それぞれの分割が得られる確率は \left( \frac {M_1} N, \frac {M_2} N, \cdots, \frac {M_m} N \right)となります。また、それぞれの分割の後における残り手番数の期待値の見積もりn_iも上記のnの式で計算することができます。つまり、回答xを行った平均の残り手番数の見積もり\hat nは、 各分割の出現率と、その分割における残り手番数の見積もりの期待値として次のように書けます:

 \displaystyle
\begin{align}
\hat n
&= \sum_i \frac {M_i} N n_i \\
&= \sum_i \frac {M_i} N  \frac 1 {\log p} \log \frac 1 {M_i} \\
&= \frac 1 {\log p}  \sum_i \frac {M_i} N  \log \frac 1 {M_i} \\
\end{align}

これを少し変形すると、

 \displaystyle
\begin{align}
\hat n % \left(M_1, M_2, \cdots, M_m \right)
&= \frac 1 {\log p}  \sum_i \frac {M_i} N  \log \frac 1 {M_i} \\
&= \frac 1 {\log p}  \sum_i \frac {M_i} N  \left( - \log {M_i}  + \log N - \log N\right) \\
%&= \frac 1 {\log p}  \sum_i \frac {M_i} N  \left( - \log \frac {M_i} N - \log N\right) \\
%&= \frac 1 {\log p}  \sum_i - \frac {M_i} N  \log \frac {M_i} N + \frac 1 {\log p} \sum_i \frac {M_i} N \log N \\
&= \frac 1 {\log p}  \sum_i - \frac {M_i} N  \log \frac {M_i} N + \frac 1 {\log p} \log N \\
\end{align}

が得られます。

さてここで、下記の事実に着目します:

  • どのような分割\left(M_1, M_2, \cdots, M_m \right)に対しても、
    • それらの合計Nは不変である。
    • 仮定として置いているpの値は不変である。

したがって、\hat nの和の係数、および第二項はどのような分割を選んでも値が不変であることがわかります。

したがって、\hat nを最小化するためには、次のような関数\tilde nを最小化すれば良いことになります:

 \displaystyle
\begin{align}
\tilde n \left(M_1, M_2, \cdots, M_m \right)
%H \left(M_1, M_2, \cdots, M_m \right)
&= - \sum_i \frac {M_i} N  \log \frac {M_i} N, \ \ N = \sum_i M_i
\end{align}

これを離散確率分布\left( \frac {M_1} N, \frac {M_2} N, \cdots, \frac {M_m} N \right)平均情報量またはエントロピーと呼びます。 この量は一般の離散確率分布\left(p_1, p_2, \cdots, p_m \right)に対しても次のようにのように定義されます:

 \displaystyle
\begin{align}
H \left(p_1, p_2, \cdots, p_m \right)
&= - \sum_i p_i  \log p_i
\end{align}

さて、今行いたいのは一番質の良い分割を与えてくれる回答可能ポケモンを探すことでした。今回で言う質の良い分割とは、全ポケモンの平均回答手番数を最小化してくれるような分割です。その近似値として残り手番数の近似値\hat nを計算しましたが、その値を最小化するような分割を知りたいわけです。そしてそれを達成するのは、 Hを最小化するような分割、つまりエントロピーを最大化するような分割を与えてくれる回答ポケモンです。

したがって、分割の質としてエントロピーを使い、そのエントロピーを最大化するようなポケモンを選ぶことが有効初手導出の方法として使えます。

どのような分割がエントロピーを最大化するか

さて、候補数の合計Nが一定の時、どのような分割\left( \frac {M_1} N, \frac {M_2} N, \cdots, \frac {M_m} N \right)がその後の平均手番数を最小化すると思われるか、つまりエントロピーを最大化するかが気になります。 これは一般に確率分布\left( \frac {M_1} N, \frac {M_2} N, \cdots, \frac {M_m} N \right)一様分布であるときであることが知られています。このようなエントロピーの性質は一般の離散確率分布にも適用することができ、ラグランジュの未定乗数法という方法によって導出することができます。

今回の問題で言い換えると、これは全ての分割における候補数が均等である時であると言いかえられます。 先程例として同じ4分割でも(508匹、1匹、1匹、1匹)という分割より(128匹、128匹、128匹、127匹)という分割の方が一般的に性能が良いと言えるだろうという話をしましたが、この時の性能は分割のエントロピーの大小で比べることができます。実際にエントロピーを計算してみると、

 \displaystyle
\begin{align}
% \tilde n \left(M_1, M_2, \cdots, M_m \right)
H \left(\frac {508} {511}, \frac {1} {511}, \frac {1} {511}, \frac {1} {511} \right)
&= 0.042466 \\
H \left(\frac {128} {511}, \frac {128} {511}, \frac {128} {511}, \frac {127} {511} \right)
&= 1.386289
\end{align}

後者の分割ではエントロピーが32倍近くとなっています。 エントロピーは期待手番数に概ね比例する量と言えるので、後者の分割のほうが32倍も少ない手番数で正解に到達できると見積もれることがわかります。 もちろんこれは近似に近似を重ねているので正確ではないのですが、いかに均等な分割の方が手番数を少なくできるかがわかると思います。

したがってここから得られる重要な方針は、なるべく分割が均等になるポケモンを選ぶとその後の期待手番数を少なくすることができるだろうという方針です。

初手に一番良いポケモンは何か?エントロピーによる考察

さて、エントロピーという道具を手に入れた今、初手で一番良く候補を絞ることができるポケモンが何であるかを導くことができます。 先程の考察によると、何も回答していない状態でエントロピーを最大にするようなポケモンが初手として一番良いポケモンになります。*9

以下の表は、初手において一番良く候補を絞り込んでくれる順に並んだポケモンの名前たちです。左から順位、名前、エントロピーの値、得られるパネル列の種類、そして各パネル列が得られた時に正解候補として残るポケモンの数が記されています。この表の一番上が初手にエントロピーの意味で最適なポケモンで、その次が初手の選択として2番目に良いポケモン、その次が3番目…となっています。

その表がこちらです。

  1 ジーランス 2.81552027301750 53 [136, 71, 55, 36, 24, 17, 16, 15, 14, 11, 10, 9, 8, 8, 7, 6, 6, 5, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  2 レントラー 2.80590281618208 46 [143, 54, 54, 38, 22, 21, 21, 15, 13, 12, 9, 9, 9, 7, 7, 7, 6, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  3 ネンドール 2.76650256510168 44 [152, 57, 52, 30, 25, 22, 19, 15, 13, 10, 9, 8, 8, 7, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  4 グラードン 2.75490681338029 58 [163, 78, 36, 30, 22, 16, 15, 12, 11, 11, 11, 10, 9, 7, 5, 4, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  5 ランクルス 2.73260697699840 48 [152, 60, 53, 32, 31, 20, 17, 14, 14, 11, 10, 9, 8, 7, 7, 6, 5, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  6 ルナトーン 2.71418343665737 46 [145, 56, 47, 39, 34, 32, 18, 16, 11, 11, 10, 10, 9, 9, 8, 6, 5, 5, 4, 4, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  7 ドータクン 2.68011040444398 49 [165, 75, 37, 33, 21, 16, 16, 15, 12, 10, 10, 10, 8, 8, 7, 7, 5, 5, 5, 4, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  8 ムーランド 2.66205210039006 47 [166, 71, 50, 28, 21, 16, 15, 15, 12, 11, 10, 8, 6, 6, 6, 5, 5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  9 ヒードラン 2.65930190748349 53 [172, 76, 35, 33, 21, 18, 15, 11, 10, 10, 10, 9, 9, 7, 6, 6, 5, 5, 5, 4, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
 10 シンボラー 2.65678627841122 46 [168, 56, 54, 37, 22, 21, 19, 14, 10, 9, 7, 7, 7, 6, 5, 5, 5, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
 11 エルフーン 2.65438392548458 47 [165, 52, 42, 36, 32, 31, 21, 17, 11, 10, 9, 9, 8, 6, 5, 5, 5, 4, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
 12 キングラー 2.64903504033593 51 [167, 62, 55, 30, 28, 21, 15, 14, 12, 11, 8, 8, 7, 6, 5, 5, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
 13 ランドロス 2.61842964058585 55 [189, 63, 34, 31, 23, 22, 16, 12, 10, 9, 9, 7, 6, 5, 5, 5, 5, 4, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
 14 ドンカラス 2.61396068008001 56 [197, 67, 34, 21, 20, 17, 16, 13, 11, 8, 8, 8, 5, 5, 5, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
 15 ペンドラー 2.61321481279127 49 [174, 56, 53, 39, 21, 19, 18, 11, 11, 11, 9, 9, 9, 7, 6, 5, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
 16 デスカーン 2.61314725428816 43 [153, 62, 43, 43, 41, 37, 15, 11, 10, 10, 10, 6, 6, 6, 5, 4, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
 17 デスバーン 2.60106990313566 45 [158, 63, 46, 42, 39, 35, 14, 10, 10, 7, 7, 6, 6, 6, 6, 5, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
 18 ドッコラー 2.58424752564100 46 [171, 72, 39, 38, 27, 19, 13, 13, 12, 12, 11, 8, 8, 8, 7, 5, 4, 4, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
 19 ハンテール 2.57962383823149 40 [163, 57, 57, 35, 31, 24, 19, 18, 12, 9, 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
 20 バクフーン 2.56037765802205 50 [183, 60, 42, 38, 34, 21, 17, 9, 8, 7, 7, 6, 6, 6, 6, 5, 5, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

!!!

さいしょは ジーランス………

…いや、さいしょはホエルオーなのですが、この言葉を見て何かを思い出した方は多いと思います。 そう、ポケモンルビー・サファイア版のおふれのせきしつ点字で書かれている、レジ系ポケモンを解放するための仕掛けを起動する手順を示した言葉です。

まさか、エントロピーを基準にした結果、ポケモンWordleの最初の一手として良いと思われるポケモンが「ジーランスであることが明かされるとは…これにはかなり驚きました!

ジーランスの分割結果を見てみると、初手でジーランスと回答するだけで次の一手で即座に正解にたどり着けるポケモンが21匹もいることがわかります。ジーランス自身を含めると、さいしょに ジーランスと答えるだけで22/511=4.5%の確率で2手以内で正解できることがわかります。(分割結果の中にジーランス自身が含まれているので、2手で正解可能なのは21匹になります。)

一番絞り込めない場合の候補数でも136匹で、これでも26.6%、つまり1/4近くにまで元の候補数から一手で絞ることができることになります。ジーランスがいかにポケモンWordleにおいて強力なポケモンであるかがわかります。

また、2位のレントラーも非常に僅差でエントロピーが高い値になっています。レントラーも2手目で即座に正解にたどり着けるポケモンが13匹も存在し、同じくらい初手として良いポケモンであると言えます。

また、ジーランスだけでなく、ネンドールグラードン、ルナトーン、ドータクンシンボラーなど伝説や古代に関わるポケモンが多くランクインしているのもアツいです。

ちなみにエントロピー下位20匹は下記の通りになります。

828 ユキハミ  0.69339811979023 11 [429, 37, 17, 15, 4, 2, 2, 2, 1, 1, 1]
829 ナゲキ   0.69246156345221  9 [433, 25, 16, 15, 11, 4, 4, 2, 1]
830 セレビィ  0.65904841055873 13 [442, 26, 10, 9, 6, 5, 5, 3, 1, 1, 1, 1, 1]
831 ポカブ   0.64736718136168 10 [437, 32, 20, 5, 5, 4, 3, 3, 1, 1]
832 ミュウ   0.64366617846590 13 [444, 25, 9, 9, 7, 6, 4, 2, 1, 1, 1, 1, 1]
833 メテノ   0.62855669184240 10 [445, 17, 12, 12, 9, 7, 6, 1, 1, 1]
834 パウワウ  0.62696439018523 11 [446, 19, 12, 11, 8, 5, 4, 3, 1, 1, 1]
835 ヨワシ   0.60924204727621 10 [439, 43, 8, 6, 4, 4, 2, 2, 2, 1]
836 エネコ   0.60375601579838  9 [445, 23, 12, 10, 10, 8, 1, 1, 1]
837 ポッポ   0.59089590679152  8 [431, 56, 14, 3, 3, 2, 1, 1]
838 ゴニョニョ 0.58629397390259 13 [454, 14, 13, 7, 6, 4, 3, 3, 2, 2, 1, 1, 1]
839 ピッピ   0.57428491795491  8 [431, 56, 18, 2, 1, 1, 1, 1]
840 マネネ   0.57162173645497  7 [440, 39, 19, 6, 4, 2, 1]
841 ベベノム  0.55402542215247 10 [454, 18, 12, 9, 7, 5, 2, 2, 1, 1]
842 ブビィ   0.53306539374617  9 [456, 17, 11, 10, 7, 5, 3, 1, 1]
843 モノズ   0.50979013067474  9 [460, 12, 10, 9, 9, 6, 2, 2, 1]
844 モココ   0.47050968698903  9 [463, 18, 11, 6, 6, 3, 2, 1, 1]
845 ミネズミ  0.46685706516407 10 [465, 11, 11, 10, 7, 2, 2, 1, 1, 1]
846 ツボツボ  0.31489085091216  8 [481, 13, 7, 4, 2, 2, 1, 1]
847 ピィ    0.21066133959411  5 [490, 14, 4, 2, 1]

エントロピー最下位はピィとなりました。ピィは名前が2文字しかなく、なおかつ珍しい文字が使われているので無理はありません。一番候補が絞り込めない場合は490匹候補が残り、全体の95.9%が候補として残ります。

名前が5文字のポケモンで最下位なのはゴニョニョで、こちらも「ゴニョ」という3文字だけが実質ヒントになっていて、なおかついずれも珍しい文字なのでこのようなランキングになっています。

エントロピーの一覧の全体は下記のリンクから閲覧することができます。

https://gist.github.com/woodrush/96e55db9a5472bbf781d7dd45ed8762f

以下は、全回答可能ポケモンエントロピーの分布を示した図です。ランキング上位のポケモンが抜きん出てエントロピーが高いことがわかります。攻略チャートを使わずにプレーする場合、これらのポケモンはいずれも初手で有効なポケモンと思われます。

ポケモンWordleにおける初手回答のエントロピーの分布
ポケモンWordleにおける初手回答のエントロピーの分布

ポケモンWordleにおける初手回答のエントロピーのヒストグラム
ポケモンWordleにおける初手回答のエントロピーヒストグラム

上記の表のエントロピーは初手においてのみ有効

ここで、先程の表で示したのは1手目におけるエントロピーであることに注意しなければなりません。 初手で候補を絞り込んだ後の2手目における残りの候補ポケモンは初手とは異なるので、同じポケモンを回答として用いても得られる分割が異なるため、そのポケモンによる分割の質も異なってきます。例えば極端な話、いくらジーランスが強いと言えども、2回連続でジーランスと答えると初手と分割が変わらず全く情報が得られません。このことから、2手目以降は全く異なるポケモンが最適となっていることがわかり、つまり2手目以降は全く別の表が作られることがわかります。

2手目以降に関しても、その時の候補を調べることで同じようなエントロピーによる方針を立てることができます。それはつまり、その時点での残りの候補のポケモンをなるべく均等に分割するようなポケモンを選ぶという方針です。そのようなポケモンをいかに上手く選べるかは、トレーナーであるあなたの腕にかかっています。

Pokedleにおけるエントロピーの計算

ここで、もう一つのポケモン版WordleであるPokedleにおいても5文字のポケモンに制限されています。ただし、こちらではつい最近発売されたPokémon LEGENDS アルセウスに登場する図鑑番号が未判明のポケモンも回答に使用できたため、合計516匹のポケモンが正解候補ポケモンとになっています。

Pokedleにおいて同様のエントロピーの計算を行うと、やはりさいしょは ジーランスが良いという結果が得られます。Pokedleにおいては出現ポケモンが異なるほか、黄色いパネルの出現仕様が少し異なるのですが、それでもはやりジーランスが最もエントロピーが高いポケモンとなりました。Pokedleの詳しい仕様については付録にて説明します。

Pokedleにおけるエントロピーの一覧、つまり有効な初手の一覧をまとめたものが下記のリンクです:

Pokedleのノーマルモードにおける初手回答ポケモンのエントロピー · GitHub

また、Pokedleには6文字以上のポケモンが入力可能なハードモードがあり、こちらのモードでは905匹全てのポケモンが入力可能となっています。更に回答手番数がなんと6手に制限されており、まさにトレーナー力が試される非常に難しいモードとなっています。

これだけ難しいハードモードなので、多くのトレーナーの方の一助となるよう、Pokedleのハードモードにおいても初手のエントロピーを計算しました。その一覧をまとめたものが下記のリンクです:

Pokedleのハードモードにおける初手回答のエントロピー · GitHub

こちらではジーランスではなくマンキーが最適となりました。これは、ハードモードでは6文字未満のポケモンは最後のスペースがフィードバックとして返され、なおかつ末尾にスペースを含んでいるポケモンは多いため、末尾にスペースを含むマンキーが最適であるという結果になったようです。

ちなみに、ノーマルモードとハードモードのいずれにおいてもゴニョニョが初手におけるエントロピーが最下位となっていました。これは先程説明した通りの理由であると思われるのですが、ゴニョニョは905匹の中でもオンリーワンな名前を持っていると言えます。

ピカチュウ」という名前の構成音の珍しさ

さて、Pokedleのノーマルモードにおける初手エントロピーの下位20匹を見ると、次のようになっています:

497 ギギギアル 1.15679179888471 18 [364, 51, 39, 28, 8, 6, 6, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1]
498 ヒノヤコマ 1.14223671695414 26 [387, 40, 28, 11, 11, 7, 6, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
499 ジグザグマ 1.14035134784917 18 [381, 40, 24, 22, 10, 9, 9, 3, 3, 3, 3, 2, 2, 1, 1, 1, 1, 1]
500 チョロネコ 1.13346856658721 24 [387, 37, 23, 23, 9, 7, 6, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
501 フシギソウ 1.12389149293466 16 [384, 39, 23, 14, 12, 10, 9, 8, 6, 3, 2, 2, 1, 1, 1, 1]
502 フシギダネ 1.11803020812454 18 [388, 39, 16, 14, 12, 12, 9, 6, 5, 5, 2, 2, 1, 1, 1, 1, 1, 1]
503 ピカチュウ 1.10909905602434 24 [398, 29, 19, 16, 8, 7, 7, 5, 4, 3, 3, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
504 ウデッポウ 1.10416584531979 19 [383, 50, 20, 16, 14, 9, 4, 4, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1]
505 ビクティニ 1.10130255849240 20 [390, 39, 23, 14, 13, 8, 4, 4, 4, 3, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1]
506 レジエレキ 1.09800510234134 19 [393, 34, 21, 14, 11, 9, 7, 6, 5, 3, 3, 2, 2, 1, 1, 1, 1, 1, 1]
507 マダツボミ 1.07879901160671 21 [396, 33, 17, 15, 15, 11, 6, 4, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
508 カゲボウズ 1.05345690945028 18 [403, 22, 17, 16, 10, 9, 8, 8, 7, 4, 3, 2, 2, 1, 1, 1, 1, 1]
509 ヒポポタス 1.04618136093343 16 [385, 59, 18, 18, 7, 5, 5, 4, 3, 3, 3, 2, 1, 1, 1, 1]
510 ハハコモリ 1.04283042860577 18 [391, 54, 18, 10, 8, 7, 6, 5, 4, 3, 2, 2, 1, 1, 1, 1, 1, 1]
511 エネコロロ 1.01433063287613 17 [403, 27, 19, 17, 12, 10, 7, 7, 4, 3, 1, 1, 1, 1, 1, 1, 1]
512 ユキメノコ 0.97541863359589 17 [402, 33, 28, 16, 15, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1]
513 タマゲタケ 0.96326915783888 17 [405, 42, 16, 11, 10, 9, 7, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1]
514 ナゾノクサ 0.95581647037521 20 [408, 41, 15, 14, 10, 6, 5, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1]
515 シュシュプ 0.79220765985007 14 [428, 36, 9, 9, 8, 7, 6, 5, 3, 1, 1, 1, 1, 1]
516 ゴニョニョ 0.59527491852947 13 [457, 15, 14, 7, 6, 4, 3, 3, 2, 2, 1, 1, 1]

なんと下から14位にピカチュウがランクインしています。

ピカチュウと言えば、ポケモンを代表すると言っても良い名前です。にも関わらずこれだけエントロピーが低いのは、ポケモン全体の名前で見ると珍しい音で構成されている名前であるからと言えるでしょう。

そこでポケモンWordleにおけるポケモンの文字を出現頻度順に並べると次のようになります:

    'ー', 'ン', 'ル', 'ラ', 'ス', 'ッ', 'リ', 'ド', 'イ', 'マ',
    'ト', 'ク', 'ロ', 'シ', 'オ', 'ア', 'キ', 'カ', 'バ', 'ジ',
    'レ', 'ガ', 'グ', 'コ', 'チ', 'ウ', 'タ', 'フ', 'ニ', 'ャ',
    'ブ', 'ム', 'ダ', 'デ', 'ゴ', 'ュ', 'ノ', 'テ', 'メ', 'ナ',
    'ミ', 'サ', 'エ', 'ハ', 'ヤ', 'ボ', 'ギ', 'パ', 'ゲ', 'モ',
    'ワ', 'ザ', 'ィ', 'ズ', 'ビ', 'プ', 'ケ', 'ネ', 'ツ', 'ポ',
    'ョ', 'ヒ', 'ベ', 'ペ', 'ホ', 'ヨ', 'ゼ', 'ソ', 'ピ', 'セ',
    'ユ', 'ェ', 'ヌ', 'ォ', 'ゾ', 'ァ', 'ヘ', '2',  'Z', 'ヂ',

このように、ピカチュウの「ピ」が下から12位であることがわかります。ピカチュウと言えば冒頭の「ピ」が目立ちますが、実はポケモン全体で見ると「ピ」はかなり珍しい文字なのです。

したがってポケモンを代表すると言っても良いピカチュウは、ポケモン全体の中で見ると珍しい構成音を持つ名前なのです。しかしだからこそ、ピカチュウポケモンの中でも独特な響きを持つ名前として印象に残るのかもしれません。

最後に

エントロピーに基づいた考察の結果、ポケモンWordleおよびPokedleの有効な初手はジーランスであることがわかりました。また、Pokedleのハードモードにおいてはマンキーが有効であることがわかりました。そして初手および2手目以降において、なるべく次の候補が均等に分割されるようなポケモンを選ぶのが良いという方針が得られました。

また、エントロピーを考察した二次的な効果として、「ピカチュウ」という名前がポケモン全体の中で見てもかなり珍しい音で構成されていることがわかりました。だからこそ、ピカチュウポケモンの中でも独特な響きを持つ名前として印象に残るのかもしれません。

さて、エントロピーの導出にて述べたように、エントロピーはその後の平均手番回数の見積もりでしかありません。なぜならば、エントロピーを使う時は「その後の選択肢は毎手番p \lt 1倍になる」という非常に強い仮定を置いているからです。 エントロピーの一覧を見ると、各ポケモンによって実際の候補の別れ方はバラバラで、綺麗にp \lt 1倍にはなっていないことがわかります。ここからもわかるように、エントロピーを使うのは現実と離れている見積りにすぎないため、この結果が最適である保証はどこにもありません。したがって、今後更なる良い戦略が見つかる可能性は存分に残されています。

そして上位のポケモンエントロピーがかなりの僅差となっていました。そのため、初手におけるポケモンの選択にはその分の余地が残されています。更に、2手目以降はエントロピーの表が完全に書き換わるため、その時の残りの候補を考慮して良いポケモンを選ぶ能力が問われることになります。

これは、ポケモン金銀における次の名言を思い起こさせます。

つよいポケモン よわいポケモン

そんなの ひとの かって

ほんとうに つよい トレーナーなら

すきなポケモンで かてるように がんばるべき

付録

以下では付録としてPokedleにおける内容について述べます。

Pokedleのデータの収集

Pokedleの作者のちゅうさんの製作記事*10によると、 Pokedleは5文字のポケモンに正解候補および回答候補が限定されているようです。 そこで全国ポケモン図鑑順のポケモン一覧 - Wikipedia から5文字のポケモンの名前を収集します。

つい先日発売されたPokémon LEGENDS アルセウスに登場する図鑑番号が未判明のポケモンも含めると、 5文字の名前を持つポケモンは2022年2月1日現在全部で516匹いることがわかります。 アルセウスに登場するポケモンを入力したところ有効だと判定されたので、これらのポケモンも正解候補に存在していると思われます。

Pokedleにおけるパネルのフィードバックのルール

Pokedleをプレーしてみた結果、パネルのフィードバックのルールは下記のようになっていると思われます。

  • まず回答と正解の両方において位置と内容が一致している文字を全て探し、それらを緑色のパネルとする。
  • 次に位置は合っていないが正解の名前中に含まれている文字を全て探し、それらを黄色のパネルとする。
    • ただし、同じ文字が重複して登場している場合でも、一度でも登場していれば全て黄色のパネルとする。
  • 名前中に含まれていないパネルは全て灰色のパネルとする。

実際にPokedleをプレーしてみると、黄色のパネルの出現ルールが原作のWordleでの仕様とは異なっているようです。 具体的には、1月31日の正解ポケモンは伸ばし棒「ー」が一つ含まれていたのですが、 伸ばし棒が2つ含まれるポケモンを回答したところいずれの伸ばし棒も黄色いパネルになりました。 これに対しWordleでは黄色いパネルは正解単語に含まれる文字数分だけ現れるようです。 例えば正解単語にAが1つ含まれていて、予想単語にAが2つ含まれていた場合、黄色いパネルで表示されるAは1枚だけになるようです。 これらはいずれも本記事の著者がプレーした結果なので確かではないのですが、このような仕様になっていると思われます。

PARANOIA survivor MAX (鬼) SP のラストの滝たちは、互いに鏡像変換の関係にある譜面となっている

Dance Dance Revolution *1に関する記事です。

PARANOIA survivor MAX (鬼) SP のラストには長い滝が登場します。この滝は4つの部分に分けられますが、これらの滝は全て1つ目の滝に対して下記のような鏡像変換を適用したような配置になっていることに気付きました。

  • 2つ目の滝では、←と→が互いに入れ替わり、他のポジションは固定(ただし、最後の一音だけ例外で、→が入れ替わらず→のままになっています。)
  • 3つ目の滝では、↓と↑が互いに入れ替わり、他のポジションは固定
  • 4つ目の滝では、上記の変換が両方適用される

この事実は目視では確認しづらいので、これを検証する下記のようなコードを書きました。言語はPythonです。実際、2つ目の滝の最後の音だけが入れ替わっていないことは、このコードを動かすことで初めて気付きました。

l = [
    "jhjkhlkjljhkjlhjklhjljklkjhlkjl",
    "jljklhkjhjlkjhljkhljhjkhkjlhkjl",
    "khkjhljklkhjklhkjlhklkjljkhljkl",
    "klkjlhjkhkljkhlk",
]

d_2 = {
    "h": "l",
    "j": "j",
    "k": "k",
    "l": "h",
}

d_3 = {
    "h": "h",
    "j": "k",
    "k": "j",
    "l": "l",
}

d_4 = {
    "h": "l",
    "j": "k",
    "k": "j",
    "l": "h",
}

stream_1 = l[0]
stream_2 = "".join([d_2[c] for c in l[1]])
stream_3 = "".join([d_3[c] for c in l[2]])
stream_4 = "".join([d_4[c] for c in l[3]])


assert stream_1 == stream_3
assert stream_1[:-1] == stream_2[:-1]
assert stream_1.startswith(stream_4)

print(stream_1)
print(stream_2)
print(stream_3)
print(stream_4)

なぜ二つ目の滝では最後の一音だけ→が入れ替わらず→のままになっているかという理由について、ここが←になっていた場合を考えると、3つ目の滝の冒頭の↑を右足で踏もうとした時に、すでに右足で←を踏んでしまっているため足が絡まってしまうことから、どうやらそのような事を防止するために最後の音だけ入れ替わらずにしてあるようです。

また、4つ目の滝は途中で曲が減速する部分に入り、滝が途中で終わってしまいます。この理由について、これは鏡像変換を二つ適用していることから、実は省略されている部分は難しい配置になっているため途中で切っているのではないかと予想したのですが、特にそうではありませんでした。下記のコードによって、1つ目の滝に4つ目の滝の変換を適用することで省略された残りの滝の譜面を生成し、矢印表記で表示してみたのですが、特に変わった様子はありませんでした。(下記のコードは、上記のコードの末尾にappendして使います。)

stream_4_dash = "".join([d_4[c] for c in l[0]])

def printstream (stream):
    c2arrow = {
        "h": "←",
        "j": " ↓",
        "k": "  ↑",
        "l": "   →",
    }
    print("←↓↑→")
    for c in stream:
        print(c2arrow[c])

printstream(stream_4_dash)

さけるチーズを避けるチーズによるラムダ計算・Lazy K入門

純粋関数型言語「さけるチーズ」とは、難解プログラミング言語「Lazy K」の文法に束縛変数を導入することでラムダ計算風にし、自然言語的に意味が通るように文法を直した言語です:
woodrush.hatenablog.com

この記事では、「さけるチーズ」を用いてチャーチエンコーディングによる自然数やリストの表現について説明し、最後にさけるチーズ(というよりもLazy K)を用いたHello, world!プログラムの書き方を解説します。この記事は前回の記事の続きでもあり、また筆者自身のラムダ計算・Lazy K入門の過程をまとめた記事でもあります。Lazy Kはとても面白い言語なのですが資料が少ないので、この記事をラムダ計算・Lazy K入門の副読記事として活用して頂ければ幸いです。

ここでは、

  • 自然数の表現
  • 加算と累乗
  • リストの表現
  • Hello, World!プログラム

について解説します。

さけるチーズとLazy Kの相互翻訳法については、記事末尾の付録にて解説しています。

自然数の表現

まずはプログラミング上最も重要なデータの一つ、数を表現してみます。数字を含まない文法しか持たないさけるチーズで、どのようにして自然数を表現するのでしょうか?

さけるチーズでは、自然数をチャーチエンコーディング究極の関数型言語による至高のHello, world! - Life Goes On参照)によって表現します。
これは端的に言うと、自然数Nを、「任意の構造物fとXを捧げられた時、XにfをN回捧げた物を返す構造物」で表すという事です。
つまり「Nに捧げるfに捧げるX」が

Nに捧げるfに捧げるX
= fに捧げる「fに捧げる「fに捧げる…「fに捧げるX」」」」…」」」」  (fがN回登場)

に変換されるような構造物Nで、自然数Nを表します。

具体的には、これは以下のような構造物で実現できます:

0 = 「さけるチーズを避ける「裂けてるチーズ」」
1 = 「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」に捧げる「さけるチーズを避ける「裂けてるチーズ」」」
2 = 「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」に捧げる「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」に捧げる「さけるチーズを避ける「裂けてるチーズ」」」」
…

例えば

0に捧げるfに捧げるX
= 「さけるチーズを避ける「裂けてるチーズ」」に捧げるfに捧げるX
= 「fを避ける「裂けてるチーズ」」に捧げるX
= 「裂けてるチーズ」に捧げるX
= X

となり、確かにfにXを0回捧げた結果が返ってきます。
また、ここでは長くなるので割愛しますが、「2に捧げるfに捧げるX」という構造物を評価すると、実際に「fに捧げる「fに捧げるX」」となることが確認できます。

実はこの表現には規則性があり、後者関数

SUCC = 「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」

を定義すると、

0 = 「さけるチーズを避ける「裂けてるチーズ」」
1 = SUCCに捧げる0
2 = SUCCに捧げる1
3 = SUCCに捧げる2
…

のように計算できます。

このような数の表現方法(チャーチエンコーディング)におけるポイントは、どの数の表現の最上層部にも禁断の者が存在しているため、これ以上の変形ができないという事です。例えば 0 = 「さけるチーズを避ける「裂けてるチーズ」」では禁断の者さけるチーズがいます。また、1 = SUCCに捧げる0 では、SUCCがさけるチーズとチーズという2人の禁断の者を含んでいることから、0を捧げても禁断の者さけるチーズが残り、これ以上の変形ができません。
変形ができないことから、「最終的に計算結果の答えとして残す」ような使い方ができるのです。

加算と累乗

このような数の表し方の下で、数同士の演算も行うことができます。

まずX+Yという計算は、「XにSUCCをY回適用する」ことによって表すことができます。
そしてY自身、「与えられた関数をY回適用する」という機能を持つため、

「Yに捧げるSUCCに捧げるX」
= 「SUCCに捧げる「SUCCに捧げる…「SUCCに捧げるX」」」」」…」  (SUCCがY回登場)

となります。
ここで、

ADD = 「「裂けてるチーズ」と「さけるチーズを避けるSUCC」と地図のある地、伊豆」

を定義すると、

ADDに捧げるXに捧げるY
= 「「裂けてるチーズ」と「さけるチーズを避けるSUCC」と地図のある地、伊豆」に捧げるXに捧げるY
= 「「裂けてるチーズ」と「さけるチーズを避けるSUCC」とXのある地、伊豆」に捧げるY
= 「裂けてるチーズ」に捧げるXに捧げる「「さけるチーズを避けるSUCC」に捧げるX」に捧げるY
= 「裂けてるX」に捧げる「「Xを避けるSUCC」」に捧げるY
= Xに捧げるSUCCに捧げるY
= 「SUCCに捧げる「SUCCに捧げる…「SUCCに捧げるX」」」」」…」  (SUCCがY回登場)

となり、捧げ物をすることで足し算が行える構造物を得ることができました。

ここで、3を表す構造物に2を捧げたらどうなるでしょうか?
「3に捧げるfに捧げるX」=「fに捧げる「fに捧げる「fに捧げるX」」」であることから、

3に捧げる2に捧げるfに捧げるX
= 「2に捧げる「2に捧げる「2に捧げるf」」」に捧げるX  (3の直後の捧げ物を2つ取るため、Xは余る)
= 2に捧げる「2に捧げる「2に捧げるf」」に捧げるX
= 「「2に捧げる「2に捧げるf」」に捧げる「「2に捧げる「2に捧げるf」」に捧げるX」」  (※1)
= 「「2に捧げる「2に捧げるf」」に捧げる「2に捧げる「2に捧げるf」に捧げるX」」
= 「「2に捧げる「2に捧げるf」」に捧げる「「2に捧げるf」に捧げる「「2に捧げるf」に捧げるX」」」
= 「「2に捧げる「2に捧げるf」」に捧げる「2に捧げるfに捧げる「「2に捧げるf」に捧げるX」」」
= 「「2に捧げる「2に捧げるf」」に捧げる「2に捧げるfに捧げる「2に捧げるfに捧げるX」」」
= 「「2に捧げる「2に捧げるf」」に捧げる「2に捧げるfに捧げる「fに捧げる「fに捧げるX」」」」
= 「「2に捧げる「2に捧げるf」」に捧げる「fに捧げる「fに捧げる「fに捧げる「fに捧げるX」」」」」  (※1)

A = 「fに捧げる「fに捧げる「fに捧げる「fに捧げるX」」」」とおくと、
= 「「2に捧げる「2に捧げるf」」に捧げるA

※1、※2より、
「「2に捧げる「2に捧げるf」」に捧げるA
= 「fに捧げる「fに捧げる「fに捧げる「fに捧げるA」」」」
となることがわかる。よって、Aを代入して

= 「fに捧げる「fに捧げる「fに捧げる「fに捧げる「fに捧げる「fに捧げる「fに捧げる「fに捧げるX」」」」」」」」

これは、Xにfを8回捧げたものになっています。
よって、「3に捧げる2」は、さけるチーズ言語でいう8に等しいことになります。
ここでいう8は2の3乗を表しています。「与えられた物を3回捧げる」機能を持つものに「与えられた物を2回捧げる」機能を持つものを与えた結果、2×2×2回捧げることになった、というわけです。

リストの表現

さて、これまでで一つの数を表すことができました。しかし、文字列や数の列を扱うには、列の概念、つまりリストの概念が必要です。

まず、

PAIRに捧げるXに捧げるYに捧げるf
= fに捧げるXに捧げるY

となるような構造物PAIRを考えます。
PAIRは、具体的には

PAIR = 「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「さけるチーズを避けるチーズ」」と「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「「裂けてるチーズ」とさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と「さけるチーズを避ける「さけるチーズを避けるチーズ」」と地図のある地、伊豆」

と表すことができます。(証明はとても長いのでここでは省略します。)

ここで、PAIRにXとYのみを捧げ、fを捧げず

PAIRに捧げるXに捧げるY

で捧げ物を止めてみましょう。この構造物にはfを捧げる余地の為の禁断の者が1人含まれるため、これ以上変形できません。
これは、XとYの組(X . Y)を表しています。

A,B,C,Dのリストを作る場合、

「PAIRに捧げるAに捧げる「PAIRに捧げるBに捧げる「PAIRに捧げるCに捧げる「PAIRに捧げるDに捧げるEND」」」」

これは、(A . (B . (C . (D . END))))という、入れ子になったペアを表しています。
ここで、ENDはリストの終わりを表す特別な構造物です。冒頭にて述べたように、さけるチーズはLazy Kをベースにしているため、ENDには256を用います。
(リストに関して、詳しくは究極の関数型言語による至高のHello, world! - Life Goes On参照。)

Hello, World!

さて、ここまでの知識が揃うと、いよいよHello, World!プログラムを書くことができます。

さけるチーズでは、実行結果として残った構造物をASCII文字コードの入ったリストとして解釈し、文字列として表示します。
つまり、Hello, World!を出力するには、

(72 . (101 . (108 . (108 . (111 . (44 . (32 . (119 . (111 . (114 . (108 . (100 . (33 . 256)))))))))))))
= 「PAIRに捧げる72に捧げる「PAIRに捧げる101に捧げる「…に捧げる256」」」」…」」」」

という構造物を作れば良いのです。

ここでややこしいことに、さけるチーズ(というよりもLazy K)では「プログラムに標準入力の値が捧げられる」ため、実行時には

「PAIRに捧げる72に捧げる「PAIRに捧げる101に捧げる「…に捧げる256」」」」…」」」」に捧げる標準入力

という構造物が評価されてしまいます。
そこで、この標準入力を右から左へ受け流すため、

「さけるチーズを避けるHELLO_WORLD」

というプログラムを書きます。これによって、

「さけるチーズを避けるHELLO_WORLD」に捧げる標準入力
= 「標準入力を避けるHELLO_WORLD」
= HELLO_WORLD
⇒ Hello, World!

のように、無事Hello, World!を表示することができます。

また、数を効率的に表現するために2進法を使います:

4 = 2に捧げる2
8 = 3に捧げる2 = (2+1)に捧げる2
16 = 4に捧げる2 = (2^2)に捧げる2
32 = 5に捧げる2 = (2^2+1)に捧げる2
64 = 2に捧げる8

72 = ADDに捧げる64に捧げる8
101 = ADDに捧げる64に捧げる「ADDに捧げる32に捧げる「ADDに捧げる4に捧げる1」」
…

このようにして書いたさけるチーズによるHello, World!プログラムが以下です:

「さけるチーズを避ける「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」」」と地図のある地、伊豆」と「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズと
さけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「裂けてるチーズ」」」」」と地図のある地、伊豆」と「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ
」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」」」」」と地図のある地、伊豆」と「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」」」」」と地図のある地、伊豆」と「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と
地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」のある地、伊豆」に捧げる「裂けてるチーズ」」」」」」」と地図のある地、伊豆」と「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「「「「
「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」」」」と地図のある地、伊豆」と「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」」と地図のある地、伊豆」と「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを
避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」のある地、伊豆」に捧げる「裂けてるチーズ」」」」」」」と地図のある地、伊豆」と「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と
「裂けてるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」のある地、伊豆」に捧げる「裂けてるチーズ」」」」」」」と地図のある地、伊豆」と「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける
「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」」」」」と地図のある地、伊豆」と「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチー
ズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」」」」」と地図のある地、伊豆」と「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」と「「「さけるチーズを避け
る「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」」」」と地図のある地、伊豆」と「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「「「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」に捧げる「裂けてるチーズ」」」と地図のある地、伊豆」と「さけるチーズを避ける「「裂けてるチーズ」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」のある地、伊豆」」と地図のある地、伊豆」」と地図のある地、伊豆」」と地図のある地、伊豆」」と地図のある地、伊豆」」と地図のある地、伊豆」」と地図のある地、伊豆」」と地図のある地、伊豆」」と地図のある地、伊豆」」と地図のある地、伊豆」」と地図のある地、伊豆」」と地図のある地、伊豆」」と地図のある地、伊豆」」と地図のある地、伊豆」」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と地図のある地、伊豆」」


結論:さけるチーズを避けるチーズでプログラミングをすることができる

あとがき

今回は、さけるチーズによる自然数の表現、加算と累乗計算、リストの表現、そしてHello, World!プログラムについて解説しました。
累乗以外にも加減乗除など様々な演算を行うことができます。さけるチーズはチューリング完全であるため、数にまつわる演算ならばいかなるものでも行うことができます。今回、Lazy Kの計算能力や方法には度々驚かされました。特に、404 Blog Not Found:Math - 言語はどこまで小さくなれるか - (unlambda|iota|jot) のすすめ究極の関数型言語による至高のHello, world! - Life Goes Onなどが非常に参考になります。

さけるチーズやLazy K自体を書くことは難しいのですが、究極の関数型言語による至高のHello, world! - Life Goes Onにあるように、Scheme内のDSLで記述したプログラムに対応するLazy Kコードを出力するプログラムがあり、それを用いると非常にさけるチーズ(Lazy K)開発が捗ります。

また、この記事の執筆にあたって筆者が最も嵌ったのは、Lazy Kではチャーチ数そのものを出力に用いることができず、単一の数字でも、必ずリストに入れて出力しなければいけないという事です。
例えば、65という数字(ASCIIのAに対応)を出力したい時、チャーチ数の65を使うと出力されず、

PAIRに捧げる65に捧げるEND

という65を唯一の要素に持つリストを出力しなければなりません。
これは仕様にしっかりと書いてあることなのですが、そもそもSKIコンビネータ計算におけるリストとは何なのか、という点から調べる必要があり、苦労しました。

付録 - さけるチーズとLazy Kの相互翻訳

まず、Lazy Kからさけるチーズに翻訳する場合、

1. SXYZ → 「XとYとZのある地、伊豆」
2. KXY → 「Yを避けるX」  (※YとXが逆な事に注意!これは、演算子の日本語的な意味を保存するため)
3. IX → 「裂けてるX」
4. (式)XYZ → 「「式」に捧げるAに捧げるBに捧げるC」

4つ目の式が一番特徴的で、関数適用を「に捧げる」の文法で表しています。

これを踏まえた上で、さけるチーズからLazy Kに翻訳する場合、

  • 「XとYと地図のある地、伊豆」 → (SXY)
  • 裂けてる「Xを避けるチーズ」 → I(KX)
  • 「XとYと地図のある地、伊豆」に捧げるZ → (SXY)Z

のように、禁断の者(チーズ、さけるチーズ、地図)を空のコンビネータで置き換えることで翻訳が可能になります。
最後の「に捧げる」を用いた翻訳が最大のポイントで、これはコンビネータSXY(つまりラムダ式 λ a. SXYa )にZを適用したものであるためこうなっています。言い換えると、禁断の者がラムダ計算における束縛変数を表していて(つまり「XとYと地図のある地、伊豆」 = λ Z. SXYZ)、更にLazy Kでは関数適用はコンビネータの直後に引数を置くだけで行えるということが、この翻訳の原理になっています。

さけるチーズを避けるチーズで作る関数型言語

最近、「裂けてるさけるチーズを裂けて避けるチーズが載ってる裂けてる地図を裂けて避けるチーズ」が話題になりました。
togetter.com

「さけるチーズを避けるチーズ」において、チーズがさけるチーズを避けた結果、残るのはチーズ。
「さけるチーズを避けるチーズを避ける地図」において、さけるチーズとチーズが避けられた結果、残るのは地図。
では「裂けてるさけるチーズを裂けて避けるチーズが載ってる裂けてる地図を裂けて避けるチーズ」の「事の果て」には、何が残るのか?
この記事では、そのような疑問を追うこと、つまりさけるチーズや地図が従う法則を追う行為によって、チューリング完全な純粋関数型言語「さけるチーズ」を構成します。

(具体的には、Lazy Kと呼ばれる言語に束縛変数を導入することでラムダ計算風にし、自然言語的に意味が通るように中置記法に改めたものです。)

例えば以下は、さけるチーズで記述した素数を無限に出力し続けるプログラムです。

「さけるチーズを避ける「「裂けてるチーズ」と「裂けてるチーズ」と「「さけるチーズを避ける「「「さけるチーズを避ける「「裂けてるチーズ」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」とさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「チーズとさけるチーズと地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」と「さけるチーズを避ける「さけるチーズを避けるチーズ」」のある地、伊豆」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「さけるチーズを避けるチーズ」」と「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「「さけるチーズ
を避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「さけるチーズを避けるチーズ」」と「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「さけるチーズを避けるチーズ」」と「「裂けてるチーズ」と「裂けてるチーズ」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と「さけるチーズを避ける「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避けるチーズ」」と地図のある地、伊豆」」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と「さけるチーズを避ける「「さけるチーズを避ける「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「「裂けてるチーズ」とさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「さけるチーズを避けるチーズ」」と「「さけるチーズを避ける「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」
と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」と「「「裂けてるチーズ」と「裂けてるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」「に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」のある地、伊豆」」と「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避ける「裂けてるチーズ」」」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「さけるチーズを避けるチーズ」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と地図のある地、伊豆」
」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と「さけるチーズを避ける「「さけるチーズを避ける「さけるチーズを避けるチーズ」」と「「「裂けてるチーズ」と「さけるチーズを避ける「「「「「「チーズとさけるチーズと地図のある地、伊豆」と「さけるチーズを避けるチーズ」と「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避ける「裂けてるチーズ」」」と地図のある地、伊豆」のある地、伊豆」と「さけるチーズを避ける「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」と地図のある地、伊豆」のある地、伊豆」「「に捧げる「「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「さける
チーズを避ける「裂けてるチーズ」」」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」」に捧げる「さけるチーズを避ける「さけるチーズを避けるチーズ」」」」と地図のある地、伊豆」と「さけるチーズを避ける「さけるチーズを避けるチーズ」」と地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「「裂けてるチーズ」とさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「さけるチーズを避けるチーズ」」と「「さけるチーズを避ける「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」と「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避けるチーズ」」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と「さけるチーズを避ける「さけるチーズを避ける「さけるチーズを避ける「裂けてるチーズ」」」」と地図のある地、伊豆」と
地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「「裂けてるチーズ」とさけるチーズと地図のある地、伊豆」」と「「チーズとさけるチーズと地図のある地、伊豆」と「「裂けてるチーズ」とさけるチーズと地図のある地、伊豆」と「さけるチーズを避ける「さけるチーズを避けるチーズ」」のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と「「さけるチーズを避ける「さけるチーズを避けるチーズ」」と「「さけるチーズを避ける「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」と「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避ける「裂けてるチーズ」」」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」」と地図のある地、伊豆」と「さけるチーズを避ける「さけるチーズを避ける「さけるチーズを避ける「裂けてるチーズ」」」」と地図のある地、伊豆」と地図のある地、伊豆」」と地図のある地、伊
豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と「さけるチーズを避ける「さけるチーズを避ける「裂けてるチーズ」」」と地図のある地、伊豆」のある地、伊豆」」と「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避けるチーズ」」と地図のある地、伊豆」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「「さけるチーズを避ける「「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「「さけるチーズを避ける「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」」と「「「裂けてるチーズ」と「裂けてるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」のある地、伊豆」と地図のある地、伊豆」」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」と「さけるチーズを避
けるチーズ」と地図のある地、伊豆」」とさけるチーズと地図のある地、伊豆」」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「さけるチーズを避けるチーズ」」と「「裂けてるチーズ」と「裂けてるチーズ」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と「さけるチーズを避ける「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避ける「裂けてるチーズ」」」と地図のある地、伊豆」」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」のある地、伊豆」「に捧げる「「裂けてるチーズ」と「裂けてるチーズ」と「「さけるチーズを避ける「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「「「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避けるチーズ」」と地図のある地、伊豆」と「さけるチーズを避ける「裂けてるチーズ」」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」と「「チーズとさけるチーズと地図のある地、伊豆」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊
豆」」と「「さけるチーズを避ける「さけるチーズを避けるチーズ」」と「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「「裂けてるチーズ」とさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」と「さけるチーズを避ける「さけるチーズを避けるチーズ」」のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」とさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「「さけるチーズを避ける「さけるチーズを避けるチーズ」」とさけるチーズと地図のある地、伊豆」」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「さけるチーズを避けるチーズ」」と「「裂けてるチーズ」と「裂けてるチー
ズ」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と「さけるチーズを避ける「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と「さけるチーズを避ける「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「「「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避けるチーズ」」と地図のある地、伊豆」と「さけるチーズを避ける「裂けてるチーズ」」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「さけるチーズを避けるチーズ」」と「「さけるチーズを避ける「「裂けてるチーズ」と「裂けてるチーズ」と「「さけるチーズを避ける「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「「さけるチーズを避ける「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけ
るチーズを避ける「さけるチーズを避けるチーズ」」と「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「「裂けてるチーズ」とさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と「さけるチーズを避ける「さけるチーズを避けるチーズ」」と地図のある地、伊豆」」とさけるチーズと地図のある地、伊豆」」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「さけるチーズを避けるチーズ」」と「「さけるチーズを避ける「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避けるチーズ」」と地図のある地、伊豆」」と「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避けるチーズ」」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と「さけるチーズを避ける「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避けるチーズ」」と地図のある地、伊豆」」と地図のある地、伊豆」と地図のある地、
伊豆」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」とさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「「さけるチーズを避ける「さけるチーズを避けるチーズ」」とさけるチーズと地図のある地、伊豆」」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「さけるチーズを避けるチーズ」」と「「裂けてるチーズ」と「裂けてるチーズ」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と「さけるチーズを避ける「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避ける「裂けてるチーズ」」」と地図のある地、伊豆」」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と「さけるチーズを避ける「さけるチーズを避ける「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避ける「裂けてるチーズ」」」と地図のある地、伊豆」」」と地図のあ
る地、伊豆」と地図のある地、伊豆」のある地、伊豆」」と「「さけるチーズを避ける「「裂けてるチーズ」と「裂けてるチーズ」と地図のある地、伊豆」」と「「さけるチーズを避ける「「さけるチーズを避ける「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避ける「裂けてるチーズ」」」と地図のある地、伊豆」」とさけるチーズと地図のある地、伊豆」」と「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける「さけるチーズを避けるチーズ」」と「「裂けてるチーズ」と「さけるチーズを避ける「「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避ける「裂けてるチーズ」」」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と「さけるチーズを避ける「「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避けるチーズ」」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」と「「さけるチーズを避ける
「さけるチーズを避けるチーズ」」と「「裂けてるチーズ」と「裂けてるチーズ」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と地図のある地、伊豆」と「さけるチーズを避ける「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避ける「裂けてるチーズ」」」と地図のある地、伊豆」」と地図のある地、伊豆」」と地図のある地、伊豆」と地図のある地、伊豆」のある地、伊豆」「「に捧げる「「「さけるチーズを避ける「チーズとさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」と「裂けてるチーズ」と地図のある地、伊豆」」に捧げる「「裂けてるチーズ」と「裂けてるチーズ」と「「さけるチーズを避ける「「さけるチーズを避ける「「「裂けてるチーズ」と「さけるチーズを避ける「さけるチーズを避ける「裂けてるチーズ」」」と地図のある地、伊豆」とさけるチーズと地図のある地、伊豆」」と「さけるチーズを避けるチーズ」と地図のある地、伊豆」」と「「裂けてるチーズ」と「
裂けてるチーズ」と地図のある地、伊豆」と地図のある地、伊豆」のある地、伊豆」」」」

The Lazy K Programming LanguageのSample Codeをさけるチーズに変換しました。)

このチーズ達の「せめぎ合い」の果てに何が残るのか、それを探す過程が素数を求める事に対応するのです。
さけるチーズはチューリング完全であるため、これほど単純な文法を持ちながら、素数計算に限らず、計算機上で実行できるいかなる計算も実行することができます。

自然数すら現れないこのコードで、なぜ素数が計算できるのか…?本当にそうなのか?という疑問に答えるため、この記事では上記のコードを実際に実行するために必要なツールを用意しました。「さけるチーズ」は「Lazy K」と呼ばれる言語をベースにしているため、今回はさけるチーズ → Lazy K 翻訳器と Lazy K → さけるチーズ翻訳器を構成しました。上記のコードを実際に実行するには、翻訳器によってさけるチーズをLazy Kに翻訳し、Lazy Kインタプリタ(たとえば http://lazy-k.appspot.com/ など)を使用して下さい。(インタプリタ作成は今回は割愛しました。)翻訳器はGitHub - woodrush/ski2cheese: 純粋関数型言語「さけるチーズ」とLazy Kの相互翻訳器に載せています。

では、さけるチーズとはどのような言語なのでしょうか。

さけるチーズにおける4つの法則

世の中には数多の言語が存在し、それぞれ複雑な構文や規則を持っています。しかし、さけるチーズに存在するのはたった4つの構文です。
それは、

1. 「さけるチーズを避けるチーズ」
2. 「裂けてるチーズ」
3. 「Xに捧げるY」
4. 「チーズとさけるチーズと地図のある地、伊豆」

の4つです。
そしてこの言語の唯一の原則は、以上の語句が現れたタイミングで、自然の摂理に従った置き換えを行うという事です。

第一法則:さけるチーズを避けるチーズ

まずは「さけるチーズを避けるチーズ」。
「Yを避けるX」という語句が現れたら、「X」に置き換えます。
なぜならば、YはXに避けられ、結果としてXが残るからです。これが第一の法則です。

例えば

「「Yを避けるX」を避けるZ」を避ける「Aを避ける「Bを避けるC」」

という構造物は、第一の法則に従って

「「Yを避けるX」を避けるZ」を避ける「Aを避ける「Bを避けるC」」
= 「Aを避ける「Bを避けるC」」
= 「Bを避けるC」
= C

のように変形できるため、「「Yを避けるX」を避けるZ」を避ける「Aを避ける「Bを避けるC」」の実行結果(評価結果)はCという事になります。

第二法則:裂けてるチーズ

続いて、「裂けてるチーズ」です。
「裂けてるX」という語句が現れたら、「X」に置き換えます。
なぜならば、裂けたXはやがて自らの力で修復され、元に戻るからです。これが第二の法則です。

例えば、

「「Yを避けるX」を避けるZ」を避ける「裂けてる「Aを避ける「「裂けてるB」を避ける「裂けてるC」」」」

は、第一・第二の法則を合わせて

「「Yを避けるX」を避けるZ」を避ける「裂けてる「Aを避ける「「裂けてるB」を避ける「裂けてるC」」」」
= 「裂けてる「Aを避ける「「裂けてるB」を避ける「裂けてるC」」」」
= 「Aを避ける「「裂けてるB」を避ける「裂けてるC」」」
= 「裂けてるB」を避ける「裂けてるC」
= 「裂けてるC」
= C

となり、「「Yを避けるX」を避けるZ」を避ける「裂けてる「Aを避ける「「裂けてるB」を避ける「裂けてるC」」」」の実行結果はCとなります。

第三法則:Xに捧げるY

さて、ここで事態は少し複雑になります。
この構文を説明する前に、この世界(言語)に関する重要な定めについて話す必要があります。それは、この世界には触れてはならぬ禁断の者が3人存在するということです。彼らはすなわち、「さけるチーズ」「チーズ」「地図」です。
そして実は、先ほどの第一、第二の法則、そして続く第四の法則では、これら禁断の者本人が存在する場合、置き換えを行ってはなりません。
例えば、

「Aを避ける「Bを避けるチーズ」」
= 「Bを避けるチーズ」
≠ チーズ  (※禁断の者を含む構造物を変形してはいけない!)

と変形されます。
まず、一行目から二行目の変形は許されています。「Bを避けるチーズ」は禁断の者本人ではないため、「Aを避ける「Bを避けるチーズ」」は変形が可能なのです。
しかし、第二行目において「チーズ」は禁断の者であることから、これ以上変形ができません。

同様に、

裂けてる「「裂けてるチーズ」を避ける「Aを避ける「「裂けてるチーズ」を避けるチーズ」」」
= 「裂けてるチーズ」を避ける「Aを避ける「「裂けてるチーズ」を避けるチーズ」」
= 「Aを避ける「「裂けてるチーズ」を避けるチーズ」」
= 「裂けてるチーズ」を避けるチーズ
≠ チーズ  (※禁断の者を含む構造物を変形してはいけない!)

のようになります。最後の一つ手前の行では、構造物が禁断の者チーズを含んでいるためこれ以上変形できません。

さて、ここで「Xを捧げるY」という構文が登場します。
「Xを捧げるY」は、「Xに含まれる最強の禁断の者を、Yで置き換える」という規則です。
禁断の者たちの強さの順番は、禁断の者の強さの順は「チーズ>さけるチーズ>地図」となっています。

例えば、

「さけるチーズを避けるチーズ」に捧げるXに捧げるY
= 「さけるチーズを避けるX」に捧げるY
= 「Yを避けるX」
= X

となり、この構造物の値はXとなります。
また、

「Aを避ける「Bを避けるチーズ」」に捧げるX
= 「Bを避けるチーズ」に捧げるX
= 「Bを避けるX」
= X

となります。
1行目から2行目の変形では、第一項(「Aを避ける「Bを避けるチーズ」」)の最上層部には禁断の者は存在しないため、「に捧げるX」は発動しません。
第二項内部の第二項「チーズ」は、1行目の最上層には存在しないため、禁断の者としてカウントされません。
しかし2行目にたどり着くと、第一項(「Bを避けるチーズ」)が変形できない形になっています。
ここで、「に捧げるX」という構文によって、2行目から3行目にかけて禁断の者チーズがXに置き換えられました。
そして第一の法則によって、最終的にこの値はXとなっています。

また、捧げ物同士で捧げあってはいけません。例えば、

「さけるチーズを避けるチーズ」に捧げるXに捧げるY
= Yを避けるX  (※正しい変形)

「さけるチーズを避けるチーズ」に捧げるXに捧げるY
≠ 「さけるチーズを避けるチーズ」に捧げる「Xに捧げるY」 (※間違い!)
= さけるチーズを避ける「Xに捧げるY」 (※結果が正しい変形の場合と異なってしまっている)

ということです。(つまり、「〜に捧げる」は左結合な演算子です。)

(補足)
禁断の者を、以下のように空欄で置き換えると、この法則が明快になります。

「裂けてる「「裂けてるチーズ」を避ける「さけるチーズを避ける「さけるチーズを避けるチーズ」」」」に捧げるXに捧げるY
↓
「裂けてる「「裂けてる__1」を避ける「__1を避ける「__2を避ける__1」」」」に捧げるXに捧げるY

この構造物は、

「裂けてる「「裂けてる__1」を避ける「__1を避ける「__2を避ける__1」」」」に捧げるXに捧げるY
= 「「裂けてる__1」を避ける「__1を避ける「__2を避ける__1」」」に捧げるXに捧げるY
= 「__1を避ける「__2を避ける__1」」に捧げるXに捧げるY
= 「Xを避ける「__2を避ける__1」」に捧げるY
= 「__2を避ける__1」に捧げるY
= 「__2を避けるY」

と変形されます。
つまり、禁断の者に関するルールは、最上層に空欄が存在する構造物は変形してはいけないという事になります。

第四法則:「チーズとさけるチーズと地図のある地、伊豆」

さて、この法則がさけるチーズにおいて最も複雑な法則になります。
神聖なる地、伊豆では、古来から物を捧げる文化が発達してきました(要出典)。
そんな伊豆にまつわる第四の法則における変換規則は

「XとYとZのある地、伊豆」
= Xに捧げるZに捧げる「Yに捧げるZ」

です。
例えば、

「「さけるチーズを避けるチーズ」と「さけるチーズを避けるチーズ」と「裂けてるチーズ」のある地、伊豆」
= 「さけるチーズを避けるチーズ」に捧げる「裂けてるチーズ」に捧げる「さけるチーズを避けるチーズ」
= 「さけるチーズを避ける「裂けてるチーズ」」に捧げる「さけるチーズを避けるチーズ」
= 「「さけるチーズを避けるチーズ」を避ける「裂けてるチーズ」」
= 裂けてるチーズ

となり、答えは「裂けてるチーズ」となります。

さけるチーズによるプログラミング

さけるチーズの全ての文法が出揃った所で、さけるチーズによる実際のプログラミング方法を解説しながら、さけるチーズで実際にプログラミングが可能であることを示したいと思います。
具体的には、

  • 自然数の表現
  • 加算と累乗
  • リストの表現
  • Hello, World!プログラム

を扱います。
続きは、次の記事で!
woodrush.hatenablog.com

Configuring and Installing TensorFlow for Non-Titan GPUs

TensorFlow officially supports GPUs with versions greater than the GeForce GTX TITAN. However, it is possible to configure and install TensorFlow for GPUs before Titan, such as the GeForce GTX 960 (which I have used for verification) by using "unofficial settings" that are not tested and supported (but is mentioned on the official installation instructions).

TensorFlow's official GPU compatibility is mentioned in the "Optional: Install CUDA (GPUs on Linux)" section in the TensorFlow installation instructions
https://www.tensorflow.org/get_started/os_setup.html#installation-for-linux:

TensorFlow GPU support requires having a GPU card with NVidia Compute Capability >= 3.5. Supported cards include but are not limited to:

However, as mentioned in the "Enabling Cuda 3.0" section, we can configure and install TensorFlow for non-Titan GPUs by using "unofficial settings" during the configuration.

Caution: as it is called as "unofficial," this method is "largely untested and unsupported," meaning that the installation may be glitchy. This is mentioned in the following message that appears during the `./configure` part in the installation:

WARNING: You are configuring unofficial settings in TensorFlow. Because some
external libraries are not backward compatible, these settings are largely
untested and unsupported.

A Japanese version of this entry can be found here: http://qiita.com/woodrush/items/67703153541ce869e3dc

Installation

Build from source, according to the official installation guide
https://www.tensorflow.org/versions/master/get_started/os_setup.html:

  1. Follow each step in the "Installing from sources" section before the "Configure the installation" step
  2. Follow the "Enabling Cuda 3.0" section and ./configure the "unofficial settings"
  3. Follow the "Create the pip package and install" to create a pip wheel and install TensorFlow from the wheel
    • (This step is required only when installing in virtual python environments such as pyenv, virtualenv, etc. When installing TensorFlow for the system's Python environment, follow the instructions in "Build your target with GPU support" section instead.)

I used a Geforce GTX 960, Ubuntu 15.04 PC setup for verifying these steps. I tested the "Neural Art in TensorFlow" repo for testing functionality: woodrush/neural-art-tf · GitHub.