class Weather def self.get_weather(zone, hash = hash(get_seed)) total = 0 APP_DATA[zone][:weather].each do |arr| name, rate = arr if (total += rate) > hash return name end end end def self.forecast(zone, seed = get_seed, count = 10) res = [] prev_hash = hash(seed - 1) prev_weather = get_weather(zone, prev_hash) count.times do |_| curr_hash = hash(seed) curr_weather = get_weather(zone, curr_hash) res.push({ zone: zone, prev_weather: prev_weather, curr_weather: curr_weather, weather_name: get_weather_name(curr_weather), seed: seed, time: Time.at(seed * 1400000.0 / 1000) }) prev_hash = curr_hash prev_weather = curr_weather seed += 1 end res end def self.round_to_last_weather_time(time) last_hour = time.hour / 8 * 8 time.change(hour: last_hour) end def self.get_weather_name(name) case name when "fair" then "Fair Skies" when "showers" then "Showers" when "gales" then "Gales" when "blizzards" then "Blizzards" when "heat" then "Heat" when "thunder" then "Thunderstorms" when "gloom" then "Gloom" when "snow" then "Snow" when "fog" then "Fog" when "umbral_wind" then "Umbral Wind" else "Unknown Weather" end end def self.get_seed (Time.now.utc.to_i * 1000 / 1400000.0).floor end def self.hash(seed = get_seed) base = (seed / 3).floor * 100 + ((seed + 1) % 3) * 8 # Ruby has no other convenient way to convert a signed integer into an unsigned one step1 = [ ((base << 11) ^ base) ].pack("L").unpack("L").first step2 = [ (([ (step1 >> 8) ].pack("L").unpack("L").first.to_i ^ step1)) ].pack("L").unpack("L").first.to_i step2 % 100 end def self.unsigned_right(input, by) input << by & 0xFF00 | input >> by & 0xFF end end