[抱負]

久しぶりに、ダブルクロスの達成値の平均値を求めるプログラムをschemeで書く、です。

なんかもう久しぶり過ぎて良く覚えていない上に、色々考え方が変わってきたので、別手法でいくことにします。
…気にするな、きっとこういう方向転換がまだまだある(もしくは抱負自体が風化する)。

ファンブル時の計算を忘れていたため、修正。

ダブルクロスで能力値1、技能0、クリティカル値10、エフェクトは使用しない。

上記の場合、達成値の平均値は以下のように算出される。
出た目が1〜9の場合、その目が出る確率に出た目を掛け合わせる。
プログラムで書くと以下の様になる。

(+ (/ 1 10) (/ 2 10) (/ 3 10) (/ 4 10) (/ 5 10) (/ 6 10) (/ 7 10) (/ 8 10) (/ 9 10) )

出た目が10の場合、その目が出る確率に出た目を掛け合わせたものに、クリティカル分が加算される。

(+ (/ 10 10) (/ x 10)) ; xがクリティカル分

まとめると下記の様になる

(+ (/ 1 10) (/ 2 10) (/ 3 10) (/ 4 10) (/ 5 10) (/ 6 10) (/ 7 10) (/ 8 10) (/ 9 10)
  (/ 10 10) (/ x 10)) ; xがクリティカル分

(+ (/ (+ 1 2 3 4 5 6 7 8 9 10) 10.0)
  (/ x 10.0)) ; xがクリティカル分

(+ 5.5 (/ x 10.0)) ; xがクリティカル分

ここで、xはもとめる平均値そのものである。
再帰的にずっと続く)

…なんかよくまとまんないんだけど、下記の様になる。

(+
  5.5
  (/ 5.5 10 )
  (/ 5.5 100 )
  (/ 5.5 1000 )
  (/ 5.5 10000 )
  ; ずっと続く。
)

(+
  (/ 5.5 (expt 10 0))
  (/ 5.5 (expt 10 1))
  (/ 5.5 (expt 10 2))
  (/ 5.5 (expt 10 3))
  (/ 5.5 (expt 10 4))
  ; ずっと続く。
)

このexptは累乗関数。
これは初項5.5、公比0.1の無限等比級数に等しくなる。
無限等比級数の和の公式から、

(/ 5.5 (- 1 0.1))
; => 6.111111111111111

が求める平均値になる。
で、実際の判定では最初の1回で1が出た場合はファンブルである。
(1回でもクリティカルした後の1はファンブルでは無い)
ファンブル(絶対失敗)時の扱いをとりあえず達成値0とすると(異論はあるかもしれないけど1ではないのは確か)、
最初の1回で1が出る可能性×その時の出目(当然1)をこの平均値から引く。

(- (/ 5.5 (- 1 0.1)) (/ 1 10.0))
; => 6.011111111111111

これが正しい平均値である。

同様に能力値1、技能0、クリティカル値9、エフェクトは使用しないケース。

これは初項5.6(ダイス目9の場合は10として扱うため)、公比0.2(クリティカル率があがる)の無限等比級数に等しくなる。

(/ 5.6 (- 1 0.2))
; => 6.999999999999999

となる。

同様に、上記とクリティカル値のみが異なるケースを列挙する。

(/ (+ 1 2 3 4 5 6 7 8 9 10) 10.0)		;クリティカル値が10の場合の初項	5.5
(/ (+ 1 2 3 4 5 6 7 8 10 10) 10.0)		;クリティカル値が9 の場合の初項	5.6
(/ (+ 1 2 3 4 5 6 7 10 10 10) 10.0)		;クリティカル値が8 の場合の初項	5.8
(/ (+ 1 2 3 4 5 6 10 10 10 10) 10.0)		;クリティカル値が7 の場合の初項	6.1
(/ (+ 1 2 3 4 5 10 10 10 10 10) 10.0)		;クリティカル値が6 の場合の初項	6.5
(/ (+ 1 2 3 4 10 10 10 10 10 10) 10.0)		;クリティカル値が5 の場合の初項	7.0
(/ (+ 1 2 3 10 10 10 10 10 10 10) 10.0)		;クリティカル値が4 の場合の初項	7.6
(/ (+ 1 2 10 10 10 10 10 10 10 10) 10.0)	;クリティカル値が3 の場合の初項	8.3
(/ (+ 1 10 10 10 10 10 10 10 10 10) 10.0)	;クリティカル値が2 の場合の初項	9.1
(/ 5.5 (- 1 0.0))	;クリティカル値が11の場合の平均値 => 5.5
(/ 5.5 (- 1 0.1))	;クリティカル値が10の場合の平均値 => 6.111111111111111
(/ 5.6 (- 1 0.2))	;クリティカル値が9 の場合の平均値 => 6.999999999999999
(/ 5.8 (- 1 0.3))	;クリティカル値が8 の場合の平均値 => 8.285714285714286
(/ 6.1 (- 1 0.4))	;クリティカル値が7 の場合の平均値 => 10.166666666666666
(/ 6.5 (- 1 0.5))	;クリティカル値が6 の場合の平均値 => 13.0
(/ 7.0 (- 1 0.6))	;クリティカル値が5 の場合の平均値 => 17.5
(/ 7.6 (- 1 0.7))	;クリティカル値が4 の場合の平均値 => 25.33333333333333
(/ 8.3 (- 1 0.8))	;クリティカル値が3 の場合の平均値 => 41.500000000000014
(/ 9.1 (- 1 0.9))	;クリティカル値が2 の場合の平均値 => 91.00000000000001

(面倒なのでファンブル時の修正は後回し)

次に、もう少し一般化する。

公比は(/ (- 11 cr) 10.0)である(crはクリティカル値)。
初項は5.5に、以下の等比数列の和の十分の一を加算したものである。

  • 初項0、項数(- 10 cr)、公差1
  • 等比数列の和の公式から、この部分は(/ (* (- 10 cr) (+ (- 10 cr) 1)) 2)になる

すなわち、初項は(+ 5.5 (/ (/ (* (- 10 cr) (+ (- 10 cr) 1)) 2) 10.0))となる

と言うわけで、クリティカル値を引数にとる関数を定義してみる。

(define (roll-1dice cr)
  (/ 
   (+ 5.5 (/ (/ (* (- 10 cr) (+ (- 10 cr) 1)) 2) 10.0))	; 初項の部分
   (- 1 
	  (/ (- 11 cr) 10.0)		; 公比の部分
	  )))

実行結果

gosh> (define (roll-1dice cr)
  (-
   (/ 
	(+ 5.5 (/ (/ (* (- 10 cr) (+ (- 10 cr) 1)) 2) 10.0))	; 初項の部分
	(- 1 
	   (/ (- 11 cr) 10.0)		; 公比の部分
	   )
	)
   (/ 1 10.0)		; ファンブル時の分を減算する
   )
  )

roll-1dice
gosh> (roll-1dice 10)

6.011111111111111
gosh> (roll-1dice 9)
6.8999999999999995
gosh> (roll-1dice 8)
8.185714285714287
gosh> (roll-1dice 7)
10.066666666666666
gosh> (roll-1dice 6)
12.9
gosh> (roll-1dice 5)
17.4
gosh> (roll-1dice 4)
(roll-1dice 4)
25.233333333333327
gosh> (roll-1dice 3)
41.40000000000001
gosh> (roll-1dice 2)
90.90000000000002

参考にしたページ

無限等比級数の和

等差数列の和の公式

検算するときに参考にした

ダブルクロスの確率

参考書籍

っつーか、読んだだけとか実は通読してないとか含む。

数学入門〈上〉 (岩波新書)

数学入門〈上〉 (岩波新書)

数学入門〈下〉 (岩波新書 青版 396)

数学入門〈下〉 (岩波新書 青版 396)

プログラマの数学

プログラマの数学

数学ガール (数学ガールシリーズ 1)

数学ガール (数学ガールシリーズ 1)

プログラミング言語SCHEME

プログラミング言語SCHEME

  • 作者: R.ケントディヴィグ,R.Kent Dybvig,村上雅章
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2000/05
  • メディア: 単行本
  • 購入: 2人 クリック: 71回
  • この商品を含むブログ (20件) を見る