LazyShpee

Snow Plow Algorithm

Sep 29th, 2018
155
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 3.79 KB | None | 0 0
  1. #!/usr/bin/env lua
  2.  
  3. -- Edit those
  4.  
  5. local house_count = 1000
  6. local bounds = { min = -1000, max = 1000}
  7.  
  8. -- Init and helper functions ---------------------------------------
  9.  
  10. math.randomseed(os.time())
  11.  
  12. local total_time = 0
  13. local snow_plow
  14. local street = {}
  15.  
  16. local function house_exists(distance)
  17.     for i, house in ipairs(street) do
  18.         if house.x == distance then
  19.             return house
  20.         end
  21.     end
  22. end
  23.  
  24. for i=1,house_count do
  25.     local distance
  26.     repeat -- Makes sure no houses are at the same spot
  27.         distance = math.random() * (bounds.max - bounds.min) + bounds.min
  28.     until not house_exists(distance)
  29.     if distance ~= 0 then -- House at 0 is clean by default
  30.         local new_house = {
  31.             clean = false,
  32.             x = distance,
  33.             time = 0
  34.         }
  35.  
  36.         street[#street + 1] = new_house
  37.     end
  38. end
  39.  
  40. do -- Adding a dummy house at 0 to be the starting point
  41.     local new_house = {
  42.         index = #street + 1,
  43.         clean = true,
  44.         x = 0,
  45.         dummy = true
  46.     }
  47.     street[#street + 1] = new_house
  48. end
  49.  
  50. table.sort(street, function(a, b) return a.x < b.x end)
  51.  
  52. for i, house in ipairs(street) do
  53.     if i < #street then
  54.         house.next = street[i + 1]
  55.     end
  56.     if i > 1 then
  57.         house.prev = street[i - 1]
  58.     end
  59.     if house.dummy then
  60.         snow_plow = house
  61.     else
  62.         print(("%g"):format(house.x))
  63.     end
  64. end
  65.  
  66. -- Calculates the density of house per max distance to the left and right of the plow
  67. local function get_lr_density()
  68.     local cursor = snow_plow
  69.     local left, right = 0, 0
  70.  
  71.     while cursor.prev do
  72.         cursor = cursor.prev
  73.         if not cursor.clean then -- house isn't clean and should be counted
  74.             left = left + 1
  75.         end
  76.     end
  77.     if cursor ~= snow_plow then
  78.         left = left / math.abs(cursor.x - snow_plow.x)
  79.     end
  80.  
  81.     cursor = snow_plow
  82.     while cursor.next do
  83.         cursor = cursor.next
  84.         if not cursor.clean then -- house isn't clean and should be counted
  85.             right = right + 1
  86.         end
  87.     end
  88.     if cursor ~= snow_plow then
  89.         right = right / math.abs(cursor.x - snow_plow.x)
  90.     end
  91.  
  92.     return left, right
  93. end
  94.  
  95. -- Actual algorithm ------------------------------------------
  96.  
  97. while true do
  98.     local left, right = get_lr_density()
  99.     if left == 0 and right == 0 then break end -- We're done
  100.  
  101.     local old_x = snow_plow.x
  102.     if left > right then -- left has more people
  103.         while snow_plow.prev and snow_plow.clean do -- go left until we find the next unclean house
  104.             snow_plow = snow_plow.prev
  105.         end
  106.     else -- right has more people
  107.         while snow_plow.next and snow_plow.clean do -- go right until we find the next unclean house
  108.             snow_plow = snow_plow.next
  109.         end
  110.     end
  111.     local time = math.abs(old_x - snow_plow.x) -- Time spent during this maneuver
  112.     for i, house in ipairs(street) do
  113.         if not house.clean then -- Add wait time to every unclean house ...
  114.             house.time = house.time + time
  115.         end
  116.     end
  117.     total_time = total_time + time -- ... and to the total timer
  118.     snow_plow.clean = true -- Clean the house after adding the wait time
  119. end
  120.  
  121. -- Recap stuff
  122.  
  123. local total_times = 0
  124. local total_houses = 0
  125.  
  126. for i, house in ipairs(street) do
  127.     if not house.dummy then
  128.         total_times = total_times + house.time
  129.         total_houses = total_houses + 1
  130.     end
  131. end
  132.  
  133. local avg = total_times / total_houses
  134.  
  135. print(([[-----------------
  136. Done !
  137. Cleaned %d houses on a street going from %g to %g
  138. Spent %g (UNIT) of total time (or distance)
  139. Average wait time is %g (UNIT)
  140. Total time to average ratio is %g (higher is better)]]):format(total_houses, bounds.min, bounds.max, total_time, avg, total_time / avg))
Advertisement
Add Comment
Please, Sign In to add comment