1. ホーム
  2. c++

[解決済み] 予測可能なランダムジェネレータの必要性

2022-04-28 15:03:17

質問

私はウェブゲームの開発者ですが、乱数に関する問題が発生しました。例えば、あるプレイヤーが剣でクリティカルヒットを出す確率が20%だとします。つまり、5発中1発はクリティカルになるはずです。問題は、現実の結果が非常に悪いことです。5回のヒットで3回クリティカルが出ることもあれば、15回のヒットで1回も出ないこともあります。バトルはかなり短いので(3~10ヒット)、良いランダム分布にすることが重要です。

現在、私はPHPを使用しています。 mt_rand() しかし、私たちはコードをC++に移行したばかりなので、私たちのゲームの新しいエンジンでこの問題を解決したいのです。

解決策は一様乱数発生器なのか、それとも以前の乱数状態を記憶して適切な分布を強制することなのか、わかりません。

解決方法は?

ゲームによっては、少量生産で本当の意味でのランダム性は望ましくないという、先の回答に同意します--いくつかのユースケースでは、あまりにも不公平に見えます。

私はRubyで簡単なシャッフルバッグのような実装を書き、いくつかテストしてみました。 その実装はこんな感じでした。

  • まだ公平と思われる場合、あるいは最小出目の閾値に達していない場合は、通常の確率に基づいた公平な当たりを返す。
  • 過去の出目から観測された確率が不公平に見える場合、"Fair-ifying"ヒットを返します。

境界確率に基づいて不当と判断される。 例えば、20%の確率の場合、10%を下限、40%を上限とすることができる。

その境界線を用いて、10ヒットのランでわかったこと。 真の擬似乱数の実装では、14.2%の確率で境界から外れた結果が得られました。 . 約11%の確率で、10回の試行でクリティカルヒットは0回でした。 3.3%の確率で、10回中5回以上クリティカルヒットが発生した。 当然ながら、このアルゴリズム(最小出目は5)を使用すると、"Fairish"のランのうち、はるかに少ない量(0.03%)が範囲外であったことになります。 たとえ以下の実装が不向きだとしても(確かにもっと巧妙なことはできる)、注目すべきは、本当の擬似乱数解で不公平だと感じるユーザーが顕著に多いことである。

以下は、私の FairishBag Rubyで書かれています。 全体の実装と簡単なモンテカルロ・シミュレーション はこちら(gist)からどうぞ .

def fire!
  hit = if @rolls >= @min_rolls && observed_probability > @unfair_high
    false
  elsif @rolls >= @min_rolls && observed_probability < @unfair_low
    true
  else
    rand <= @probability
  end
  @hits += 1 if hit
  @rolls += 1
  return hit
end

def observed_probability
  @hits.to_f / @rolls
end

更新しました。 この方法を使用すると、クリティカルヒットの全体的な確率が上がり、上記の境界を使用して約22%になります。 これは、quot;real" の確率を少し低く設定することで相殺することができます。 17.5%の確率に公正な修正を加えると、長期的な確率は約20%になり、短期的な実行は公正に保たれます。