From 5ce9363f907c747e3300d0b6fe29e23c55dac1ad Mon Sep 17 00:00:00 2001 From: Monica Moniot Date: Sat, 24 Sep 2022 17:03:03 -0500 Subject: [PATCH] added missing train handling --- main.lua | 151 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 116 insertions(+), 35 deletions(-) diff --git a/main.lua b/main.lua index 72b3413..b058e1f 100644 --- a/main.lua +++ b/main.lua @@ -2,37 +2,96 @@ local function get_item_amount(station, item_id) return 0 end +local function get_valid_train(stations, r_station_i, p_station_i, available_trains) + return 0 +end + local function get_distance(stations, r_station_i, p_station_i) return 0 end -local function send_train_between(stations, r_station_i, p_station_i) - stations[r_station_i].last_p_station_i = p_station_i - stations[p_station_i].last_r_station_i = r_station_i +local function send_train_between(stations, r_station_i, p_station_i, train) + local r_station = stations[r_station_i] + local p_station = stations[p_station_i] + r_station.last_p_station_i = p_station_i + p_station.last_r_station_i = r_station_i + + r_station.deliveries_total = r_station.deliveries_total + 1 + p_station.deliveries_total = p_station.deliveries_total + 1 + + local r_amount = get_item_amount(r_station, item_id) + r_station.delivery_amount[item_id] + local p_amount = get_item_amount(p_station, item_id) + p_station.delivery_amount[item_id] + local transfer_amount = math.min(train.capacity, -r_amount, p_amount) + assert(transfer_amount > 0, "main.lua error, transfer amount was not positive") + + r_station.delivery_amount[item_id] = r_station.delivery_amount[item_id] + transfer_amount + p_station.delivery_amount[item_id] = p_station.delivery_amount[item_id] - transfer_amount end --[[ - station: + station: { deliveries_total: int train_limit: int - requester_limit: int - provider_limit: int + requester_limit: int > 0 + provider_limit: int > 0 priority: int + last_delivery_tick: int + train_layout: [ [ { + [car_type]: true|nil + } ] ] + accepted_layouts: { + [layout_id]: true|nil + } + } + available_trains: [{ + layout_id: int + capacity: int + }] ]] -local function tick(stations, all_items) - for _, item_id in pairs(all_items) do +--local function check_train_layouts(station, available_layouts) +-- for _, layout_id in ipairs(available_layouts) do +-- if station.accepted_layouts[layout_id] then +-- return true +-- end +-- end +-- return false +--end + +local function icpairs(a, start_i) + start_i = start_i%#a + 1 + local i = start_i - 1 + local flag = true + return function() + i = i%#a + 1 + if i ~= start_i or flag then + flag = false + local v = a[i] + if v then + return i, v + end + end + end +end + + +local function tick(stations, all_items, available_trains, ticks_total) + if #all_items == 0 then + return + end + local failed_because_missing_trains_total = 0 + --psuedo-randomize what item (and what station) to check first so if trains available is low they choose orders psuedo-randomly + for _, item_id in icpairs(all_items, ticks_total) do local r_stations = {} local p_stations = {} for station_i, station in pairs(stations) do if station.deliveries_total < station.train_limit then - local item_amount = get_item_amount(station, item_id) - local delivery_amount = station.delivery_amount + local item_amount = get_item_amount(station, item_id) + station.delivery_amount[item_id] - if -(item_amount + delivery_amount) >= station.requester_limit then + if -item_amount >= station.requester_limit then table.insert(r_stations, station_i) - elseif item_amount + delivery_amount >= station.provider_limit then + elseif item_amount >= station.provider_limit then table.insert(p_stations, station_i) end end @@ -43,43 +102,65 @@ local function tick(stations, all_items) if #r_stations > 0 and #p_stations > 0 then if #r_stations <= #p_stations then --backpressure, prioritize locality - for i, r_station_i in ipairs(r_stations) do - local best = 1 + for i, r_station_i in icpairs(r_stations, ticks_total) do + + local best = 0 + local best_train = nil local best_dist = math.huge local highest_prior = -math.huge + local could_have_been_serviced = false for j, p_station_i in ipairs(p_stations) do local d = get_distance(stations, r_station_i, p_station_i) local prior = stations[p_station_i].priority - if prior > highest_prior then - best = j - best_dist = d - highest_prior = prior - elseif prior == highest_prior and d < best_dist then - best = j - best_dist = d + if prior > highest_prior or (prior == highest_prior and d < best_dist) then + local train, is_possible = get_valid_train(stations, r_station_i, p_station_i, available_trains) + if train then + best = j + best_dist = d + best_train = train + highest_prior = prior + elseif is_possible then + could_have_been_serviced = true + end end end - send_train_between(stations, r_station_i, p_stations[best]) - table.remove(p_stations, best) + if best > 0 then + send_train_between(stations, r_station_i, p_stations[best], best_train) + table.remove(p_stations, best) + elseif could_have_been_serviced then + failed_because_missing_trains_total = failed_because_missing_trains_total + 1 + end end else --prioritize round robin - for j, p_station_i in ipairs(p_stations) do - local best = 1 + for j, p_station_i in icpairs(p_stations, ticks_total) do + + local best = 0 + local best_train = nil + local lowest_tick = math.huge local highest_prior = -math.huge - local last_r_station_i = stations[p_station_i].last_r_station_i + local could_have_been_serviced = false for i, r_station_i in ipairs(r_stations) do - local prior = stations[r_station_i].priority - if r_stations[i] > last_r_station_i then - prior = prior + .5 - end - if prior > highest_prior then - best = i - highest_prior = prior + local r_station = stations[r_station_i] + local prior = r_station.priority + if prior > highest_prior or (prior == highest_prior and r_station.last_delivery_tick < lowest_tick) then + local train, is_possible = get_valid_train(stations, r_station_i, p_station_i, available_trains) + if train then + best = i + best_train = train + lowest_tick = r_station.last_delivery_tick + highest_prior = prior + elseif is_possible then + could_have_been_serviced = true + end end end - send_train_between(stations, r_stations[best], p_station_i) - table.remove(r_stations, best) + if best > 0 then + send_train_between(stations, r_stations[best], p_station_i, best_train) + table.remove(r_stations, best) + elseif could_have_been_serviced then + failed_because_missing_trains_total = failed_because_missing_trains_total + 1 + end end end end