エンカウント確率分布
過去ブログの転載です。
昔ながらのRPGでは、歩いているとランダムに敵と遭遇して戦闘が始まりますよね。あれをランダムエンカウントと言いますが、具体的にどんなランダムであれば心地よく戦闘を迎えられるのか考えます。
過去ブログの投稿に沿った内容なので、カテゴリがツクール2000になっていますが……実際、2000で実装するにはきつい内容です。↓MV向けのプラグインを作りましたので、MVでの実装はこちらを使っていただければ一瞬です。
エンカウント確率分布
ランダムエンカウントは、何歩か歩いたら突然戦闘が始まる、というものになっています。そのため、シンプルには以下のような方法で実装されます。
(1) 一歩ごとに低確率の遭遇判定を設け、その確率になったとき遭遇
(2) 次に遭遇するまでの歩数をランダムに計算しておく
RPGツクールで標準に使えるランダムな数は一様乱数です。これは、例えばランダムの範囲を1~10にすると、1~10の値がそれぞれ等しい確率で出るというものです。一様乱数を用いて以上の実装をすると、考えすぎかもしれませんが、それぞれに対して次のような問題が発生します。
(1) 一歩ごとに遭遇判定
⇒ 戦闘が終わってから数歩歩いただけで、また戦闘が始まってしまうことがある。
(2) エンカウント歩数をランダム
⇒ 歩数の下限や上限が気になる。例えば10歩以上30歩以下とすると、9歩までは確実に出ないし、遭遇なしに31歩以上歩けない。
とても些細ですけれど、いずれもイライラの要因になりうる問題です。
このような問題が発生してしまう原因は、一様乱数だからに尽きます。そうではなく、例えば歩数をランダムにするにしろ、5歩になる確率は10%、10歩になる確率は20%、みたいに、よくありそうな歩数になる確率が必然的に高くなるような乱数を作ればイライラすることなく自然にエンカウントできると考えられます。
そこで、ここでは有名な確率分布である正規分布を使います。
横軸が歩数に相当し、縦軸が遭遇確率に相当します。これは、平均、標準偏差の正規分布で、平均と標準偏差は好きに決めることができます。それらを予め決めてやってこの分布に従った乱数を作ってやれば、理想のエンカウントを作れそうですね。平均は最も出現確率の高い歩数、標準偏差は大きくなると分布の幅が広がる定数を意味します(出現歩数にムラが出来る)。
一様乱数から正規分布を作る
一様乱数からこの分布に従った乱数を作る方法はいくつか考案されています。
(A) 一様乱数を大量に足し算して平均をとる(中心極限定理)
(B) ボックス=ミュラー法
(C) 一様乱数で面積を出し、その面積となるような積分範囲を求める
(A)は最も実装がお手軽ですが、平均や標準偏差を指定することが難しく、厳密さにこだわるのであれば適しません。しかし実際は十分良い手法ですし、恐らく大半はこの方法で作られています。今回は割愛です。
(B)は個人的なオススメです。一様乱数で得た数に対して、比較的簡単な関数の計算を行うだけで、正規分布に従った乱数が得られてしまうという奇跡の手法です。オススメですが、こちらも割愛です。ごめんね……
今回は(C)でやります。厳密なやり方ですが、実装が困難です。
積分を用いた正規乱数の生成
初めに、確率分布の面積を一様乱数で決めてしまいます。全体の面積の0%~100%のどれかを一様乱数で決めて、そのような面積になるときの範囲を計算するのです。
上図は一様乱数によって80%が出たときの例です。左端から歩数までの範囲の面積を計算して、全体の80%になるようなを求めたら、それがエンカウント歩数ということになります。このようにすれば、一様乱数から正規乱数を得ることが可能です。
問題はこのをどう求めるかですが、簡単ではありません。正規分布の関数(確率密度関数といいます)を、積分範囲からで積分して、答えが一様乱数の結果になるようなを求めることになります。
エンカウント歩数の公式
平均、標準偏差に従う正規分布に基づくエンカウント歩数は、一様乱数として次式から得られる。
ただし、は床関数(小数点以下切り捨て)、は逆誤差関数を表す。
導出
正規分布の確率密度関数はと表されるので、これをからの範囲で積分し、を求めることを考える。ところが直接その範囲で積分をすると結果が複雑になるため、この関数がを軸として線対称なことを利用して、からまでの範囲を求めるものとする。それに伴い、一様乱数の範囲もではなくを採用する。
に置換すると
となる。この積分は初等関数では答えを表せず、誤差関数を用いてと表せる。
より、
ここで、と改め、誤差関数の逆関数を逆誤差関数とすると、
歩数は整数なので、四捨五入したものを答えとすれば、
として求められる。
□
こうして一様乱数からエンカウント歩数を求める式は得られましたが、肝心の逆誤差関数の計算が難しいので、ここまで来たらプログラムに任せましょう。
2000で何とか実装出来ないか試行錯誤したものの実らず、結局は補間により無理やりそれっぽく計算して実装しました。ボクらの故郷というRPG作ってますが、そこではスプライン補間による方法で実装しています。ややこしい割に、その恩恵があまり感じられない気もしますが……