ポケモンGOのPvPで強そうなポケモンをPagerankで計算してみた

# 概要
ポケモンGOのPvPが意外と面白いです．
やってるうちに強いポケモンってなんなん？？という疑問が湧いてきまして，数値的に強さみたいなものを出せたら楽しいんじゃないかと思ってこんな記事を書いています．
特に途中の過程なんて興味ねえよ！って方は一番最後の結果だけ見てもらえればと思います．

色々考えた結果，Pagerankアルゴリズムがポケモンの環境において強いやつを探すのにいいんじゃないかと思いました．

**追記: jungleルールというレギュレーションで試してみました．とてもリーズナブルな結果がでました．**

# Pagerankアルゴリズム
Pagerankは，[Google](https://google.com)が一昔前に「ウェブサイトのランキング」を計算するために用いていたアルゴリズムです．要するに**検索結果の上位に出てくるページってどんなん？**ってのを求めてくれるわけです．
簡単に言うと次のアイデアに基づいています．

- 多くのサイトから引用される（リンクを張られる）サイトは重要
- 多くのサイトから引用されるサイトが引用しているサイトはとても重要

リンク，被リンクの関係をネットワーク的に表し，グラフ理論っぽく解くと，サイトの重要性を数値で出してくれます．詳細はググればたくさん出てきますので省略．

さて，この話をポケモンのPvP環境の話に置き換えると

- 多くのポケモンに勝てるポケモンは強いポケモン
- 多くのポケモンに勝てるポケモンに勝てるポケモンはとても強いポケモン

ということになります．Pagerankでうまく表現できそうな気がしないでしょうか？科学できそうな気がします．ただし，単純に勝ち負けでネットワークを組むと，ギリギリ倒せない場合（ほぼ互角）等の条件を考慮できていないので，勝ち負けの他にHP残量の割合をエッジの重みとして追加します．

# シミュレータ
今回必要なのは「全ポケモン、全技パターンにおける勝ち負けとHP残量の割合」です．
人間がこの全パターンを試すのは不可能なわけで，当然シミュレータが必要になります．
すでに[ポケマピ](https://pokemongo-get.com/taimansym/)さん等のサイトがシミュレータを実装してくれており，僕もヘビーに利用させていただいております．ありがとうございます．
ただ，今回の場合，以下の点で問題があるといえます．

- 全パターン手入力でやるのは無理w
- スペシャル技が一つしか選べない（本来は二つ選べる）

１個目は自作すればよいとして，スペシャル技が一つしか選べないのは「全体的な強さ」を考える上で問題になります．**今の環境に適した技構成というものがあるはずだから**です．また．二つのスペシャル技を搭載したとしてもどっちを撃てばいいのか，という問題があります．いくつか例をあげてみます．(以下, n = normal attack, s1, s2 = special attack）

**「ナマズン/nマッドショット/s1どろばくだん/s2ふぶき」vs「チルタリス/nりゅうのいぶき/s1ゴッドバード/s2マジカルシャイン」**の場合，シールドを考慮しなければ二重弱点をつけるのでナマズンはふぶき一択のはずです．また，**「チャーレム/nカウンター/s1グロウパンチ/s2れいとうパンチ」vs「メガニウム/nはっぱカッター/s1ハードプラント/s2じしん」**の場合，グロウパンチ->れいとうパンチで撃つとギリギリチャーレムが勝利しますが他のパターンでは負けます．他の状況では，**どうせ死ぬなら消費の小さい技を選択して多少でも相手を削って死んだ方がいい（最後っ屁）**という状況も多々あると思います．

## 技選択アルゴリズム
というわけで技選択アルゴリズムを考えなければなりませんが，厳密に解くのは結構難しいです．というより僕には以下の点で無理でした．（もしかすると[組み合わせ最適化問題](https://ja.wikipedia.org/wiki/%E7%B5%84%E5%90%88%E3%81%9B%E6%9C%80%E9%81%A9%E5%8C%96)かもしれないとか思いはじめて諦めた、知らんけど）

- 単純にエネルギー効率の良い技を選択し続けるよりうまく削る方法があり得る
- 相手の攻撃も考慮する必要がある
- 通常技で「ためて」スペシャルを「撃つ」という機構

こうなると，全パターン列挙すればいいことになるんですが，二番目の理由から考えるのが難しかったです．頑張ればできるんだと思いますが．

そこで以下のように考えて準最適（っぽい）解を求めることにしました．
アイデアは**「各ポケモンがランダムに技を選択する，というのをどっちかが死ぬまでやる」という行動をなんども繰り返して，一番最短で相手を倒せたパターンが準最適っぽい」**というものです．
例えば先ほどの**「ナマズン/nマッドショット/s1どろばくだん/s2ふぶき」vs「チルタリス/nりゅうのいぶき/s1ゴッドバード/s2マジカルシャイン」**を考えます．
お互いがランダムに行動した場合，ナマズンは「どろばくだん、どろばくだん、ふぶき」とか「どろばくだん、ふぶき」とか「ふぶきだけ」とかいろいろ行動パターンがありますが，一番はやく倒せるのは一番初めに「ふぶき」を撃つパターンになるので，これが最適じゃない？と考えるということになります．
同じ時間で相手を倒しきれるパターンが存在した場合，生き残る側が最も少ないHPになるものを選択すれば，負けた側の最適な行動を選択できたことになります．
こう考えると，以下のメリットがあります．

- 実装が楽
- だいたい最適な行動パターンが得られる

デメリットは

- 例えばナマズンがランダム上で，一生「どろばくだん」を選択した場合，結果が間違う
- 全パターン考えるより計算時間がかかるかもしれない

とはいえ，結果がさっさと見たいのでこれでやってみることにしました．今回はシールドは考えません．あくまでシールド無しタイマン性能を考えます．

# ひとまずPythonで実装してみる
pythonで実装します．本来はPokemonクラスとかいう株ポケくらいしか実装しなさそうなものを実装したりしていますが，あまりアルゴリズム的には関係ないのでスルーします．ついでにアシッドボムとかそのへんの相手の防御を下げるやつなんかも適当に実装しときました．コアな部分だけ．

```python
import math
import random
from pokemon import Pokemon
from file_load import normal_skill_data, special_skill_data, type_comp
import sys
from pprint import pprint
MAX_REPEAT = 500

class Simulator:
    '''
    Overview: PvPのシミュレーションを行うクラス
    '''
    def __init__(self, poke1, poke2):
        '''
        Overview: 上におなじ
        params:
            poke1, poke2: pokemonクラスのオブジェクト
        '''
        self.poke1 = poke1
        self.poke2 = poke2

    @staticmethod
    def type_coeff(skiil_type, type_defender):
        '''
        Overview: 技のタイプと防御側のタイプから倍率を計算
        params: 
            skill_type : 技のタイプ
            type_defender : 防御側のタイプ, タプル
        return:
            倍率(float)
        '''
        coeff = 1.
        type_list = type_comp[skiil_type]
        for t in type_defender:
            is_batugun = t in type_list['ばつぐん']
            is_imahitotu = t in type_list['いまひとつ']
            is_mukou = t in type_list['むこう']
            if is_batugun:
                coeff = coeff * 1.6
            elif is_imahitotu:
                coeff = coeff / 1.6
            elif is_mukou:
                coeff = coeff / 1.6 / 1.6
            if type_defender[1] == None:
                break
        return coeff

    def calc_damage(self, skill, poke_attacker, poke_defender):
        '''
        Overview: 
            ダメージを計算する
            see: https://pokemongohub.net/post/pvp/ (のPvP mechanism)
        params:
            skill: 技のデータが入ってるタプル
                ('名前', bool(is_normal))
            type_attacker: 攻撃者のPokemonインスタンス
            type_defender: 防御側のPokemonインスタンス
            なお，selfはtype_coeff関数を呼ぶために必要
        return: 
            ダメージ(float)
        '''
        if skill[1] == True: # ノーマルの場合
            skill_data = normal_skill_data[skill[0]]
        else: 
            skill_data = special_skill_data[skill[0]]
        A_attacker = poke_attacker.battle_AP
        B_defender = poke_defender.battle_BP
        type_attacker = poke_attacker.get_type()
        type_defender = poke_defender.get_type()
        if skill_data['TYPE'] in type_attacker:
            type_icchi = 1.2
        else:
            type_icchi = 1.
        damage_to_defender = (A_attacker / B_defender) * \
            skill_data['DAMAGE'] * \
            self.type_coeff(skill_data['TYPE'], type_defender) * \
            type_icchi * 1.3 * 0.5 # 1.3 is only used for pvp
        return math.floor(damage_to_defender) + 1

    def get_action_list(self, poke_attacker, poke_defender):
        '''
        Overview: 相手をサンドバッグにして殺すまでランダムに行動する
        params: 
            poke_attacker: 攻撃者 (Pokemonクラスのインスタンス)
            poke_defender: サンドバッグ (おなじ)
        return:
            タプル(frame, (技名, is_normal(bool)), defenderの残りHP)
        '''

        f = 1 # frame
        used_normal = poke_attacker.get_normal_attack()
        used_normal_data = normal_skill_data[used_normal]
        action_list = []
        while poke_defender.battle_HP > 0: 
            rand = 0 if random.random() > 0.5 else 1
            try:
                used_special = poke_attacker.get_special_attack()[rand]
            except: # スペシャルの２つめがない場合怒られれば良い
                used_special = poke_attacker.get_special_attack()[0]
            used_special_data = special_skill_data[used_special]
            normal_wait_frame = 1 # ノーマルの待機時間の制御用
            # 溜まるまでループ
            while poke_attacker.energy < used_special_data['ENERGY']:
                if normal_wait_frame != used_normal_data['FRAME']:
                    normal_wait_frame += 1
                else:
                    un = (used_normal, True) # 通常と判断させるため
                    damage = self.calc_damage(un, poke_attacker, poke_defender)
                    poke_defender.decrease_HP(damage) # ダメージを与える
                    poke_attacker.update_energy(used_normal_data['EPT'])# ためる
                    action_list.append((f, un, poke_defender.battle_HP))
                    if poke_defender.battle_HP <= 0 : # 通常で殺しきった場合
                        break 
                    normal_wait_frame = 1
                f += 1
            if poke_defender.battle_HP > 0:
                # スペシャルをぶちかますが，入力に1フレーム消費する
                f += 1
                us = (used_special, False)
                damage = self.calc_damage(us, poke_attacker, poke_defender)
                poke_defender.decrease_HP(damage) # ダメージを与える
                poke_attacker.update_energy(-used_special_data['ENERGY']) # へる
                self.update_by_additional_effect(poke_attacker, poke_defender, \
                                                 used_special_data)
                action_list.append((f, us, poke_defender.battle_HP))
                f += 1 # 撃つのにも1フレ必要
        pprint(action_list)
        poke_attacker.init_battle_status()
        poke_defender.init_battle_status()
        return action_list

    def update_by_additional_effect(self, poke_attacker, \
                                    poke_defender, used_special_data):
        '''
        Overview: 追加効果による攻撃力アップなどを実現する
        params: 
            poke_attacker, poke_defender: 攻撃者と防御者
            used_special_data: スペシャル技のデータ
        '''
        add = used_special_data['ADDITIONAL'].split('_')
        if add[0] == 'SELF': # 自分の能力アップとか
            if add[1] == 'UP':
                if random.random() <= float(add[3]):
                    if 'A' in add[2]:
                        poke_attacker.update_battle_status('A', int(add[4]))
                    if 'B' in add[2]:
                        poke_attacker.update_battle_status('B', int(add[4]))
        elif add[0] == 'ENEM': # 相手の防御ダウンとか
            if add[1] == 'DOWN':
                if random.random() <= float(add[3]):
                    if 'A' in add[2]:
                        poke_defender.update_battle_status('A', -int(add[4]))
                    if 'B' in add[2]:
                        poke_defender.update_battle_status('B', -int(add[4]))

    def battle_random(self):
        '''
        Overview: 
            get_action_listを用いてランダムな行動をした場合に
            どちらが勝つかをシミュレーションする
        return: 
            タプル(loser(str), winner(str), remained_HP/pokemon_HP(float))
            最後のやつは，ページランクに投げる時に必要なため
        '''
        poke1_action = self.get_action_list(self.poke1, self.poke2)
        poke2_action = self.get_action_list(self.poke2, self.poke1)
        # 殺すのにかかったフレーム数
        p1a_last_frame = poke1_action[-1][0]
        p2a_last_frame = poke2_action[-1][0]
        last_frame = min(p1a_last_frame, p2a_last_frame)
        # UNDER CONSTRUCTION
        if p1a_last_frame == p2a_last_frame: # 相打ち
            winner = self.poke1
            winner_MAX_HP = 1 # なんでもいい
            loser = self.poke2
            remained_HP = 0
        else: # 勝敗がつく場合
            if p1a_last_frame < p2a_last_frame: # poke1 wins
                winner = self.poke1
                winner_MAX_HP = self.poke1.get_H_point()
                loser = self.poke2
                loser_act = poke2_action
            else: # poke2 wins
                winner = self.poke2
                winner_MAX_HP = self.poke2.get_H_point()
                loser = self.poke1
                loser_act = poke1_action
            # 終了時のHPを抽出
            for a in loser_act:
                if a[0] == last_frame:
                    remained_HP = a[2]
                    break
                elif a[0] > last_frame:
                    remained_HP = before[2]
                    break
                before = a # 一個前に戻る用
        return (loser, winner, remained_HP/winner_MAX_HP), last_frame
    
    def get_suboptimal_action_result(self):
        '''
        Overview: 
            self.battle_random を用いて対戦を複数回行い，
            最も効率が良い場合を採用する．
            個人的にはMAX_REPEAT は500程度でほぼ良い気がする
        return:
            (loser, winner, remained_HP, frame)
            loser, winner例　'ゴルバットnつばさでうつs1どくどくのキバs2シャドーボール'
        '''
        min_frame = float('inf')
        min_remain_HP = float('inf')
        for i in range(MAX_REPEAT):
            (l, w, r), f = self.battle_random()
            if f < min_frame or (f == min_frame and r < min_remain_HP):
                min_frame, min_remain_HP = f, r
                l_special = l.get_special_attack()
                w_special = w.get_special_attack()
                try: # 技の情報も名前に含める
                    loser_name_with_skill = l.get_pokemon_name() + 'n' + \
                        l.get_normal_attack() + 's1' + l_special[0] + \
                        's2' + l_special[1]
                except:
                    loser_name_with_skill = l.get_pokemon_name() + 'n' + \
                        l.get_normal_attack() + 's1' + l_special[0] + 's2'
                try:
                    winner_name_with_skill = w.get_pokemon_name() + 'n' + \
                        w.get_normal_attack() + 's1' + w_special[0] + \
                        's2' + w_special[1]
                except:
                    winner_name_with_skill = w.get_pokemon_name() + 'n' + \
                        w.get_normal_attack() + 's1' + w_special[0] + 's2'
                suboptimal = (loser_name_with_skill, winner_name_with_skill, r, f)
        return suboptimal
```
独自のフォーマットを使っているのでアレな部分もあるかと思いますが．
ページランクの方はnetworkxというパッケージを使えば楽チンです．

```python
import networkx as nx

def calc_pagerank_score(node_info):
    '''
    Overview: ページランクスコアを計算する
    params: 
        node_info: [(loser1, winner1, remain_HP1), (l2, w2, r2), ... ]
        の形で表されるリスト．loser, winnerはstr, remained_HPはfloat
    '''
    D = nx.DiGraph()
    D.add_weighted_edges_from(node_info)
    return nx.pagerank(D)
```

# 結果
## 自分の環境でやってみた
実際にこれらを使って僕の対戦環境でページランクスコアを計算してみます．リーグはスーパーリーグです．
僕の周辺で使われるポケモンは
「マリルリ、エアームド、トリデプス、ナマズン、デオキシスD、チルタリス、チャーレム、ドククラゲ、ゴルバット、ヤルキモノ、スカタンク、スピアー、ジュカイン、ベトベトン(アローラ)、マイナン」といったところでしょうか．これでとりあえずやってみます．
スクリプトは以下

```python
import sys
sys.path.append('../lib/')
from file_load import pokemon_and_ivs, poke_data
from pokemon import Pokemon
from simulator import Simulator
from pagerank import calc_pagerank_score
from pprint import pprint
import itertools
import sys
import json
import os
poke_names = ['マリルリ', 'エアームド', 'トリデプス', 'ナマズン', \
              'デオキシス(ディフェンスフォルム)', 'チルタリス', \
              'チャーレム', 'ドククラゲ', 'ゴルバット', 'ヤルキモノ', \
              'スカタンク', 'スピアー', 'ジュカイン', \
              'ベトベトン(アローラのすがた)', 'マイナン']
poke_list = []
for p_name in poke_names:
    normal_list = poke_data[p_name]['NORMAL_ATTACK']
    special_list = poke_data[p_name]['SPECIAL_ATTACK']
    conb = itertools.product(normal_list, itertools.combinations(special_list, 2))
    for c in conb:
        poke_list.append([p_name, c])
poke_objects = []
for p in poke_list:
    name = p[0]
    p_ivs_plv = pokemon_and_ivs[name]
    ivs, plv = (p_ivs_plv['S_H_iv'], p_ivs_plv['S_A_iv'], \
                p_ivs_plv['S_B_iv']), p_ivs_plv['S_PLV']
    poke = Pokemon(name, ivs, plv, \
                   n_skill=p[1][0], s_skill=list(p[1][1]))
    poke_objects.append(poke)

pagerank_node_info = []
# 総当たり戦
for i, c in enumerate(itertools.combinations(poke_objects, 2)):
    s = Simulator(c[0], c[1])
    suboptimal = s.get_suboptimal_action_result()
    pagerank_node_info.append(suboptimal[0:-1])
pprint(pagerank_node_info)
result = calc_pagerank_score(pagerank_node_info)
result = sorted(result.items(), key=lambda x:x[1])
print('-'*5, ' 昇順順位 ', '-'*5)
pprint(result)
data_path = os.path.dirname(os.path.abspath(__file__)) + '/../data/'
with open(data_path + 'pagerank_all.json', 'w') as f:
    json.dump(result, f, indent=4)
```

これだけでもこいつらの技パターン全てに対して計算しているのでそれなりに時間がかかってしまいますが、、、仕方ないですね．

123通りあるらしいので，そのうち上位の30パターンを書き出してみます．
名前nノーマル技s1スペシャル1s2スペシャル2, ページランクスコアの順です．
下に行くほどページランクスコアは高くなります．

３０位〜
('エアームドnエアスラッシュs1ブレイブバードs2ラスターカノン', 0.010873885965628653),
('マイナンnスパークs1１０まんボルトs2スピードスター', 0.010963773682036288),
('トリデプスnアイアンテールs1ストーンエッジs2かえんほうしゃ', 0.011020910002229217),
('エアームドnはがねのつばさs1ブレイブバードs2ラスターカノン', 0.011172295994243091),
('ジュカインnれんぞくぎりs1リーフブレードs2つばめがえし', 0.011404537063815784),
('エアームドnはがねのつばさs1ブレイブバードs2ゴッドバード', 0.011431132349556962),
('チャーレムnカウンターs1ばくれつパンチs2グロウパンチ', 0.011661521209950614),
('マイナンnスパークs1１０まんボルトs2ほうでん', 0.01171921588009839),
('トリデプスnアイアンテールs1ストーンエッジs2ラスターカノン', 0.011843011477598434),
('ナマズンnみずでっぽうs1みずのはどうs2どろばくだん', 0.011871475349739766),
('マリルリnあわs1じゃれつくs2れいとうビーム', 0.011935593947075801),
('ジュカインnタネマシンガンs1リーフブレードs2じしん', 0.012353321649853945),
('エアームドnエアスラッシュs1ブレイブバードs2ゴッドバード', 0.012528180634072059),
('チルタリスnりゅうのいぶきs1マジカルシャインs2りゅうのはどう', 0.01302125009075449),
('チルタリスnりゅうのいぶきs1ゴッドバードs2マジカルシャイン', 0.013064452773717122),
('マリルリnあわs1じゃれつくs2ハイドロポンプ', 0.013184708653042254),
('エアームドnはがねのつばさs1ゴッドバードs2ラスターカノン', 0.01346341404185571),
('ナマズンnみずでっぽうs1みずのはどうs2ふぶき', 0.013633085955678763),
('エアームドnエアスラッシュs1ゴッドバードs2ラスターカノン', 0.014006394760793127),
('マリルリnあわs1ハイドロポンプs2れいとうビーム', 0.014094099190586483),
**('チルタリスnりゅうのいぶきs1ゴッドバードs2りゅうのはどう', 0.014437433816295005),
('ナマズンnマッドショットs1みずのはどうs2ふぶき', 0.014504214370076972),
('ナマズンnマッドショットs1みずのはどうs2どろばくだん', 0.014671887830480266),
('ジュカインnれんぞくぎりs1じしんs2ハードプラント', 0.015735750288605205),
('ナマズンnみずでっぽうs1ふぶきs2どろばくだん', 0.016751286629171573),
('ジュカインnれんぞくぎりs1リーフブレードs2じしん', 0.017829049763205308),
('トリデプスnうちおとすs1かえんほうしゃs2ラスターカノン', 0.019325916458072346),
('トリデプスnうちおとすs1ストーンエッジs2かえんほうしゃ', 0.02084337029410739),
('ナマズンnマッドショットs1ふぶきs2どろばくだん', 0.020894679484516482),
('トリデプスnうちおとすs1ストーンエッジs2ラスターカノン', 0.021071234689260816)**]
〜１位

## 考察１
ガード無し前提，ブラフ無しなので実戦だとどうなるかわかりませんが，やはりトリデプスは最強でした．どのパターンもほぼ上位にランクインしています．意外だったのは「かえんほうしゃ」を覚えていないトリデプスがトップだったこと．確かに我々の環境で使われているポケモンに炎技が刺さるポケモンが少ないので納得の結果かもしれません．また，そのトリデプスに勝てるナマズンもやはり強いようです．一般的にスーパーリーグ４強くらいに入りそうなマリルリは一応上位ですが，我々の環境では残念ながらTOP10には入らなかったですね．ジュカインが大健闘な感じです．直感通り，ハードプラントジュカインよりもリーフブレードジュカインが上位にきているのも納得する点．また，僕の愛するマイナンも２３位にランクインしたので嬉しいところです．もっといろいろ考察を書きたいことはありますが，とりあえず今回のところはこの辺にしておきましょう．

このやり方で良い点は，いろいろなレギュレーション環境でシミュレーションが可能な点ですかね．最近流行りの[silph arena](https://silph.gg/)では様々なレギュレーションで大会が行われているようですが，候補を突っ込むだけで強そうなポケモンがリストアップされます．ということで2019/06/20現在，silphのレギュレーションである「jungleルール」で試して見ました．

## jungleレギュレーションでやってみた
ルールに関しては以下のツイートがわかりやすいかと思います．

<blockquote class="twitter-tweet" lang="ja"><p>silph league シルフリーグの7月テーマは「🍀ジャングルカップ🍀」とな🙄

・でんき⚡️、くさ🌱、むし🐛、ノーマル
・トロピウスとミノマダムとガーメイルが禁止

何故電気・・・？と思ったけど、ノーマル含んだ飛行🕊タイプに対して、草と虫がヤバイから、カウンター枠として電気絡めたのね☝︎</p>&mdash; sdtachikawa (@S_Daigo) <a href="https://twitter.com/S_Daigo/status/1141080450686828544">2019, 6月 18</a></blockquote>

このルールで選出されるのは以下のツイートのようになるらしいです．
<blockquote class="twitter-tweet" lang="ja"><p>フレンドとジャングルカップルールで10連戦ほどしましたが、フォレトス、スピアー、ヨルノズク、レアコイル辺りが対策してないとボッコボコにされる感じです。草ポケは良い仕事することもあるんですがボコられる方が多すぎるｗ</p>&mdash; dxx(@blisseeey) <a href="https://twitter.com/blisseeey/status/1141376401414578176">2019, 6月 19</a></blockquote>

これを見た上でページランクスコアランキングTOP100(くらい）をみてみましょう．
約1100通りのポケモンがいるのでかなり上位を見ているといえます．
例によって下に行くほど強いです．

100位〜
 ('メガニウムnつるのムチs1はなふぶきs2ソーラービーム', 0.0017190615418439335),
 ('ビークインnむしくいs1シザークロスs2パワージェム', 0.0017280972860569978),
 ('カイロスnれんぞくぎりs1シザークロスs2インファイト', 0.0017353981876806872),
 ('レアコイルnチャージビームs1でんじほうs2ラスターカノン', 0.0017358252194798593),
 ('モルフォンnむしくいs1ぎんいろのかぜs2むしのさざめき', 0.0017364847999493094),
 ('マイナンnスパークs1１０まんボルトs2ほうでん', 0.0017389698711498263),
 ('フシギソウnつるのムチs1ソーラービームs2パワーウィップ', 0.0017403021889003255),
 ('スピアーnどくづきs1ヘドロばくだんs2つばめがえし', 0.0017431314988152673),
 ('テッカニンnれんぞくぎりs1シャドーボールs2つばめがえし', 0.0017556140182905283),
 ('スピアーnどくづきs1ヘドロばくだんs2シザークロス', 0.0017560790543197293),
 ('モルフォンnむしくいs1ぎんいろのかぜs2サイコキネシス', 0.0017575265150378565),
 ('マルマインnスパークs1ほうでんs2はかいこうせん', 0.0017603017752718844),
 ('モルフォンnむしくいs1ぎんいろのかぜs2どくどくのキバ', 0.0017610766650749327),
 ('メガヤンマnむしくいs1げんしのちからs2つばめがえし', 0.0017617323168780063),
 ('ヤルキモノnカウンターs1じならしs2かわらわり', 0.0017643472024606107),
 ('モジャンボnつるのムチs1げんしのちからs2ソーラービーム', 0.0017695803962884031),
 ('ライボルトnチャージビームs1ワイルドボルトs2はじけるほのお', 0.0018033140684621978),
 ('ハッサムnバレットパンチs1シザークロスs2アイアンヘッド', 0.0018079392691478426),
 ('メガニウムnつるのムチs1ソーラービームs2じしん', 0.0018126357921171646),
 ('メガヤンマnつばさでうつs1つばめがえしs2むしのさざめき', 0.0018274887129493692),
 ('フシギバナnつるのムチs1ヘドロばくだんs2ハードプラント', 0.00184510875367743),
 ('ジバコイルnチャージビームs1でんじほうs2ワイルドボルト', 0.001846690564209896),
 ('フシギバナnつるのムチs1ソーラービームs2ハードプラント', 0.0018527171435410402),
 ('オオスバメnつばさでうつs1つばめがえしs2ブレイブバード', 0.0018608249205236216),
 ('ヤンヤンマnつばさでうつs1つばめがえしs2ぎんいろのかぜ', 0.0018612059313737894),
 ('ピジョットnエアスラッシュs1つばめがえしs2エアカッター', 0.00186777465442176),
 ('ランターンnチャージビームs1ハイドロポンプs2かみなり', 0.0018692092844463427),
 ('メガニウムnつるのムチs1じしんs2ハードプラント', 0.0018797944563602093),
 ('ピジョットnつばさでうつs1つばめがえしs2エアカッター', 0.001887134340914409),
 ('マルマインnスパークs1１０まんボルトs2はかいこうせん', 0.0018971362096973194),
 ('ビークインnむしくいs1むしのさざめきs2パワージェム', 0.0019029042794731022),
 ('フォレトスnむしのていこうs1ヘビーボンバーs2じしん', 0.001905025629358293),
 ('フシギバナnつるのムチs1ヘドロばくだんs2ソーラービーム', 0.00190643164033383),
 ('ピジョットnつばさでうつs1ぼうふうs2エアカッター', 0.0019102703582933346),
 ('レアコイルnでんきショックs1マグネットボムs2ほうでん', 0.0019357220745586353),
 ('ヤンヤンマnつばさでうつs1げんしのちからs2つばめがえし', 0.0019494756740225587),
 ('ランターンnチャージビームs1ハイドロポンプs2１０まんボルト', 0.001957136809292383),
 ('ジバコイルnチャージビームs1でんじほうs2ラスターカノン', 0.0019724613137147035),
 ('フォレトスnむしのていこうs1じしんs2がんせきふうじ', 0.00198754997360272),
 ('ジバコイルnチャージビームs1ワイルドボルトs2ラスターカノン', 0.001995252356064331),
 ('メガヤンマnつばさでうつs1げんしのちからs2むしのさざめき', 0.0019953002045025167),
 ('ユレイドルnまとわりつくs1くさむすびs2ストーンエッジ', 0.0020011166765785053),
 ('ヘラクロスnカウンターs1インファイトs2じしん', 0.0020021535073704287),
 ('ピジョットnエアスラッシュs1つばめがえしs2ブレイブバード', 0.002002688796973392),
 ('フシギソウnつるのムチs1ヘドロばくだんs2ソーラービーム', 0.002006223841928719),
 ('ヤルキモノnカウンターs1のしかかりs2じならし', 0.0020101252569820877),
 ('メガヤンマnつばさでうつs1げんしのちからs2つばめがえし', 0.0020167625694861063),
 ('ピジョットnエアスラッシュs1ぼうふうs2つばめがえし', 0.0020199844799835163),
 ('ゴローン(アローラのすがた)nいわおとしs1ストーンエッジs2１０まんボルト', 0.002022576617794692),
 ('メガニウムnつるのムチs1ソーラービームs2ハードプラント', 0.0020252782460295346),
 ('ピジョットnつばさでうつs1ブレイブバードs2エアカッター', 0.002027940930485958),
 ('オオスバメnつばさでうつs1つばめがえしs2ゴッドバード', 0.002045628945849954),
 ('キノガッサnカウンターs1ヘドロばくだんs2くさむすび', 0.0020548696571294316),
 ('ヤルキモノnカウンターs1のしかかりs2かわらわり', 0.0020604062239344976),
 ('ゴローニャ(アローラのすがた)nいわおとしs1ストーンエッジs2ワイルドボルト', 0.002065954871736028),
 ('ヤンヤンマnつばさでうつs1げんしのちからs2ぎんいろのかぜ', 0.0020699323006164077),
 ('レアコイルnでんきショックs1マグネットボムs2ラスターカノン', 0.0020930097187685606),
 ('オオスバメnつばさでうつs1ブレイブバードs2ゴッドバード', 0.0021156380983305165),
 ('ピジョットnつばさでうつs1ぼうふうs2つばめがえし', 0.0021174573784421414),
 ('ピジョットnつばさでうつs1ぼうふうs2ブレイブバード', 0.002125139476277498),
 ('ユレイドルnまとわりつくs1じならしs2ストーンエッジ', 0.00213550663991931),
 ('レアコイルnスパークs1マグネットボムs2ラスターカノン', 0.0021361899718999777),
 ('ランターンnみずでっぽうs1１０まんボルトs2かみなり', 0.0021662267804562142),
 ('キノガッサnカウンターs1ばくれつパンチs2くさむすび', 0.0021684273306878774),
 ('ゴローニャ(アローラのすがた)nいわおとしs1ワイルドボルトs2ロックブラスト', 0.002175965622788812),
 ('サンダーnでんきショックs1１０まんボルトs2でんじほう', 0.002185282292465725),
 ('ゴローン(アローラのすがた)nいわおとしs1ロックブラストs2１０まんボルト', 0.002187448148569348),
 ('キノガッサnカウンターs1ばくれつパンチs2ヘドロばくだん', 0.0021923046700945523),
 ('ゴローニャ(アローラのすがた)nいわおとしs1ストーンエッジs2ロックブラスト', 0.002229284397209872),
 ('ヨルノズクnじんつうりきs1ゴッドバードs2ナイトヘッド', 0.002239484443594109),
 ('ヨルノズクnじんつうりきs1サイコキネシスs2ゴッドバード', 0.002258574243649496),
 ('サンダーnでんきショックs1かみなりs2でんじほう', 0.002273748719123169),
 ('レアコイルnスパークs1ラスターカノンs2ほうでん', 0.0022753710750438617),
 ('レアコイルnでんきショックs1ラスターカノンs2ほうでん', 0.0022847572130108157),
 ('ランターンnみずでっぽうs1ハイドロポンプs2かみなり', 0.0022879346359959015),
 ('ピジョットnつばさでうつs1つばめがえしs2ブレイブバード', 0.0023509002106518137),
 ('ゴローン(アローラのすがた)nいわおとしs1ストーンエッジs2ロックブラスト', 0.002364172499218901),
 ('キノガッサnカウンターs1タネばくだんs2ヘドロばくだん', 0.0023847404051988113),
 ('ランターンnみずでっぽうs1ハイドロポンプs2１０まんボルト', 0.0023869722377560547),
 ('レアコイルnスパークs1でんじほうs2マグネットボム', 0.0024129133081209147),
 ('ヘラクロスnカウンターs1メガホーンs2じしん', 0.0024141482886917455),
 ('レアコイルnスパークs1でんじほうs2ほうでん', 0.0024346033289891662),
 ('キノガッサnカウンターs1タネばくだんs2くさむすび', 0.0024413479056060922),
 ('ジバコイルnスパークs1ワイルドボルトs2ラスターカノン', 0.0024616297588415203),
 ('ヘラクロスnカウンターs1メガホーンs2インファイト', 0.002467243758703343),
 ('フォレトスnむしくいs1ヘビーボンバーs2がんせきふうじ', 0.0025423522031167794),
 ('レアコイルnスパークs1でんじほうs2ラスターカノン', 0.002552871204178482),
 **('キノガッサnカウンターs1ばくれつパンチs2タネばくだん', 0.0026613554798247405),
 ('レアコイルnでんきショックs1でんじほうs2マグネットボム', 0.002792279293373775),
 ('レアコイルnでんきショックs1でんじほうs2ほうでん', 0.0028172044393106016),
 ('レアコイルnでんきショックs1でんじほうs2ラスターカノン', 0.002843864994234127),
 ('ジバコイルnスパークs1でんじほうs2ラスターカノン', 0.0028502756956025922),
 ('フォレトスnむしくいs1ヘビーボンバーs2じしん', 0.0028690865940579034),
 ('ジバコイルnスパークs1でんじほうs2ワイルドボルト', 0.0029002392656013645),
 ('ヨルノズクnつばさでうつs1ゴッドバードs2ナイトヘッド', 0.0029400947319945608),
 ('ヨルノズクnつばさでうつs1サイコキネシスs2ゴッドバード', 0.0029644338911777673),
 ('フォレトスnむしくいs1じしんs2がんせきふうじ', 0.002989787604444073)**]
〜１位

## 考察２
こちらもあくまでシミュレーション上の結果なので多少人間の直感とずれる部分があるかと思われますが，大枠はかなり良い結果が出たんじゃないかと思います．
実際にこのレギュレーションで対戦されている方のツイートに出てきた「フォレトス、ヨルノズク、レアコイル」がばっちりTOP10に入ってきています．スピアーもTOP100には入っていますね．おしゃれなのは13位にランクインした「ヘラクロス」ですかね？地域限定ポケモンで戦うのは面白そうです．
単純に上から強いポケモンを１０体選出すると
「フォレトス、ヨルノズク、ジバコイル、レアコイル、キノガッサ、ヘラクロス、ランターン、サンダー、アローラゴローン、ピジョット」になるので、困ったらこいつらから選出しておけばよさそう．
アローラゴローン、まあまあ大健闘な気がしてきた．


# 結論
- だいたいそれっぽい結果がでた．
- いろいろな環境で使えそう．
- たのしい
- そのうち公開するから使ってね

現在全ポケモン、全技パターンでシミュレーション中です！

ここまでお読みいただきありがとうございました！