北海道内15箇所にポケモンマンホールが設置されるので最適経路を計算してみた

## はじめに
11月末ごろに、北海道にポケモンマンホールが設置される旨、公式ウェブサイトや各種ニュースサイトで取り上げられました。

![スクリーンショット 2019-12-02 21.11.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/c0f52e41-6a65-0dc7-5afd-f3071ef2e190.png)

[ポケモンマンホール『ポケふた』](https://local.pokemon.jp/manhole/)

１５箇所がそれなりに均等に全道に散らばっており、コンプリートはなかなか大変そうです。私の地元もなんと設置対象となっており、ポケモン好きとして、そしてジオ道へ進む身として、またアドベントカレンダーの良いネタが見つかったという事で、<B>道内全１５箇所を巡る最適経路を計算してみたい！</b>と思いやってみました。

## 『ポケふた』を位置情報データにする
### 位置情報を取得
公式サイトで地図情報と座標が取得出来ます。

![スクリーンショット 2019-12-02 21.18.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/5305d8ef-294f-c40a-9181-174a75118c6d.png)

### QGIS上で１５箇所をプロット
マウスでカチカチ…

![スクリーンショット 2019-12-02 21.20.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/4491e83d-92b9-beb7-8849-2ab00fd91e64.png)

やったぜ。

### CSVファイルに座標を出力
フィールド計算機で、属性に座標（経度・緯度）を追加します。＄xで経度(lon)を、＄yで緯度(lat)を取得可能。

![スクリーンショット 2019-12-02 21.24.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/2d36ece7-e092-ab72-f7f1-66f96399ce72.png)

そしてCSVでエクスポート。

```
['士別市', '44.1759660664951', '142.392400060057']
['比布町', '43.8750601338394', '142.471656275175']
['足寄町', '43.2442234401681', '143.546750238874']
['石狩市', '43.5859009826181', '141.423896468599']
['恵庭市', '42.8971470864568', '141.585830729499']
['洞爺湖町', '42.5661295066754', '140.819057243298']
['森町', '42.1088651156221', '140.572905228496']
['上ノ国町', '41.8084126507218', '140.095325019279']
['天塩町', '44.8845377760538', '141.747994037888']
['稚内市', '45.4170905393652', '141.676181866153']
['豊富町', '45.1033949651183', '141.778599640962']
['紋別市', '44.334669948041', '143.37218366193']
['遠軽町', '44.0218720548609', '143.497163771181']
['大空町', '43.9155408070508', '144.171387033476']
['新得町', '43.0826784443182', '142.832912172283']
```

## 最適経路計算
### 計算手法
さてデータの下準備が完了し、ここからが本番です。がしかし、最適経路の計算手法などは全く知らないのでとりあえずGoogleってみました。こういう、多数の地点の巡回ルートの最適化は一般に、巡回セールスマン問題と呼ばれています。

![スクリーンショット 2019-12-02 21.29.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/0ba04bb2-c328-327a-dd35-8681789292a0.png)

![スクリーンショット 2019-12-02 21.31.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/24193b5e-3304-f05f-2eda-5dbc66dc3237.png)
（答えが載ってる…最高…）

という訳でこちらの記事を参考にさせて頂きました。
[組合せ最適化 - 典型問題 - 巡回セールスマン問題 - Qiita](https://qiita.com/SaitoTsutomu/items/def581796ef079e85d02)

### コード

[https://github.com/Kanahiro/-pokefuta_analyzer](https://github.com/Kanahiro/-pokefuta_analyzer)

```python
import csv
import numpy as np
from scipy.spatial import distance
from ortoolpy import tsp

asahikawa_airport = [142.4541427, 43.6708414]
shinchitose_airport = [141.6811815, 42.7876057]
shinkansen_hokuto = [140.6486832, 41.9046279]

start_point = shinkansen_hokuto
nodes = [start_point]

with open('./pokefuta_coordinates.csv') as f:
    reader = csv.reader(f)
    header = next(f)
    for row in reader:
        nodes.append([ row[2], row[1] ])

dist = distance.cdist(nodes, nodes)
print(tsp(nodes, dist))
```

pokefuta_coordinates.csvの中身は先ほどのcsvファイルと同じです。
経度・緯度の配列をnodesとして、それぞれの距離を要素数x要素数の行列distをつくり、tsp(traveling salesman problem)に渡すと結果が出力されます。

```
(12.651143975005297, [0, 10, 9, 8, 3, 5, 7, 6, 4, 14, 2, 13, 12, 11, 1])
```

最初の値は移動コストです。２つ目の返り値の配列が、移動コストを最小化する場合に通るべき経路を示します。常に1番目のnode（[0]のこと）がスタート地点かつゴール地点に設定されます。先ほどのcsvファイルで言うと士別市がスタート地点となります。この経路を図示すると以下になります。

![スクリーンショット 2019-12-02 22.23.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/bf8d1f6b-fd91-6720-2159-15d0bbdba3d2.png)

コード自体は問題なさそうですね、ちゃんと最短経路っぽくなっています。
道民はみんな自家用ヘリコプターで移動するので海上ルートでも問題ありません。まあ車での移動だったとしても、森町と上ノ国町は同時に回るのが効率良いので、今回の分析には影響はないものとします（距離の乖離は大きそうだけれど、巡回の順番には影響がないものとする）。
というのが士別市発ルートですが、皆様のご旅行のプランに合わせていくつかのパターンをご覧ください（記載されている総移動距離は直線距離の総和による概算です）。

### 旭川空港発ルート
総移動距離：1267km

![スクリーンショット 2019-12-02 22.57.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/bb8edfb9-9bf9-068b-fb9b-7d1b2b547131.png)


北海道第２位の都市旭川市、ではなく隣の東神楽町にあり、悪天候をものともしない堅牢さにより驚異の就航率99.7%を誇る我らが旭川空港から、道内１５箇所のマンホール巡りしてみませんか？

### 新千歳空港発ルート
総移動距離：1237km

![スクリーンショット 2019-12-02 22.56.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/24b802b4-bf52-a19a-c9ec-98ddce754824.png)

ハブ空港として北海道の玄関口でありながら、飛行機に乗らずとも様々なテナントで楽しめる我らが新千歳空港から、１２００ｋｍドライブでマンホール制覇だ！

### 新幹線北斗駅発ルート
総移動距離：1239km

![スクリーンショット 2019-12-02 22.54.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/e7a0f08c-5b4e-4bc3-0135-ff39232d06e1.png)

ついに来たぞ新幹線、東京から４時間くらいで着くらしいのでとりあえず来てみませんか、マンホール巡りしませんか？

## 終わりに
複数プランを示したものの、結局ルートは環状になったため当然ですが、順番が多少異なるだけでほとんど違いがありませんでした…。今回の記事は思いつきで始めてみましたが、思ったより早く記事に出来ました（トータル４時間くらい）。位置情報データの表示や加工は仕事や趣味で色々やってきましたが、今回の最適化のような分析はあまり経験がなく、実際今回のコードも、便利なライブラリに助けられただけでその計算手法などは全くわからないままです。わからない事だらけですが、ひとまずはこの記事を読まれた方に楽しんで頂けたなら幸いです。

## 参考サイト

[組合せ最適化 - 典型問題 - 巡回セールスマン問題 - Qiita](https://qiita.com/SaitoTsutomu/items/def581796ef079e85d02)

[pythonでのcsvファイルの読み込み - Qiita](https://qiita.com/motoki1990/items/0274d8bcf1a97fe4a869)

[QGISでラインをポイントに変換してｘｙ座標を取り出す - Qiita](https://qiita.com/ishiijunpei/items/a90385cca43ddcb91428)