class Zombie
THAW_TIME = 10.0
NORMAL_SPEED = 0.3
SLOW_SPEED = 0.15
PEA_SPEED = 3.0
FIRE_PERIOD = 1.4
@@collisions = 0
attr_reader :path
def initialize index
@state = :normal
@now = 0.0
@x = 0.0
@last_collision = nil
@path = ['M', 0, 0]
end
def next_event
result = Event.new next_collide, :slow_down, self
if @state == :slow
time = @last_collision + THAW_TIME
result = Event.new time, :speed_up, self if time < result.time
end
result
end
def next_collide
v = speed
(v*@now + PEA_SPEED*FIRE_PERIOD*@@collisions - @x) / (v + PEA_SPEED)
end
def slow_down time
@@collisions += 1
@last_collision = time
@x += (time - @now) * speed
@now = time
@state = :slow
step_path
end
def speed_up time
@x += (time - @now) * SLOW_SPEED
@now = time
@state = :normal
step_path
end
def step_path
@path.push 'L', @now*10, @x*50
end
def speed
{normal: NORMAL_SPEED, slow: SLOW_SPEED}[@state]
end
def average_speed
@x / @now
end
end
Event = Struct.new :time, :action, :zombie do
def occur
zombie.public_send action, time
end
end
def simulate n
zombies = Array.new(n) { Zombie.new _1 }.lazy
(n * 500).times do
zombies.map(&:next_event).min_by(&:time).occur
end
zombies.sum(&:average_speed) / n
end# your code goes here
Y2xhc3MgWm9tYmllCiAgVEhBV19USU1FID0gMTAuMAogIE5PUk1BTF9TUEVFRCA9IDAuMwogIFNMT1dfU1BFRUQgPSAwLjE1CiAgUEVBX1NQRUVEID0gMy4wCiAgRklSRV9QRVJJT0QgPSAxLjQKICBAQGNvbGxpc2lvbnMgPSAwCiAgYXR0cl9yZWFkZXIgOnBhdGgKICBkZWYgaW5pdGlhbGl6ZSBpbmRleAogICAgQHN0YXRlID0gOm5vcm1hbAogICAgQG5vdyA9IDAuMAogICAgQHggPSAwLjAKICAgIEBsYXN0X2NvbGxpc2lvbiA9IG5pbAogICAgQHBhdGggPSBbJ00nLCAwLCAwXQogIGVuZAogIGRlZiBuZXh0X2V2ZW50CiAgICByZXN1bHQgPSBFdmVudC5uZXcgbmV4dF9jb2xsaWRlLCA6c2xvd19kb3duLCBzZWxmCiAgICBpZiBAc3RhdGUgPT0gOnNsb3cKICAgICAgdGltZSA9IEBsYXN0X2NvbGxpc2lvbiArIFRIQVdfVElNRQogICAgICByZXN1bHQgPSBFdmVudC5uZXcgdGltZSwgOnNwZWVkX3VwLCBzZWxmIGlmIHRpbWUgPCByZXN1bHQudGltZQogICAgZW5kCiAgICByZXN1bHQKICBlbmQKICBkZWYgbmV4dF9jb2xsaWRlCiAgICB2ID0gc3BlZWQKICAgICh2KkBub3cgKyBQRUFfU1BFRUQqRklSRV9QRVJJT0QqQEBjb2xsaXNpb25zIC0gQHgpIC8gKHYgKyBQRUFfU1BFRUQpCiAgZW5kCiAgZGVmIHNsb3dfZG93biB0aW1lCiAgICBAQGNvbGxpc2lvbnMgKz0gMQogICAgQGxhc3RfY29sbGlzaW9uID0gdGltZQogICAgQHggKz0gKHRpbWUgLSBAbm93KSAqIHNwZWVkCiAgICBAbm93ID0gdGltZQogICAgQHN0YXRlID0gOnNsb3cKICAgIHN0ZXBfcGF0aAogIGVuZAogIGRlZiBzcGVlZF91cCB0aW1lCiAgICBAeCArPSAodGltZSAtIEBub3cpICogU0xPV19TUEVFRAogICAgQG5vdyA9IHRpbWUKICAgIEBzdGF0ZSA9IDpub3JtYWwKICAgIHN0ZXBfcGF0aAogIGVuZAogIGRlZiBzdGVwX3BhdGgKICAgIEBwYXRoLnB1c2ggJ0wnLCBAbm93KjEwLCBAeCo1MAogIGVuZAogIGRlZiBzcGVlZAogICAge25vcm1hbDogTk9STUFMX1NQRUVELCBzbG93OiBTTE9XX1NQRUVEfVtAc3RhdGVdCiAgZW5kCiAgZGVmIGF2ZXJhZ2Vfc3BlZWQKICAgIEB4IC8gQG5vdwogIGVuZAplbmQKCkV2ZW50ID0gU3RydWN0Lm5ldyA6dGltZSwgOmFjdGlvbiwgOnpvbWJpZSBkbwogIGRlZiBvY2N1cgogICAgem9tYmllLnB1YmxpY19zZW5kIGFjdGlvbiwgdGltZQogIGVuZAplbmQKCmRlZiBzaW11bGF0ZSBuCiAgem9tYmllcyA9IEFycmF5Lm5ldyhuKSB7IFpvbWJpZS5uZXcgXzEgfS5sYXp5CiAgKG4gKiA1MDApLnRpbWVzIGRvCiAgICB6b21iaWVzLm1hcCgmOm5leHRfZXZlbnQpLm1pbl9ieSgmOnRpbWUpLm9jY3VyCiAgZW5kCiAgem9tYmllcy5zdW0oJjphdmVyYWdlX3NwZWVkKSAvIG4KZW5kIyB5b3VyIGNvZGUgZ29lcyBoZXJl