2010-06-16

World Cup 2010 Monte-Carlo Simulator (2)

Here is the source code of wc2010.rb.

#! /usr/bin/ruby
#
# World Cup 2010 point simulator
# Copyright (C) 2010 Yamauchi Hitoshi
# License: new BSD.
#------------------------------------------------------------

require "getoptlong.rb"

WC2010      = "0.0.0"
MAX_MATCHES = 64

#------------------------------------------------------------
# class Wc2010
#------------------------------------------------------------
class Wc2010
  # constructor
  def initialize()
    # last year's result as probability distribution function
    @sample = [
               4, 2,    0, 2,    1, 0,    0, 0,    2, 1,
               0, 1,    3, 1,    0, 1,    3, 1,    0, 3,
               2, 0,    2, 1,    0, 0,    1, 0,    4, 0,
               2, 2,    1, 0,    3, 0,    2, 0,    1, 0,
               6, 0,    2, 1,    0, 0,    2, 0,    0, 2,
               1, 1,    0, 0,    2, 0,    1, 1,    0, 2,
               0, 4,    3, 1,    0, 3,    1, 2,    2, 0,
               2, 2,    2, 1,    1, 1,    0, 0,    3, 2,
               0, 2,    2, 1,    1, 4,    2, 2,    0, 1,
               1, 0,    0, 2,    2, 0,    2, 0,    2, 1,
               1, 0,    1, 0,    1, 0,    0, 0,    3, 0,
               1, 3,    1, 1,    3, 0,    0, 0,    0, 1,
               0, 2,    0, 1,    3, 1,    1, 1]

    @max_point = @sample.max {
      |a,b|
      a <=> b
    }
    # sample bin. Array [0, 0, ..., 0], size == @max_point + 1
    @sample_bin = Array.new(@max_point + 1, 0)
    @accum_dist = Array.new(@max_point + 1, 0)

    # put them to the bin
    for val in @sample
      @sample_bin[val] = @sample_bin[val] + 1
    end

    @accum_max = 0
    idx   = 0
    for hist in @sample_bin
      @accum_max = @accum_max + hist
      @accum_dist[idx] = @accum_max
      idx   = idx + 1
    end

    idx   = 0
    for val in @accum_dist
      idx   = idx + 1
    end

    @range_array = []
    @range_array << Range.new(0, @accum_dist[0], true)

    # create range objects
    idx = 0
    while idx < (@accum_dist.length - 1)
      @range_array << Range.new(@accum_dist[idx], @accum_dist[idx + 1], true)
      idx = idx + 1
    end

    idx = 0
    for r in @range_array
      idx = idx + 1
    end
  end

  # get random value -> point with the same distribution of last year
  # \param  _rd uniform random value
  # \return generated random variable
  def get_point(_rd)
    begin
      idx = 0
      for r in @range_array
        if r.include? _rd then
          return idx
        end
        idx = idx + 1
      end

      raise RuntimeError.new(_rd.to_s + " is not in any range.\n")
    end
  end

  # run the simulation
  def run()
    begin
      srand(42)                  # always the same for debug.
      idx = 0
      while idx < MAX_MATCHES do
        rd1 = rand(@accum_max)
        rd2 = rand(@accum_max)
        pt1 = get_point(rd1)
        pt2 = get_point(rd2)
        print "[" + (idx + 1).to_s + "]: " + pt1.to_s + ' ' + pt2.to_s + "\n"
        idx = idx + 1
      end
    end
  end
end

#------------------------------
# command line option parsing
#------------------------------
args = GetoptLong.new();
args.set_options(['--version',   '-V', GetoptLong::NO_ARGUMENT]);

begin
  args.each_option do |name, arg|
    # print(name + ", " + arg + ":\n")
    eval "$OPT_#{name.sub(/^--/, '').gsub(/-/, '_').upcase} = '#{arg}'"
  end
rescue
  exit(1)
end

#--- show version
if $OPT_VERSION
  $stderr.print(WC2010 + "\n")
  exit(1)
end

wc = Wc2010.new()
wc.run()

# --- end of wc2010.rb

No comments: