
2026/05/15 20:02
ポケモンを用いた Prolog の基礎解説
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
元の要約は良いが、特定の Prolog 構文の詳細やデータ例についてやや曖昧になっている。変数名の慣用表記と具体的な例を含めることで、主要な物語を変更せずに忠実度を向上させることができる。
改善された要約: 2026 年 1 月に作成されたこの Scryer Prolog プロジェクトは、Bruce Tate の『七週間で seven Languages』を基盤としており、Pokémon の戦闘メカニクスをシミュレートすることで言語論理的拡張性を示すことを目的としている。系統が異なる 1,025 種以上のポケモン(ブイバサウール #1 からペチャラント #1025)を読み込み、6 つのポケモンのパーティをシステム上でモデル化し、タイプ相性ルールに基づいてスーパーエフェクティブな攻撃は 2 倍ダメージ、免疫状態では 0 ダメージを与えるように実装する。Prolog では大文字で始まる変数(例:
Type, Pokemon)を用いて統一操作を通じて複雑な問い合わせ(水系かつ氷属性かつ高特攻を持つポケモンの一覧取得など)を処理し、著者はこれを冗長になる SQL よりも簡潔だと評価している。ロジックエンジンでは、積層されたタイプ修飾子(例:シザークロスが火属性攻撃に対して 4 倍ダメージを受けるケース)や優先度メカニクス(->/2 コンストラクトを使用して、プラインクスター能力のターン順序効果を実装)を処理する。著者は \+/2 および ->/2 が厳密な Scryer ガイドラインから逸脱していることに留意しつつも、必要な表現力のためにこれらを利用し、静的スプレッドシートよりも動的事実に基づく戦闘結果の分析が可能であるためロジックベースのアプローチを好む。
- 不足している要素(ある場合):特にない;具体的な例が含まれている。
- 推測/飛躍(ある場合):改訂版では新たなものはいっさい導入されていない。
- 改善された要約(必要であれば、それ否则元のまま):上記の改善版はキーポイントリストのカバーをより良くしつつ明晰さを維持している。
本文
非意図的な陳腐化(Unplanned Obsolescence)
2026 年 1 月 5 日
この記事の靈感をあたえたプロジェクトは少々滑稽でもあります——私は子供向けのビデオゲームの仕組みについて、極めて詳細に説明しようとしていますから—but この特定の課題こそが、ブルース・テート(Bruce Tate)氏の『セブン・ランゲイジャーズ・イン・セブン・ウィークス』を読み始めて以来追いかけていた私の「ひらめき」をようやくプロログ(Prolog)で得させる決定的な要因となりました。この演習は、やや実用的なドメインにおいて構築しようとしているインターフェースの種類について多くのことを教えてくれました。特定の種類の関係において、論理プログラミングは私がこれまで使用したプログラミングシステムの中で圧倒的に簡潔かつ表現力が高いものです。なぜそうなのかを理解するために、ポケモンについてお話ししましょう。
ポケモンの基礎知識
ポケモンとは、人間と多種多様の色彩豊かな動物キャラクターたちが共生する世界を舞台にしたビデオゲームシリーズであり、またマルチメディア franchises やライフスタイルブランドです。「Pokémon」という名称は、フランチャイズ名そのものと同時に、個々の固有の種名を持つこれらの動物キャラクター自体に対する一般用語としても使われます。ポケモンの種類は 1,000 を超えるものであり、ピカチュウ(#25)からペチャールント(#1025)まで存在します。
人気のあるポケモン(左から右へ):
- ピカチュウ(#25)、アーケオプス(#567)、ディップリン(#1101)。
現在ではさまざまな種類のポケモンゲームがありますが、メインシリーズの核心は常に「ポケモンの捕獲」と「戦闘」にあります。戦闘中、あなたの 6 匹のポケモンチームが敵チームに対峙します。各ポケモンは通常、相手をダメージを与えるために選択できる 4 つの技を装備しています。あなたが相手側から攻撃される前に、相手の全ポケモンの HP(ヒットポイント)をゼロにする必要があります。各ポケモンは独自の特性を持ち、それがどのように戦うかに影響します。それらは基本ステータスのセット、多くの技の候補、数々の能力、そしてタイプを持っています。以下で確認すると思いますが、ここにある組み合わせの数々は膨大であり、その追跡を試みる software 化の動機となっています。
スカジール はバグ・スチール(鋼)タイプのポケモンであり、攻撃力が高く速度が低いです(Smogon を参照)。
タイプは特に重要です。技には「炎」や「岩」のようなタイプがあり、ポケモンも最大 2 つのタイプを持つことができます。相手のポケモンに対して超有効なタイプを持つ技はダメージを 2 倍にし、逆にあまり効かないタイプを持つ技は半分のダメージしか与えません。これについて例を挙げて説明すると分かりやすくなります。炎タイプの技「フラメット(火炎放射)」は草タイプには 2 倍のダメージを与えます。それは草が炎に弱いからですが、一方、水タイプの技「サーフィン」はその草ポケモンに対しては半分のダメージしか与えません。これは草が水に耐性があるためです。
ルナトーン は岩・ Psychic(超能)タイプです。岩タイプは水タイプに弱いため、かつ超能タイプは水タイプに対して中立であるため、「サーフィン」はこのポケモンには 2 倍のダメージを与えます。
タイプ修飾子は積み上がります。スカジールはバグとスチールの複合タイプですが、両方とも炎タイプに弱いため、炎タイプの技はスカジールに対して 4 倍のダメージを与えます。電気タイプは水タイプに弱くなりますが、地面タイプには免疫があるため、もしあなたが地面・水の Swampert(沼河豚)に対して電気タイプの技を使用した場合、0×2 が依然として 0 であることからゼロのダメージしか与えません。もちろん、これらの関係を保つためのチャートも存在します。
ポケモンタイプ表(Wikimedia より)
これが私が 8 歳の頃、ポケモンビデオゲームの仕組みを理解していた時点での有効なメカニズムです。ダメージを与えたい技をクリックし、类型上の有利な対照を持つ技を探してクリックしてみてください。これらのゲームは子供向けのものであり、表面的にはそれほど難しくないのです。
プロログの基礎知識
ポケモンのメカニズムが内部でどのように複雑になるかを説明する前に、まず論理プログラミングの仕組みについて説明する必要があります。ポケモンは論理プログラミングとの相性が非常に良い理由は、ポケモンの戦闘は本質的には極めて精巧なルールエンジンだからです。まずは、多くの事実を含むファイルを作成して始めるしましょう。
pokemon(bulbasaur). pokemon(ivysaur). pokemon(venusaur). pokemon(charmander). pokemon(charmeleon). pokemon(charizard). pokemon(squirtle). pokemon(wartortle). pokemon(blastoise).
プロログでは「述語(predicates)」を宣言します。述語は関係性を定義します:bulbasaur はポケモンであり、charmander もポケモンであるなどです。この述語を
pokemon/1 と呼びます。述語の名前は「pokemon」で、引数は 1 つあるためです。これらの事実は、「トップレベル(top-level)」と呼ばれる対話式のプロンプトに読み込まれます。
トップレベルへのクエリは、プロンプトに文を入力して実行することで行い、プロログはその文が真になるすべての方法を求めようとします。複数の解決策がある場合、トップレベルは最初の解決策を表示し、ユーザーの入力を待機します。その後、もう一つの解決策を表示させたり、すべての解決策を表示させたり、あるいは完全に停止させることも可能です。
この最初の例では、
pokemon(squirtle). と入力して Enter を押すと、トップレベルは「true」と返信します。スカルートルは確かにポケモンなのです。
?- pokemon(squirtle). true.
すべてのものはポケモンではありません。
?- pokemon(alex). false.
ここにポケモンのタイプを追加しましょう。述語
type/2 を使用します。
type(bulbasaur, grass). type(bulbasaur, poison). type(ivysaur, grass). type(ivysaur, poison). type(venusaur, grass). type(venusaur, poison). type(charmander, fire). type(charmeleon, fire). type(charizard, fire). type(charizard, flying). type(squirtle, water). type(wartortle, water). type(blastoise, water).
前述の通り、一部のポケモンは一つのタイプのみを持ち、他のポケモンは二つのタイプを持っています。後者の場合は、2 つの type 事実にモデル化されます。bulbasaur は草タイプであり、かつ毒タイプでもあります;両方とも真です。このパラダイムは、SQL データベースにおける One-To-Many(1 対多)の関係と似ています。
対話的に、スカルートルが水タイプであるかを確認できます。
?- type(squirtle, water). true.
スカルートルが草タイプであると述べることはできるでしょうか?
?- type(squirtle, grass). false.
いいえ、スカルートルは水タイプだからです。もしスカルートルのタイプが分からない場合でも、尋ねることができます!
?- type(squirtle, Type). Type = water.
プロログでは、大文字から始まる名前は変数です。プロログは、その変数に対して可能なすべてのマッチと述語を「統一(unify)」しようとします。ただし、この特定の述語が真になる方法は一つだけです:Type は水である必要があります。なぜならスカルートルの唯一のタイプは水だからです。二つのタイプを持つポケモンの場合、述語は二度にわたり統合されます。
?- type(venusaur, Type). Type = grass ; Type = poison.
意味論的には、3 行目にあるセミコロン(;)は「または」を意味します。
type(venusaur, Type) は Type = grass または Type = poison の場合に真となります。どの項も変数となり得るため、質問はあらゆる方向に行うことができます。草タイプは何でしょうか?単純に第一引数を可変にして、第二引数を「grass」に設定すればよいです。
?- type(Pokemon, grass). Pokemon = bulbasaur ; Pokemon = ivysaur ; Pokemon = venusaur ; Pokemon = oddish ; Pokemon = gloom ; Pokemon = vileplume ; Pokemon = paras ; Pokemon = parasect ; Pokemon = bellsprout ; ... .
私は途中で切りましたが、トップレベルは喜んで 164 つすべてをリスト表示してくれます。カンマを使用して複数の述語をリスト化できます——プロログはすべての真となるように変数を統一します。水と氷の両方のタイプを持つポケモンをリストするには、両方の条件を満たす存在するポケモンを尋ねるだけです。
?- type(Pokemon, water), type(Pokemon, ice). Pokemon = dewgong ; Pokemon = cloyster ; Pokemon = lapras ; Pokemon = laprasgmax ; Pokemon = spheal ; Pokemon = sealeo ; Pokemon = walrein ; Pokemon = arctovish ; Pokemon = ironbundle ; false.
Pokemon が変数であっても、クエリの文脈において両方のインスタンスは同じものでなければならない(代数学と同じようにです)。クエリは、両方の述語が成立する Pokemon の値のみで統合されます。例えば、水・氷タイプの Dewgong は解決策となるのは、プログラムに以下の二つの事実が含まれているためです:
type(dewgong, water). type(dewgong, ice).
したがって、
Pokemon 変数に dewgong を代入するだけでクエリを満たします。一方、スカルートルは水タイプのみであるため、pokemon(squirtle, water) は存在しますが、pokemon(squirtle, ice) は存在しません。クエリは両方の統合を必要とするため、squirtle は Pokemon の可能な値ではありません。
ポケモンには操作できる多くのデータがあります。Iron Bundle は強力な水・氷タイプのポケモンであり、特攻が非常に高いです。具体的にはどれほどでしょうか?
?- pokemon_spa(ironbundle, SpA). SpA = 124.
これほど高い特攻を持っているため、強力な特殊技を使用したいと考えています。Iron Bundle はどのような特殊技を知っていますか?
?- learns(ironbundle, Move), move_category(Move, special). Move = aircutter ; Move = blizzard ; Move = chillingwater ; Move = freezedry ; Move = hydropump ; Move = hyperbeam ; Move = icebeam ; Move = icywind ; Move = powdersnow ; Move = swift ; Move = terablast ; Move = waterpulse ; Move = whirlpool.
Freeze-Dry は特に優れた特殊技です。特攻が 120 よりも大きく、かつ Freeze-Dry を覚える氷タイプのすべてのポケモンをクエリしてみましょう。
?- pokemon_spa(Pokemon, SpA), SpA #> 120, learns(Pokemon, freezedry), type(Pokemon, ice). Pokemon = glaceon, SpA = 130 ; Pokemon = kyurem, SpA = 130 ; Pokemon = kyuremwhite, SpA = 170 ; Pokemon = ironbundle, SpA = 124 ; false.
さらに進む前に最後の概念:ルール。ルールには頭部(head)と体部(body)があり、体部が真の場合に統合されます。技は「物理攻撃」または「特殊攻撃」のいずれかであれば、ダメージを与える技として扱われます。
damaging_move/2 述語は、直接ダメージを与えるすべての技を定義します。
damaging_move(Move) :- move_category(Move, physical) ; move_category(Move, special).
これは、直接ダメージを与えるあらゆる技と統合されます。
?- damaging_move(tackle). true. ?- damaging_move(rest). false.
SQL との比較
これまでに私が提示したのは、論理的に非常に野心的ではありません——単に「かつ」や「または」による事柄についてのステートメントです。本質的には格好いい参照テーブル罢了(glorified lookup table)です。それでも、一息ついてこのデータベースを SQL の代替案よりも便利にクエリできることを感謝してください。見せてきた事実に対して、私はおそらく次のような SQL テーブルを設定するでしょう:
-- 他のステータスは簡潔にするために省略 CREATE TABLE pokemon (pokemon_name TEXT, special_attack INTEGER); CREATE TABLE pokemon_types(pokemon_name TEXT, type TEXT); CREATE TABLE pokemon_moves(pokemon_name TEXT, move TEXT, category TEXT);
そして、次のようにクエリします:
SELECT DISTINCT pokemon, special_attack FROM pokemon as p WHERE p.special_attack > 120 AND EXISTS ( SELECT 1 FROM pokemon_moves as pm WHERE p.pokemon_name = pm.pokemon_name AND move = 'freezedry' ) AND EXISTS ( SELECT 1 FROM pokemon_types as pt WHERE p.pokemon_name = pt.pokemon_name AND type = 'ice' );
比較のために、同等のプロログクエリをもう一度示します:
?- pokemon_spa(Pokemon, SpA), SpA #> 120, learns(Pokemon, freezedry), type(Pokemon, ice).
SQL を非難しているわけではありません——私は SQL が大好きです—but、それが高水準の宣言的クエリ言語であり、多くの人々が使用するものです。私が驚いているのは、Prolog バージョンがいかにしてシンプルで柔軟性があるのかということです。もし我々が続けて子句を加えたら、SQL クエリは管理不能に複雑になり得ますが、プロログのクエリは変数の使い方に慣れると、読みやすく編集しやすいままです。
レベルアップ
基礎が確立されたところで、私が取り組んでいるプロジェクトに関する文脈を示します。ポケモンの戦闘には、すべてが複雑かつ確率的な方法で相互作用する過剰な数のメカニズムがあります。これらのゲームの魅力の一つは、すべての情報を頭の中に保持しようとする徒労(あなた方がより良い予測を立てるために)であり、それを利用して相手の計画を凌駕し、回避することです。それは一種の非常に滑稽なポーカーに似ています。
私がまだ言及していないゲームメカニズムの小さなサブセット:
- 一部の技は特定の割合でミスしてダメージを与えません。
- 一部の技はポケモンのステータスを上げたり下げたりします。
- ポケモンはさまざまな効果を持つアイテムを保持できます。
- ダメージ計算は一定ではありません;技は計算された範囲内で正規分布したダメージを与えます。
- ポケモンは凍結、燃焼、麻痺、毒、睡眠などの状態に陥ることがあり、これらはいずれも不利益な効果を持ちます。
- さまざまなフィールドエフェクト(天候、地形、トリックルームなど)があり、それらは技のダメージ、ターン順序、その他を改变します。
- ポケモンの各々は能力を持ち、さまざまな効果があります。例えば、Levitate は地面型の技への免疫を与え、Drizzle はポケモンがチームに交代するたびに天候を雨に変え、Sheer Force は技の副作用を無効化しながらダメージを 1.3 倍に増加させます。
- プレイヤーはゲーム前に各ポケモンへ(見えないように)ポイントを割り当てて選択したステータスを強化できます。チーム構築に応じて、それぞれのポケモンはあなたが予想する以上のダメージを与えるか、あるいは攻撃を受けられるようにすることも可能です。
このゲーム向けのソフトウェアを構築したい場合の課題は、すべてその複雑さをモデル化しながら精神を狂わせないことです。Prolog はこれに驚くほど優れています。主な理由は 2 つあります:
- クエリモデルはアドホックな組み合わせの記述において優れています。
- データモデルは一貫した方法でルールを重ねるために完璧に適しています。
それを示すために、私が実装した Pokémon draft league(ポケモンドラフトリーグ)での優先度を持つ技の方法を示します。ポケモンドラフトは名前通りです。ポケモンは優れたほどポイント価値が与えられ、各プレイヤーに使用可能な一定のポイントが割り当てられ、すべてのプレイヤーがポイントを消費するまでドラフトが続きます。あなたのチームには約 8〜11 匹のポケモンがおり、毎週リーグ内の他の一人と頭から対戦します。数年前に友人で WMI コラボレーターである Morry が私のところを招いてくれて以来、私はこの形式にハマっています。ゲームは 6v6 なので、戦闘の一部はあなたが相手に持ちうる 6 匹のすべての組み合わせに対応し、またあなたの 6 匹すべてを組み立ててそれらに対応できるように準備することです。当然のことながら、あなたはドラフトしたポケモンだけでチームを構築しかねません。
私は単にその述語の名前に
alex/1 と付けました。
alex(meowscarada). alex(weezinggalar). alex(swampertmega). alex(latios). alex(volcarona). alex(tornadus). alex(politoed). alex(archaludon). alex(beartic). alex(dusclops).
私が Freeze-Dry を覚えているポケモンはどのようなものですか?
?- alex(Pokemon), learns(Pokemon, freezedry). false.
ありません。残念。非常に重要な種類の技の一つが「優先度を持つ技」です。先ほど速度ステータスがどのポケモンが先に動くかを制御すると言いました。ちょっとしたニュアンスとしては、「最高優先度の技を使用しているポケモンが最初に動き、両者が同じ優先度の技を選択した場合、より高い速度を持つ方が先に動きます」。多くの技は優先度がゼロです。
?- move_priority(Move, P). Move = '10000000voltthunderbolt', P = 0 ; Move = absorb, P = 0 ; Move = accelerock, P = 1 ; Move = acid, P = 0 ; Move = acidarmor, P = 0 ; Move = aciddownpour, P = 0 ; Move = acidspray, P = 0 ; Move = acrobatics, P = 0 ; Move = acupressure, P = 0 ; Move = aerialace, P = 0 ; Move = aeroblast, P = 0
ああ、しかしすべてではありません!Accelerock の優先度は 1 です。Accelerock を使用するポケモンは、優先度がゼロ(またはそれ以下)の技を使用するあらゆるポケモンより先に動き、後者のポケモンがより高い速度ステータスを持っていた場合でも同様です。私は
learns_priority/3 という述語を定義し、それがポケモン、そのポケモンが覚える優先度を持つ技、そしてその技の優先度を統合します。
learns_priority(Pokemon, Move, P) :- learns(Pokemon, Move), move_priority(Move, P), P #> 0.
「私のチームがどの優先度の技を覚えているか」と問う単純なクエリは、多くの回答を返します。
?- alex(Pokemon), learns_priority(Pokemon, Move, Priority). Pokemon = meowscarada, Move = endure, Priority = 4 ; Pokemon = meowscarada, Move = helpinghand, Priority = 5 ; ... (長略) ... false.
これは技術的には正しいものの、ほとんどこれらの答えは実際には役に立ちません。Helping Hand と Ally Switch は非常に高い優先度を持っていますが、それらはダブルバトルにおいてのみ目的を持つものであり、私がプレイしているフォーマットではありません。これらを修正するために、すべてのダブルバトル技を定義して除外し、また機能上無意味な Bide も除外します。
\+/1 述語は「この目標が失敗する場合は真」であり、dif/2 は「これらの二つの項は異なる」という意味です。
learns_priority(Mon, Move, Priority) :- learns(Mon, Move), \+ doubles_move(Move), dif(Move, bide), move_priority(Move, Priority), Priority #> 0. doubles_move(helpinghand). doubles_move(afteryou). doubles_move(quash). doubles_move(allyswitch). doubles_move(followme). doubles_move(ragepowder). doubles_move(aromaticmist). doubles_move(holdhands). doubles_move(spotlight).
次の結果が得られます:
?- alex(Pokemon), learns_priority(Pokemon, Move, Priority). Pokemon = meowscarada, Move = endure, Priority = 4 ; Pokemon = meowscarada, Move = protect, Priority = 4 ; ... (一部略) ... false.
よくなりましたが、Detect のようにユーザーのダメージや状態から守る技など、優先度を持つとして扱われている技もあります。それが私が意味する「優先度を持つ技」ではありません——私は敵に驚きを与えるダメージや不利益な副作用をもたらす技(Quick Attack や Sucker Punch など)に関心があります。
learns_priority(Mon, Move, Priority) :- learns(Mon, Move), \+ doubles_move(Move), \+ protection_move(Move), Move \= bide, move_priority(Move, Priority), Priority #> 0. protection_move(detect). protection_move(protect). protection_move(kingsshield). protection_move(burningbulwark). protection_move(spikyshield). protection_move(banefulbunker). protection_move(endure). protection_move(magiccoat).
これらのルールを設定した後、非常に役立つ答えに達します!
?- alex(Pokemon), learns_priority(Pokemon, Move, Priority). Pokemon = meowscarada, Move = quickattack, Priority = 1 ; Pokemon = meowscarada, Move = suckerpunch, Priority = 1 ; Pokemon = beartic, Move = aquajet, Priority = 1 ; Pokemon = dusclops, Move = shadowsneak, Priority = 1 ; ... (一部略) ... false.
さらに有用なのは、その週の敵がどの優先度の技を持っているかを調べることです。
?- morry(Pokemon), learns_priority(Pokemon, Move, Priority). Pokemon = mawilemega, Move = snatch, Priority = 4 ; ... (一部略) ... false.
この時点で、私はこのプログラムを Morry に示しましたが、彼は私に挑戦を投げてくれました。Prankster という能力を持つポケモンはステータス技に対して追加の +1 の優先度を得ます。このルールを拡張してそれを注記することもできるでしょうか?私には恰好そのようなポケモンがチームにいるのでした。
?- alex(Pokemon), pokemon_ability(Pokemon, prankster). Pokemon = tornadus ; false.
これはプロログの if/then 構造、
->/2 を使用して 3 分でできました。
learns_priority(Mon, Move, Priority) :- learns(Mon, Move), \+ doubles_move(Move), \+ protection_move(Move), Move \= bide, move_priority(Move, BasePriority), ( pokemon_ability(Mon, prankster), move_category(Move, status) -> Priority #= BasePriority + 1 ; Priority #= BasePriority ), Priority #> 0.
これで同じクエリは、Tornadus のすべてのステータス技を含み、それらの増えた優先度も示されます。
?- alex(Pokemon), learns_priority(Pokemon, Move, P). Pokemon = meowscarada, Move = quickattack, P = 1 ; ... (一部略) ... Pokemon = tornadus, Move = snowscape, P = 1 ; ... (一部略) ... false.
シート(スプレッドシート)には何かがあった
冒頭で、この体験がどのようなインターフェースを構築したいかについての教訓を与えてくれたと言いました。その学習の一つは非常に明白です:Prolog は若干不器用かもしれませんが、ここでは説明されたような関係のようなものを表現・クエリするためのエレガントな言語です。これは、あなた像我が宣言的な DSL の慎重な使用に関心がある場合にインパクトがあります。他の教訓は、プログラマー以外の人々がどのようなツールを使うべきかというものです。私が「敵のチームの優先度の技を知っておけるのは素晴らしいことだ」と思わなかった最初の人間でもありません。ポケモンコミュニティには、すべての時間の最高のプログラミングインターフェースである——すなわち、謙虚なスプレッドシート上に構築された——このようなリソースがあります。
また、より美しく見えるためです。
私は「Techno の Prep Doc」のコピーを使用しており、それは時に野生の中で出会えるような spectacularly-advanced Google シートの一つです。チームを入力すると、マッチアップについての大量の有用な情報を生成します。これは素晴らしいインターフェースを持ち、各種フォーマットのサポート、スキャン可能なビジュアル、そして自動補完を備えています。私は優先度の技を見つける式について気になったのでした。それは gnarly(複雑で恐ろしい)です。
={IFERROR(ARRAYFORMULA(VLOOKUP(FILTER(INDIRECT(Matchup!$S$3&"!$AV$4:$AV"),INDIRECT(Matchup!$S$3&"!$AT$4:$AT")="X"),{Backend!$L$2:$L,Backend!$F$2:$F},2,FALSE))),IFERROR(FILTER(INDIRECT(Matchup!$S$3&"!$AW$4:$AW"),INDIRECT(Matchup!$S$3&"!$AT$4:$AT")="X"))}
少しクリックするだけで、私は基本的にこれが何を行うか理解することができました。「Backend」というシートがあり、すべての技をリストしています。それは本質的に私のプロログクエリのハードコードされたバージョンです。
検索式はいくつかのフィルタリング、VLOOKUP、そして一種のプロンプトプログラミング(INDIRECT がセル参照を返す)を行い、あなたのチームにある Backend リストに存在するすべてのポケモンを見つけ、表示します。私個人が、このデータベースをスプレッドシートの VLOOKUP で実装したものではなく、プロログで実装されたバージョンで作業することを好む理由は数多くあります。私は既存のポケモンツールキットが達成できないことを行う Web アプリケーションを構築予定です。(scryer-prolog が WASM にコンパイルされる日が来るなら。)さらに、Prolog パラダイムは明らかにより拡張可能です。スプレッドシートのバックエンドは顕著な技のリストにハードコードされていますが、私のデータベースはあらゆる技を検索できます。
私はまだこのクエリに完全に確信していない——Justin のチームのどのメンバーに対しても Tornadus が覚えるすべての特殊攻撃を特定する——そのようなものは私が知っているどのツールにも存在しません——それは通常、タブを無限に切り替えることで解こうとします。私のプログラムによって確立された文法を使って、私は 30 秒程度でこれを組み立てました。
?- justin(Target), learns(tornadus, Move), super_effective_move(Move, Target), move_category(Move, special). Target = charizardmegay, Move = chillingwater ; Target = terapagosterastal, Move = focusblast ; Target = alomomola, Move = grassknot ; Target = scizor, Move = heatwave ; Target = scizor, Move = incinerate ; Target = runerigus, Move = chillingwater ; ... (一部略) ... false.
私は構造化プログラミングがスプレッドシートよりもより拡張可能であるかどうかには興味ありません。なぜ私がすべてのプログラミングをスプレッドシートで行わないのかの理由については既に知っています。
={IFERROR(ARRAYFORMULA(VLOOKUP(FILTER(INDIRECT(Matchup!$S$3&"!$AV$4:$AV"),INDIRECT(Matchup!$S$3&"!$AT$4:$AT")="X"),{Backend!$L$2:$L,Backend!$F$2:$F},2,FALSE))),IFERROR(FILTER(INDIRECT(Matchup!$S$3&"!$AW$4:$AW"),INDIRECT(Matchup!$S$3&"!$AT$4:$AT")="X"))}
私は非常に重要な質問を見つけます:この特定の課題と、それを解決しようとした人々の性質において、最もよく維持されている解決策がスプレッドシートであるのはなぜでしょうか。
世界にはそれ подобногоの問題が無数にあり、そのプログラミングパラダイムに対する多くの改善がまだ正しく実装されていないと考えています。
注記
このブログ記事の原稿を読んでいただいた Morry Kolman 氏に感謝します。
- ドラフトリーグにはシーズン 3 で参加し、決勝で敗れた後、シーズン 4 と 5 で優勝しました。ちょうどシーズン 6 を始めました。あなたが欲しいのであれば、王冠を持つことができます。
- このドラフトリーグには多くの開発者がおり、正確にゼロ人の彼らに私のプロログプログラムを試していただくことができました。しかしそれはむしろポイントです!これはウェブサイトである必要があります…
- 私で使用している Prolog インプリメンテーションは Scryer Prolog で、標準化と形式的な正しさを強調する現代的な Prolog インプリメンテーションです。創始者の Markus Triska は素晴らしいオンライン書籍「The Power of Prolog」とそれを伴う YouTube チャンネルがあり、それは数週間私の朝食の背景音楽となりました。
- Scryer Prolog も論理的完全性と単調性を保持する構文をより多く促すように設計されており、私は
や\+/2
述語を実際に使用すべきではないという意味です。しかし、代わりに提供されるものを使いながら何が欲しいかを表現することができませんでした。もし誰かが助けたいと考えていれば、喜んで編集します。->/2 - また、Markus のウェブサイトで:「私の目標は意図通りに、信頼性高く、便利に動作するプログラムを提供することです。クラッシュやリソースリークなどの予期せぬ動作なしで、数十年間問題なく実行できるプログラムを。」この人とは私と似た興味を持っています!
- 私は Pokémon Showdown NodeJS API を使用して、すべてのデータを Prolog 述語に取得するための楽しいメタプログラミングを行いました。
- はい、コードブロックを除くすべての場所で「e」上にアクセントを入れるのは非常に面倒でした。