Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Simple simulation for my blog post
SIMULATION_LENGTH=24 * 60 * 60 # one day
ARRIVAL_RATE="random"
ARRIVAL_NUMBER= 240
OVERALL_WIP=8
class Simulation
class Car
attr_accessor :enter_time
attr_accessor :leave_time
def initialize(enter_time)
@enter_time = enter_time
end
def to_s
"car_#{@enter_time}"
end
end
def initialize(simulation_length, arrival_rate, arrival_number, overall_wip)
@order_queue = []
@order_station = {:time => 20}
@pay_queue = []
@pay_station = {:time => 30}
@collect_queue = []
@collect_station = {:time => 40}
@done = []
@simulation_length = simulation_length
@arrival_rate = arrival_rate
@arrival_number = arrival_number
@overall_wip = overall_wip
end
def start
(0..@simulation_length).each do |second|
if @arrival_rate.eql?("random")
new_car_should_arrive = (rand(@arrival_number) == 0)
else
new_car_should_arrive = (second % @arrival_number == 0)
end
if new_car_should_arrive
car = Car.new(second)
@order_queue << car
end
if @order_station[:car]
@order_station[:time] += 1
if @order_station[:time] == 20
# puts "#{second} order done with order: #{@order_station[:car]}"
@pay_queue << @order_station[:car]
@order_station[:car] = nil
end
end
if @order_station[:car] == nil && wip_allows_it?
if !@order_queue.empty?
@order_station[:car] = @order_queue.shift
@order_station[:time] = 0
end
end
if @pay_station[:car]
@pay_station[:time] += 1
if @pay_station[:time] == 30
# puts "#{second} pay done with order: #{@pay_station[:car]}"
@collect_queue << @pay_station[:car]
@pay_station[:car] = nil
end
end
if @pay_station[:car] == nil
if !@pay_queue.empty?
@pay_station[:car] = @pay_queue.shift
@pay_station[:time] = 0
end
end
if @collect_station[:car]
@collect_station[:time] += 1
if @collect_station[:time] == 40
# puts "#{second} collect done with order: #{@collect_station[:car]}"
@collect_station[:car].leave_time = second
@done << @collect_station[:car]
@collect_station[:car] = nil
# -- duplication
if @order_station[:car] == nil && wip_allows_it?
if !@order_queue.empty?
@order_station[:car] = @order_queue.shift
@order_station[:time] = 0
end
end
# -- duplication
end
end
if @collect_station[:car] == nil
if !@collect_queue.empty?
@collect_station[:car] = @collect_queue.shift
@collect_station[:time] = 0
end
end
end
#print_done_content
print_lead_time_distribution
print_throughput
end
private
def wip_allows_it?
# order queue is not part of the wip (it is ~infinite)
current_wip = @pay_queue.size
current_wip += @collect_queue.size
current_wip += 1 if @order_station[:car]
current_wip += 1 if @pay_station[:car]
current_wip += 1 if @collect_station[:car]
current_wip < @overall_wip
end
def print_done_content
@done.each do |car|
puts "#{car.enter_time} -> #{car.leave_time - car.enter_time}"
end
end
def print_lead_time_distribution
distribution = {}
@done.each do |car|
lead_time = car.leave_time - car.enter_time
if distribution[lead_time]
distribution[lead_time] += 1
else
distribution[lead_time] = 1
end
end
distribution.sort_by {|k| k[0].to_i }.each do |key,value|
puts "#{key},#{value}"
end
# puts "longest lead time: #{distribution.sort_by {|k| k[0].to_i }.last[0]}"
end
def print_throughput
throughtput_all = @done.size
puts "throughtput: #{throughtput_all}"
throughtput_per_minute = ((@simulation_length / 60.0) / throughtput_all)
puts "throughtput per minute: #{throughtput_per_minute}"
end
end
# main
Simulation.new(SIMULATION_LENGTH, ARRIVAL_RATE, ARRIVAL_NUMBER, OVERALL_WIP).start
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment