私事で恐縮なのですが、昨年の1月頃よりポケモンGoを再開いたしました。そこから1年間続けているのですがポケモンGo側にも大きな機能追加がありました。それは待望のオンラインでの対戦です。興味が無かったのですが、やってみると思いの外楽しく自分でもシミュレーションや効率的な戦いを考えてみたくなります。
それならそのポケモンデータや技データはどうやって集める?という話です。
概要
- ポケモンGoのGAME_MASTER.jsonファイルの公開元を発見
- そのファイルから必要なデータをPythonにて抽出
- 生データであり追加の加工が必要
1.データ収集方法の検討
最初に思いついたのはこの方法でした。海外サイトや国内サイト含め、ポケモンGoにおけるステータスや技データなど全て公開されています。ただし、二次利用を想定しているものではないためウェブ上からスクレイピング等で取り出す方法が必要となります。
- 案1. Webサイト上からの収集
- 攻略サイト等で公開されているページからスクレイピングする方法です。
- 案2. ゲーム内のデータから抽出
- "解析"という言葉で説明されているアレです。その展開済みデータが入手できれば活用出来るのではないかと思った次第です。
2.「ゲーム内のデータから抽出」を採用
Google検索等の検索力を発揮したところ展開済みデータを公開しているレポジトリ【pokemongo-dev-contrib/pokemongo-game-master】に遭遇しました。そこで一件落着、と思ったのですがデータに余計なモノが多すぎるということでした。ポケモン、技のデータ意外にもプレイヤーの衣装や各種設定値なども含んでいます。
3.ゲーム内のデータから必要な部分を探す
さてこのファイルですがGAME_MASTER.jsonという名称で前述の通りコスチュームデータからPvP対戦の設定値、ポケモンのデータ、技のエネルギー等等といったポケモンGOの設定データの多くが含まれています。そのせいで3.4MBと大きなサイズでありムダもあります。
まずはそこから必要データを抽出していきます。
色々なデータがあるのせまずは眺めてポケモンのデータ部分を見つけます。
{
"itemTemplates": [{
"templateId": "V0001_POKEMON_BULBASAUR",
"pokemonSettings": {
"pokemonId": "BULBASAUR",
"type": "POKEMON_TYPE_GRASS",
"type2": "POKEMON_TYPE_POISON",
"stats": {
"baseStamina": 128,
"baseAttack": 118,
"baseDefense": 111
},
"quickMoves": ["VINE_WHIP_FAST", "TACKLE_FAST"],
"cinematicMoves": ["SLUDGE_BOMB", "SEED_BOMB", "POWER_WHIP"],
},
}],
ありましたね。なお、図中では今回重要と考えたデータ部分のみを抜粋しましたが、他にも様々なデータが含まれています。
ワザワザまとめるほどではないですがkey名やデータから推測し以下のようになると推測出来ます。
Key | データ内容 |
---|---|
templateId | ポケモンデータの識別子 |
pokemonId | ポケモンの名前 |
stats | 種族値 |
type | タイプ |
quickMoves | 技1 |
cinematicMoves | 技2 |
なお、このデータには期間限定の技などは含んでいないようです。
4.プログラムでのデータ抽出
ここまでくれば私よりも皆さんの方が100倍詳しいと思いますが、一応私のプログラムも載せておきます。csv形式にて使えるように各データはカンマにて区切りました。なお技データをそのまま使うと入れ子となるのが嫌だったので、::を区切り文字として無理やりくっつけています。
# -*- coding: utf-8 -*-
import json
import re
# ポケモンのデータにマッチする正規表現用パターンを用意
pattern = '^V0\d+_POKEMON_.+'
f = open('GAME_MASTER.json', 'r')
json_dict = json.load(f)
# 最上位のキーとして"itemTemplates"があるのでまずは展開する。
for json_list in json_dict["itemTemplates"]:
templateIdData = json_list["templateId"]
result = re.match(pattern, templateIdData)
# ポケモンのデータにマッチした場合に必要なデータを抽出する
if (result):
# 技データを持たないポケモンがいるのでget形式で辞書データにアクセス
# (ドーブルが技持って無かった)
quickMoves = json_list["pokemonSettings"].get("quickMoves")
quickMovesStr = ""
if quickMoves is not None:
for quickMovesStrTemp in quickMoves:
quickMovesStr = quickMovesStr + quickMovesStrTemp + "::"
cinematicMoves = json_list["pokemonSettings"].get("cinematicMoves")
cinematicMovesStr = ""
if cinematicMoves is not None:
for cinematicMovesStrTemp in cinematicMoves:
cinematicMovesStr = cinematicMovesStr + cinematicMovesStrTemp + "::"
outPokemon = json_list.get("templateId") + "," + str(json_list["pokemonSettings"].get("type")) + "," + str(json_list["pokemonSettings"].get("type2")) + "," + str(json_list["pokemonSettings"]["stats"]["baseStamina"]) + "," + str(json_list["pokemonSettings"]["stats"]["baseAttack"]) + "," + str(json_list["pokemonSettings"]["stats"]["baseDefense"])+ ',' +quickMovesStr + ',' + cinematicMovesStr
print(str(outPokemon))
実行すると標準出力に以下の形式にて出力されます。
ポケモンデータの識別子,ポケモンタイプ1,ポケモンタイプ2,種族値スタミナ,種族値攻撃,種族値防御,種族値技1,種族値技2
V0808_POKEMON_MELTAN,POKEMON_TYPE_STEEL,None,130,118,99,THUNDER_SHOCK_FAST::,FLASH_CANNON::THUNDERBOLT::
V0809_POKEMON_MELMETAL,POKEMON_TYPE_STEEL,None,264,226,190,THUNDER_SHOCK_FAST::,FLASH_CANNON::THUNDERBOLT::HYPER_BEAM::ROCK_SLIDE::SUPER_POWER::
5.残タスク
まずはポケモンのデータを生データとして取り出せました。ただし、このデータには以下のような問題があります。
(1) 日本語非対応
(2) 図鑑番号が無い
(3) アローラ、シャドウ、リライト、ノーマル(?)の整理
(4) 限定技が含まれていない
(2)-(4)は機械的にどうにか処理できそうです。(1)については図鑑番号とマッピングデータを用意できればどうにかなるかなぁ。
ただし、技データの場合はどうしよう…。
6.あとがき
APIに直接アクセスできた当初はサーチや個体値チェック、GO Plusモドキなどテック記事に溢れてました。ブームの収束と運営会社による対策により一気に下火になりましたが…。継続しプレイや解析を続けていたユーザーにただただ感謝しかありません。
おまけ
PvP時の技データは以下のようです。その中で厄介なのは**"durationTurns"**です。PvP時の技1の硬直時間[s]を表すのですが、技の硬直時間[s]=1+durationTurnsのようです。そして硬直時間が1[s]の場合にはこのkeyが無い内容でした。
VOLT_SWITCHは硬直4秒、DRAGON_BREATHは硬直1秒
"templateId": "COMBAT_V0250_MOVE_VOLT_SWITCH_FAST",
"combatMove": {
"uniqueId": "VOLT_SWITCH_FAST",
"type": "POKEMON_TYPE_ELECTRIC",
"power": 12.0,
"vfxName": "volt_switch_fast",
"durationTurns": 3,
"energyDelta": 16
}
"templateId": "COMBAT_V0204_MOVE_DRAGON_BREATH_FAST",
"combatMove": {
"uniqueId": "DRAGON_BREATH_FAST",
"type": "POKEMON_TYPE_DRAGON",
"power": 4.0,
"vfxName": "dragon_breath_fast",
"energyDelta": 3
}