前回の記事に続いて、今度は「遠征」に要する時間を探ります。記事書くの疲れるのであっさりと。 schima.hatenablog.com
ℹ️注意
- 本記事の内容は、ゲーム攻略にはほとんど価値がないと思います。純粋な興味と、調査にあたって要した技術的知見のメモが目的です。
- 本記事にはゲーム中のスクリーンショットが含まれます。以下ガイドラインに沿います。https://www.gamecity.ne.jp/info/videopolicy.html
- 数学的その他で用語がおかしければすみません。
距離と時間の関係
横軸を遠征先までの距離(m)、縦軸を所要時間(秒)としたときのグラフが以下です。
秒だとわかりにくいですが、以下の傾向が読み取れます。
- 距離がほぼ0mでも最短2時間は要する
- およそ11km、45kmで傾向が変わる
- 11kmまでは急激に時間が増していく
- 11km(15時間半)から45km(21時間半)まではゆるく線形に時間が増加
- 45km以上では時間が増えない
- 50km以上先にはおそらく遠征不可能
以上のデータは、私の探れる範囲で、遠征先ごとの距離と所要時間をたくさん集めたものです。石高よりはだいぶ集めやすいです。
曲線・直線近似
ここからは、任意の距離から所要時間を求められるように、所要時間を決定する方程式を見出してみたいと思います。今回はPythonを書いていきます。
先に結論
遠征の所要時間(秒)を t 、遠征先までの距離(m)を d として、
- 11km以下:
- 11km~45km:
- 45km以上:
環境
Python 3.11.1
matplotlib==3.8.0 pandas==2.1.1 scikit-learn==1.3.1
11km以下
まず入力データを以下のようなTSVで用意します。(TSVなのは、スプレッドシートからコピペしたというだけの由来です。)
距離[m] 時間(秒換算) 1539 8256 1844 8668 2156 9179 2163 9190 2271 9382 2377 9589 ...
曲線近似には、scipy.optimize.curve_fit
を使いました。使い方は巷にたくさんあるので省略します。
docs.scipy.org
curve_fit
の第1引数には、近似モデルとなる関数を指定します。たぶん2次式か何かの多項式ではなかろうかと、以下のような関数にしました。xには距離(m)が入ります。ほかのa, b, cの値を推測してもらいます。
def nonlinear_fit(x, a, b, c): return b*(x**a) + c
これを使っての曲線近似とグラフ描画です。決定係数も求めてみています。
import matplotlib.pyplot as plt import numpy as np import pandas as pd from scipy.optimize import curve_fit from sklearn.metrics import r2_score def nonlinear_fit(x, a, b, c): return b*(x**a) + c df = pd.read_csv("data1.tsv", sep="\t") x = df["距離[m]"] y = df["時間(秒換算)"] p_opt, cov = curve_fit(nonlinear_fit, x, y) y_fit = np.vectorize(nonlinear_fit) fig, ax = plt.subplots() ax.set_xlabel("distance[m]") ax.set_ylabel("time[s]") ax.plot(x, y, marker="o", label="input data") ax.plot(x, y_fit(x, *p_opt), label="curve fitting") ax.grid(axis="both") ax.legend() plt.savefig("fig1.png") r2 = r2_score(y, y_fit(x, *p_opt)) print(f"{r2=}") # r2=0.9996614210697053
きれいにフィットできました。
p_opt
の要素として、推定したa
b
c
の値が入っています。
print(p_opt)
[1.96912686e+00 5.36765222e-04 7.19442529e+03]
従ってこれを使えば、任意の距離について遠征時間をいつでも求められるようになりました。以下は5000mのときの所要時間を求める例で、約17510秒 (4時間51分50秒) と求まります。
from datetime import timedelta sec = nonlinear_fit(5000, *p_opt) td = timedelta(seconds=sec) print(f"{sec=}, {str(td)=}")
sec=17510.7628634274, str(td)='4:51:50.762863'
11km~45km
11km以下のときと全く同様の手順を使えます。見た感じ明らかに直線なので、モデルは1次式にしました。
def linear_fit(x, a, b): return a*x + b
推定したa
b
の値はこうなりました。
[6.36141912e-01 4.91455490e+04]
距離が増えるにつれ、明らかにデータがガタガタしており誤差がどうしてもあります。ちなみに今回省略しますが45km以上だと、距離が増えるのに時間が減る例も観察されます。
今回はゲーム画面表示をそのままデータ採取しており、そんなに大きな誤差を考えづらいです。もしかすると、これまで距離のみによって所要時間が定まると仮定していましたが、第2、第3のファクターがあるのかもしれませんね。