キーワード能力 – オラクル解析 vol.2
前回はなんやかんやして javascript(以下:JS)で受け取る、カード情報のオブジェクトを設計する所までやりました。
直ぐにでもカードデータをぶち込んでみたい衝動に駆られていますが、先にキーワード能力に反応して仕分けする仕組みを作っていきます。
取り合えず JSON で定義しておく
テキストを分解した時に得られる英文から、真っ先にキーワード能力を拾う事で「少しでも解析する部分を少なくしよう!」と言う作戦だ。
とは言え、キーワード能力に定義された挙動の実装をしていては、永遠に前に進まないのでとりまリストだけ作るのが良さそう。
解析結果をデータベースに放り込むなら、サーバサイドのスクリプトで処理するのが楽だけど、JS 側でも使う事を想定して JSON で作っておこう。
甘く見てた
ゆうてすぐにできるじゃろと高を括っていたハズが、Wiki を開いたら
私のキーワード能力は 164 個です。
とか書いてて、作業をするために感情を生け贄に捧げるコストを要求されました。
{
"Activated": {
"Equip": {
"instant": false,
"instructions": ["Battlefield"]
},
"Fortify": {
"instant": false,
"instructions": ["Battlefield"]
},
"Aura Swap": {
"instant": true,
"instructions": ["Battlefield"]
},
/* 以下 160 キーワードぐらい略 */
}
}
これ、一つのキーワード能力の中に複数のタイプ(常在型能力と誘発型能力とか)が混ざってたり、もうほんと変な汗出るぐらいややこしかったので、ザックリとした定義だけに留めました。
キーワード能力ヤバイ。
今の所、先が思いやられる要素しかない。
いいや!限界だ押すね!
延々と単純作業を繰り返してきた管理人の我慢は臨界点をとうに超えている、つまり限界です。
取り合えずどうなるか見たい、とにかく見たいと言う衝動を抑えつつ、ここで最後の踏ん張り。
約2万5千枚のデータでフルパンしたら「何が起こっているか分からん」が起こってしまうからだ。
取り合えずそうだね、MTG は土地を置く事から始まるゲーム(例外は有るけど)だから、適当に土地を10枚ほど選んだリストを作成して、それを解析してみよう。
1能力=1行
テキストの解析は、まず書式の仕様確認から始まります。
有難い事に各種能力のフォーマットは Wiki に網羅されているので、もっと大枠の所を理解するだけで良さそうです。
まずは、プレーンテキストでオラクルを眺めてみよう。
{T}: Add {C}{C}. Ancient Tomb deals 2 damage to you.
{T}: Add {C}.
{T}, Sacrifice Crystal Vein: Add {C}{C}.
Flood Plain enters the battlefield tapped.
{T}, Sacrifice Flood Plain: Search your library for a Plains or Island card, put it onto the battlefield, then shuffle.
Hexproof
Lotus Field enters the battlefield tapped.
When Lotus Field enters the battlefield, sacrifice two lands.
{T}: Add three mana of any one color.
Lumbering Falls enters the battlefield tapped.
{T}: Add {G} or {U}.
{2}{G}{U}: Lumbering Falls becomes a 3/3 green and blue Elemental creature with hexproof until end of turn. It's still a land.
({T}: Add {W}.)
({T}: Add {W}.)
Razortide Bridge enters the battlefield tapped.
Indestructible
{T}: Add {W} or {U}.
({T}: Add {U} or {B}.)
(Dryad Arbor isn't a spell, it's affected by summoning sickness, and it has "{T}: Add {G}.")
カードの区切りには故意的に改行コードを2つ突っ込んでいるので、1枚のカード単位で見ると「1能力につき1行」と言うフォーマットになっているようです。
つまり改行コードでスプリットしてあげれば、そのカードの能力を配列で持つことが出来ますね。
// PHP の例
$text = explode("\n", $oracle);
print_r($text);
/*
Array
(
[0] => Hexproof
[1] => Lotus Field enters the battlefield tapped.
[2] => When Lotus Field enters the battlefield, sacrifice two lands.
[3] => {T}: Add three mana of any one color.
)
*/
ちなみに選んだカードは、上から順番に以下の通り。
- 古えの墳墓(マナ出しながらダメージを受ける土地。)
- 水晶鉱脈(二つのマナ能力を持ち、自身の生け贄がコストの土地。)
- 氾濫原(タップインのフェッチランド。)
- 睡蓮の原野(キーワード能力を持ち、なんか色々しつつ5色出る土地。)
- 伐採地の滝(タップインのミシュラン。)
- 平地(ベータ版の土地、テキストが古い。)
- 平地(最新版の基本土地、テキストレス。)
- 剃刀潮の橋(破壊不能を持つ2色ファクト土地。)
- 地底海(基本土地タイプを2つ持つデュアルランド。)
- ドライアドの東屋(とにかく変な土地。)
カッコのルーリング
パッと見で気になったのがカッコで括られている文章、基本土地2種とデュアランについては省略されている文章を表しているのだろう。
しかしドライアドの東屋、オメーは分からん。
そう言えば、たまにキーワード能力の横にカッコ付きで説明書いてるのもあったよなと思って《命取りの出家蜘蛛/Deadly Recluse》のオラクルを確認すると、こんな感じになっていた。
/*
Array
(
[0] => Reach (This creature can block creatures with flying.)
[1] => Deathtouch (Any amount of damage this deals to a creature is enough to destroy it.)
)
*/
んー、これはキーワード能力の定義内容だから、カッコの中身は無視して良いよね。
でも基本土地やデュアランのは、カッコの中身を取り出してやらないといけないよね?
ドライアドの東家…も、取り出す必要があるね。
となると、以下のような条件が正解だろうか。
- 能力テキストがカッコから始まっていたら中身を取り出す。
- 能力テキストの途中にカッコが出てきたら無視する。
カッコが2回以上出て来るとか、カッコの後ろから文章が再開するとか、そもそも省略しちゃいけない例外が出て来たらアウトだけど、まずはこのルールでやってみますか。
キーワード能力を振り分けてみる
今回のお題はキーワード能力の振り分けなので、水蓮の原野と剃刀潮の橋が上手く振り分けられるか確認する所までやりましょう。
$text = explode("\n", $oracle->text);
foreach($text as $t) {
if(preg_match("/^\(/", $t)) {
// カッコから始まるので中身を取り出す
preg_match("/\(.*\)/", $t, $temp);
$t = preg_replace("/\(|\)/", "", $temp[0]);
} else if(preg_match("/\(/", $t)) {
// カッコから始まらないがカッコを含むので中身を削除する
$t = preg_replace("/\(.*\)/", "", $t);
}
if(isset($keywords->Activated->{$t})) {
array_push($card["ability"]["_activated"], $keywords->Activated->{$t});
}
if(isset($keywords->Triggered->{$t})) {
array_push($card["ability"]["_triggered"], $keywords->Triggered->{$t});
}
if(isset($keywords->Static->{$t})) {
array_push($card["ability"]["_static"], $keywords->Static->{$t});
}
}
設計したオブジェクトのフォーマットへの整形は後回しにして、これで取り合えず2つとも常在型能力に「何か入る」と思われる。
[3] => Array
(
[name] => Lotus Field
[cmc] => 0
[manaCost] =>
[layout] => normal
[colors] => Array()
[supertypes] => Array()
[types] => Array
(
[0] => Land
)
[subtypes] => Array()
[power] =>
[toughness] =>
[loyalty] =>
[jpn] => 睡蓮の原野
[ability] => Array
(
[_spell] => Array()
[_activated] => Array()
[_triggered] => Array()
[_static] => Array
(
[0] => stdClass Object
(
[instructions] => Array
(
[0] => Battlefield
)
)
)
)
)
[7] => Array
(
[name] => Razortide Bridge
[cmc] => 0
[manaCost] =>
[layout] => normal
[colors] => Array()
[supertypes] => Array()
[types] => Array
(
[0] => Artifact
[1] => Land
)
[subtypes] => Array()
[power] =>
[toughness] =>
[loyalty] =>
[jpn] => 剃刀潮の橋
[ability] => Array
(
[_spell] => Array()
[_activated] => Array()
[_triggered] => Array()
[_static] => Array
(
[0] => stdClass Object
(
[instructions] => Array
(
[0] => Battlefield
)
)
)
)
)
うん、想定通りの振り分けが行われていますね。
ちなみにカッコはルーリングにより、以下のようなテキストになりました。
/*
{T}: Add {C}{C}. Ancient Tomb deals 2 damage to you.
{T}: Add {C}.
{T}, Sacrifice Crystal Vein: Add {C}{C}.
Flood Plain enters the battlefield tapped.
{T}, Sacrifice Flood Plain: Search your library for a Plains or Island card, put it onto the battlefield, then shuffle.
Hexproof
Lotus Field enters the battlefield tapped.
When Lotus Field enters the battlefield, sacrifice two lands.
{T}: Add three mana of any one color.
Lumbering Falls enters the battlefield tapped.
{T}: Add {G} or {U}.
{2}{G}{U}: Lumbering Falls becomes a 3/3 green and blue Elemental creature with hexproof until end of turn. It's still a land.
{T}: Add {W}.
{T}: Add {W}.
Razortide Bridge enters the battlefield tapped.
Indestructible
{T}: Add {W} or {U}.
{T}: Add {U} or {B}.
Dryad Arbor isn't a spell, it's affected by summoning sickness, and it has "{T}: Add {G}."
*/
良い感じなんじゃないでしょうか。
あとがき
実際にスクリプト上で動くときに、都合の良い形なるようにオブジェクトを設計しているつもりだけど、実際のスクリプトが存在しないのがなんとも。
そもそもキーワード能力がヤバいです、思いの外工数がエグイ。
次回はキーワード能力の定義も兼ねて、各種能力の解析をしてみたいと思います。
ディスカッション
コメント一覧
まだ、コメントがありません