mirror of
https://github.com/samsonjs/mystery7-simulator.git
synced 2026-04-20 13:45:48 +00:00
first commit
This commit is contained in:
commit
c9954af3de
5 changed files with 270 additions and 0 deletions
2
Gemfile
Normal file
2
Gemfile
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
gem 'trollop'
|
||||
gem 'sqlite3'
|
||||
11
Gemfile.lock
Normal file
11
Gemfile.lock
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
GEM
|
||||
specs:
|
||||
sqlite3 (1.3.5)
|
||||
trollop (1.16.2)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
sqlite3
|
||||
trollop
|
||||
13
result.rb
Normal file
13
result.rb
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
class Result
|
||||
attr_accessor :roll, :sets, :parity, :colour, :highlow, :abc, :fmu
|
||||
|
||||
def initialize(options)
|
||||
@roll = options[:roll]
|
||||
@sets = options[:sets]
|
||||
@parity = options[:parity]
|
||||
@colour = options[:colour]
|
||||
@highlow = options[:highlow]
|
||||
@abc = options[:abc]
|
||||
@fmu = options[:fmu]
|
||||
end
|
||||
end
|
||||
188
roulette.rb
Normal file
188
roulette.rb
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
require 'rubygems'
|
||||
require 'bundler/setup'
|
||||
require 'sqlite3'
|
||||
require './result'
|
||||
|
||||
class Roulette
|
||||
|
||||
# B: Black
|
||||
# G: Green
|
||||
# R: Red
|
||||
Colours = {
|
||||
'American' => %w[G R B R B R B R B R B B R B R B R B R R B R B R B R B R B B R B R B R B R G],
|
||||
'European' => %w[G R B R B R B R B R B B R B R B R B R R B R B R B R B R B B R B R B R B R]
|
||||
}
|
||||
|
||||
# F: Foundation
|
||||
# M: Middle
|
||||
# U: Upper
|
||||
FMU = {
|
||||
'American' => ['Z'] + %w[F M U] * 12,
|
||||
'European' => ['Z'] + %w[F M U] * 12 + ['Z']
|
||||
}
|
||||
|
||||
Sets = {
|
||||
:j => [1, 2, 3, 13, 15, 26, 27],
|
||||
:k => [4, 5, 6, 16, 17, 28, 30],
|
||||
:m => [7, 8, 19, 20, 21, 31, 32],
|
||||
:c => [11, 12, 22, 24, 34, 35, 36],
|
||||
:n => [9, 10, 14, 18, 23, 25, 29],
|
||||
:z => [0, 2, 16, 19, 33, 36]
|
||||
}
|
||||
|
||||
BettingSequence = [1, 1, 1, 1, 1, 2, 2, 3, 3, 4, 5, 6, 8, 10, 12, 15]
|
||||
NetProfits = [29, 22, 15, 8, 1, 23, 9, 24, 3, 11, 12, 6, 22, 24, 12, 15]
|
||||
|
||||
attr_accessor :results, :counts, :set_status
|
||||
|
||||
def initialize(options)
|
||||
@options = options
|
||||
@colours = Colours[@options[:style]]
|
||||
@fmu = FMU[@options[:style]]
|
||||
@sets = {}
|
||||
Sets.keys.each do |key|
|
||||
@sets[key] = Sets[key].dup
|
||||
end
|
||||
if @options[:style] == 'American'
|
||||
@sets[:z] << 37
|
||||
else
|
||||
@sets[:z].insert(2, 5)
|
||||
end
|
||||
|
||||
@rng = @options[:seed] ? Random.new(@options[:seed]) : Random.new
|
||||
|
||||
# generated numbers are from 0 to max
|
||||
@max = @options[:style] == 'American' ? 38 : 37
|
||||
|
||||
@set_status = {}
|
||||
Sets.keys.each do |key|
|
||||
@set_status[key] = {
|
||||
:net => 0,
|
||||
:sequence => 0,
|
||||
:sleeping => true,
|
||||
:snakes => 0,
|
||||
:wins => 0
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def simulate
|
||||
@results = []
|
||||
@counts = Hash.new { 0 }
|
||||
|
||||
@options[:iterations].times do
|
||||
result = spin
|
||||
record(result) if @options[:record]
|
||||
if @results.length % 100_000 == 0
|
||||
print @results.length / 100000
|
||||
elsif @results.length % 10_000 == 0
|
||||
print '.'
|
||||
end
|
||||
end
|
||||
puts
|
||||
end
|
||||
|
||||
def spin
|
||||
if @options[:fixed_input]
|
||||
n = @options[:input].shift
|
||||
else
|
||||
n = @rng.rand(@max)
|
||||
end
|
||||
letters = []
|
||||
@sets.each do |letter, set|
|
||||
status = @set_status[letter]
|
||||
if set.include?(n)
|
||||
if status[:sleeping]
|
||||
status[:sleeping] = false
|
||||
else
|
||||
status[:net] += NetProfits[status[:sequence]]
|
||||
status[:sequence] = 0
|
||||
status[:wins] += 1
|
||||
end
|
||||
@counts[letter] += 1
|
||||
letters << letter
|
||||
end
|
||||
end
|
||||
@set_status.each do |letter, status|
|
||||
next if letters.include?(letter)
|
||||
status[:sequence] += 1 unless status[:sleeping]
|
||||
# snake
|
||||
if status[:sequence] >= BettingSequence.length
|
||||
puts "#{letter}: SNAKE!" if @options[:verbose]
|
||||
status[:sequence] = 0
|
||||
status[:sleeping] = true
|
||||
status[:snakes] += 1
|
||||
status[:net] -= 525
|
||||
end
|
||||
if status[:sequence] > 0 && status[:sequence] % @options[:misses] == 0
|
||||
status[:sleeping] = true
|
||||
end
|
||||
end
|
||||
result = Result.new(
|
||||
:roll => n,
|
||||
:sets => letters.join(','),
|
||||
:parity => parity(n),
|
||||
:colour => colour(n),
|
||||
:highlow => high_or_low(n),
|
||||
:abc => abc(n),
|
||||
:fmu => fmu(n)
|
||||
)
|
||||
if @options[:verbose]
|
||||
puts @results.length
|
||||
puts result.inspect
|
||||
@set_status.each do |letter, status|
|
||||
puts "#{letter}: #{status.inspect}"
|
||||
end
|
||||
puts
|
||||
end
|
||||
@results << result
|
||||
result
|
||||
end
|
||||
|
||||
def seed
|
||||
@rng.seed
|
||||
end
|
||||
|
||||
def parity(n)
|
||||
if n.even? then 'E' else 'O' end
|
||||
end
|
||||
|
||||
def colour(n)
|
||||
@colours[n]
|
||||
end
|
||||
|
||||
def high_or_low(n)
|
||||
if n <= 18 then 'H' else 'L' end
|
||||
end
|
||||
|
||||
def abc(n)
|
||||
if n <= 12
|
||||
'A'
|
||||
elsif n <= 24
|
||||
'B'
|
||||
else
|
||||
'C'
|
||||
end
|
||||
end
|
||||
|
||||
def fmu(n)
|
||||
@fmu[n]
|
||||
end
|
||||
|
||||
def db
|
||||
unless @db
|
||||
@db = SQLite3::Database.new(@options[:database])
|
||||
@db.execute('drop table if exists results')
|
||||
@db.execute('create table results (roll integer, sets varchar(10), parity varchar(1), colour varchar(1), highlow varchar(1), abc varchar(1), fmu varchar(1))')
|
||||
end
|
||||
@db
|
||||
end
|
||||
|
||||
def record(result)
|
||||
db.execute("insert into results values (#{result.roll}, '#{result.sets}', '#{result.parity}', '#{result.colour}', '#{result.highlow}', '#{result.abc}', '#{result.fmu}')")
|
||||
rescue
|
||||
sleep 1
|
||||
record(result)
|
||||
end
|
||||
|
||||
end
|
||||
56
simulate.rb
Executable file
56
simulate.rb
Executable file
|
|
@ -0,0 +1,56 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'rubygems'
|
||||
require 'bundler/setup'
|
||||
require 'trollop'
|
||||
require './roulette'
|
||||
|
||||
def main
|
||||
options = Trollop::options do
|
||||
opt :style, "American or European", :short => 's', :type => String, :default => 'American'
|
||||
opt :iterations, "Number of iterations", :short => 'i', :type => :int, :default => 120
|
||||
opt :database, "Filename for results database", :type => String, :default => File.expand_path("~/Projects/Mystery7/results.sqlite")
|
||||
opt :record, "Record results", :short => 'r'
|
||||
opt :seed, "Seed for the RNG", :type => :int
|
||||
opt :misses, "Number of misses before sleeping", :short => 'm', :default => 4
|
||||
opt :verbose, "Print stats after each spin", :short => 'v'
|
||||
end
|
||||
|
||||
# options[:fixed_input] = true
|
||||
# options[:input] = [13, 3, 22, 10, 33, 22, 3, 37, 24, 5, 33, 22, 6, 25, 2, 34, 32, 1, 23, 28, 17, 19, 34, 33, 27, 7, 8, 0, 24, 8, 10, 6, 0, 23, 2, 10, 20, 30, 2, 21, 15, 3, 30, 19, 36, 6, 1, 24, 8, 2, 30, 36, 28, 26, 10, 36, 13, 0, 23, 24, 23, 25, 8, 3, 20, 11, 34, 30, 11, 35, 33, 32, 21, 23, 17, 9, 12, 18, 25, 17, 30, 31, 30, 27, 12, 15, 10, 17, 36, 29, 32, 15, 11, 25, 10, 23, 13, 22, 8, 7, 32, 4, 26, 14, 26, 0, 10, 18, 6, 26, 18, 23, 4, 2, 26, 27, 20, 29, 21, 37]
|
||||
# options[:iterations] = options[:input].length
|
||||
|
||||
article = options[:style] == 'American' ? 'an' : 'a'
|
||||
puts ">>> Simulating #{article} #{options[:style]} style game with #{options[:iterations]} iterations, sleeping after #{options[:misses]} miss#{options[:misses] > 0 ? 'es' : ''}..."
|
||||
|
||||
roulette = Roulette.new(options)
|
||||
|
||||
puts ">>> Seed: #{roulette.seed}"
|
||||
|
||||
roulette.simulate
|
||||
|
||||
status = {
|
||||
:net => 0,
|
||||
:sequence => 0,
|
||||
:sleeping => true,
|
||||
:snakes => 0,
|
||||
:wins => 0
|
||||
}
|
||||
|
||||
Roulette::Sets.each do |letter, set|
|
||||
puts "# of #{letter.to_s.upcase}s: #{roulette.counts[letter]}" if options[:verbose]
|
||||
set_status = roulette.set_status[letter]
|
||||
puts "status: #{set_status.inspect}" if options[:verbose]
|
||||
status[:net] += set_status[:net]
|
||||
status[:snakes] += set_status[:snakes]
|
||||
status[:wins] += set_status[:wins]
|
||||
end
|
||||
|
||||
puts "Net profit: #{status[:net]}"
|
||||
puts "Wins: #{status[:wins]}"
|
||||
puts "Snakes: #{status[:snakes]}"
|
||||
|
||||
puts ">>> Results are in #{options[:database]}." if options[:record]
|
||||
end
|
||||
|
||||
main if __FILE__ == $0
|
||||
Loading…
Reference in a new issue