Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
街コロの期待値を出す
class Facility
attr_reader :name, :cost, :income, :range, :color
def initialize(name:, cost:, income:, color:, range:)
@name = name
@cost = cost
@income = income
@color = color
@range = Array(range)
end
def self.initial_data
[
Facility.new(name: "麦畑", cost: 1, income: 1, color: :blue, range: 1),
Facility.new(name: "牧場", cost: 1, income: 1, color: :blue, range: 2),
Facility.new(name: "パン屋", cost: 1, income: 1, color: :green, range: [2, 3]),
Facility.new(name: "コンビニ", cost: 2, income: 4, color: :green, range: 4),
Facility.new(name: "カフェ", cost: 2, income: 3, color: :red, range: 3),
Facility.new(name: "森林", cost: 3, income: 1, color: :blue, range: 5),
Facility.new(name: "鉱山", cost: 6, income: 5, color: :blue, range: 9),
Facility.new(name: "ファミレス", cost: 3, income: 2, color: :red, range: [9, 10]),
Facility.new(name: "リンゴ園", cost: 3, income: 2, color: :blue, range: 10),
]
end
end
require("./facility")
# ダイスを1つ振った時の各目の確率
def solo_dice_ptobabilities(range)
range.reduce(0) do |sum, r|
sum + if r >= 1 && r <= 6
Rational(1, 6)
else
0
end
end
end
# ダイスを2つ振った時の各目の確率
def twice_dice_ptobabilities(range)
range.reduce(0) do |sum, r|
sum + (
{
2 => Rational(1, 36),
3 => Rational(2, 36),
4 => Rational(3, 36),
5 => Rational(4, 36),
6 => Rational(5, 36),
7 => Rational(6, 36),
8 => Rational(5, 36),
9 => Rational(4, 36),
10 => Rational(3, 36),
11 => Rational(2, 36),
12 => Rational(1, 36),
}[r] || 0
)
end
end
class Machikoro
def initialize(player_number: 4)
@player_number = player_number
end
# 階乗
def factorial(n)
return 1 if n == 0
(1..n).inject(:*)
end
alias :f :factorial
# 組み合わせ
def combination(n, r)
f(n) / (f(n - r) * f(r))
end
alias :c :combination
# 期待値
# income 報酬
# probability 報酬の出る確率
# tries 試行回数
def mean(income, probability, tries)
t = probability # 目が出る確率
f = 1 - probability # 目以外が出る確率
(1..tries).map { |k|
(k * income) * (c(tries, k)) * (t ** k) * (f ** (tries - k))
}.reduce(:+)
end
# 試行回数
def tries(color)
case color
when :blue
@player_number # 全てのプレイヤーのターン
when :green
1 # 自分のターン
when :red
@player_number - 1 # 相手のターン
end
end
# 元が取れるまで
def break_even(cost, mean)
return Float::INFINITY if mean == 0
(cost / mean).round
end
def run
puts "プレイヤー数(試行回数): #{@player_number}"
puts ""
Facility.initial_data.each do |f|
t = tries(f.color)
m1 = mean(f.income, solo_dice_ptobabilities(f.range), t)
m2 = mean(f.income, twice_dice_ptobabilities(f.range), t)
b1 = break_even(f.cost, m1)
b2 = break_even(f.cost, m2)
puts "#{f.name}(#{f.color}) 目:#{f.range} コスト:#{f.cost} 収入:#{f.income}"
puts "サイコロが1つ 期待値:#{m1} 元が取れるターン数:#{b1}"
puts "サイコロが2つ 期待値:#{m2} 元が取れるターン数:#{b2}"
puts ""
end
end
end
player_number = (ARGV[0] || 4).to_i
Machikoro.new(player_number: player_number).run
プレイヤー数(試行回数): 4
麦畑(blue) 目:[1] コスト:1 収入:1
サイコロが1つ 期待値:2/3 元が取れるターン数:2
サイコロが2つ 期待値:0 元が取れるターン数:Infinity
牧場(blue) 目:[2] コスト:1 収入:1
サイコロが1つ 期待値:2/3 元が取れるターン数:2
サイコロが2つ 期待値:1/9 元が取れるターン数:9
パン屋(green) 目:[2, 3] コスト:1 収入:1
サイコロが1つ 期待値:1/3 元が取れるターン数:3
サイコロが2つ 期待値:1/12 元が取れるターン数:12
コンビニ(green) 目:[4] コスト:2 収入:4
サイコロが1つ 期待値:2/3 元が取れるターン数:3
サイコロが2つ 期待値:1/3 元が取れるターン数:6
カフェ(red) 目:[3] コスト:2 収入:3
サイコロが1つ 期待値:3/2 元が取れるターン数:1
サイコロが2つ 期待値:1/2 元が取れるターン数:4
森林(blue) 目:[5] コスト:3 収入:1
サイコロが1つ 期待値:2/3 元が取れるターン数:5
サイコロが2つ 期待値:4/9 元が取れるターン数:7
鉱山(blue) 目:[9] コスト:6 収入:5
サイコロが1つ 期待値:0 元が取れるターン数:Infinity
サイコロが2つ 期待値:20/9 元が取れるターン数:3
ファミレス(red) 目:[9, 10] コスト:3 収入:2
サイコロが1つ 期待値:0 元が取れるターン数:Infinity
サイコロが2つ 期待値:7/6 元が取れるターン数:3
リンゴ園(blue) 目:[10] コスト:3 収入:2
サイコロが1つ 期待値:0 元が取れるターン数:Infinity
サイコロが2つ 期待値:2/3 元が取れるターン数:5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment