「信長の野望 出陣」の遠征時間を探る

前回の記事に続いて、今度は「遠征」に要する時間を探ります。記事書くの疲れるのであっさりと。 schima.hatenablog.com

ℹ️注意

距離と時間の関係

横軸を遠征先までの距離(m)、縦軸を所要時間(秒)としたときのグラフが以下です。

信長の野望 出陣」遠征先の距離と所要時間

秒だとわかりにくいですが、以下の傾向が読み取れます。

  • 距離がほぼ0mでも最短2時間は要する
  • およそ11km、45kmで傾向が変わる
  • 11kmまでは急激に時間が増していく
  • 11km(15時間半)から45km(21時間半)まではゆるく線形に時間が増加
  • 45km以上では時間が増えない
    • 50km以上先にはおそらく遠征不可能

以上のデータは、私の探れる範囲で、遠征先ごとの距離と所要時間をたくさん集めたものです。石高よりはだいぶ集めやすいです。

遠征先選択画面  ©コーエーテクモゲームス

曲線・直線近似

ここからは、任意の距離から所要時間を求められるように、所要時間を決定する方程式を見出してみたいと思います。今回はPythonを書いていきます。

先に結論

遠征の所要時間(秒)を t 、遠征先までの距離(m)を d として、

  • 11km以下:  t(d) = 0.0005.36765222d^{1.96912686} + 7200
  • 11km~45km:  t(d) = 0.636141912d + 49145.5490
  • 45km以上:  t(d) \risingdotseq 77500

環境

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

きれいにフィットできました。

curve_fitによる11km以下の遠征時間推定

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以上だと、距離が増えるのに時間が減る例も観察されます。

11km~45kmでの所要時間の直線近似

今回はゲーム画面表示をそのままデータ採取しており、そんなに大きな誤差を考えづらいです。もしかすると、これまで距離のみによって所要時間が定まると仮定していましたが、第2、第3のファクターがあるのかもしれませんね。