ensure bundles don't contains cycles
This commit is contained in:
parent
7aa0ab57ac
commit
ff661daa7d
1
main.lua
1
main.lua
@ -1,5 +1,4 @@
|
||||
local ui = require("ui")
|
||||
local term_stack = require("term-stack")
|
||||
|
||||
require("dbg")("logs.txt")
|
||||
|
||||
|
105
views/main.lua
105
views/main.lua
@ -19,6 +19,10 @@ local function copy_table(t)
|
||||
return t_copy
|
||||
end
|
||||
|
||||
local function is_integer(num)
|
||||
return num % 1 == 0
|
||||
end
|
||||
|
||||
local function list_items(inventories)
|
||||
local item_registry = {}
|
||||
for _, name in ipairs(inventories) do
|
||||
@ -96,6 +100,39 @@ local function is_bundle_name(name)
|
||||
return name:find("#") == 1
|
||||
end
|
||||
|
||||
local function do_bundles_contain_cycle(bundles)
|
||||
local visited = {}
|
||||
local stack = {}
|
||||
|
||||
local function is_cyclic_util(bundle_name)
|
||||
if not visited[bundle_name] then
|
||||
visited[bundle_name] = true
|
||||
stack[bundle_name] = true
|
||||
|
||||
for dep_name in pairs(bundles[bundle_name]) do
|
||||
if is_bundle_name(dep_name) then
|
||||
dep_name = dep_name:sub(2)
|
||||
if not visited[dep_name] and is_cyclic_util(dep_name) then
|
||||
return true
|
||||
elseif stack[dep_name] then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
stack[bundle_name] = false
|
||||
return false
|
||||
end
|
||||
|
||||
for bundle_name in pairs(bundles) do
|
||||
if not visited[bundle_name] and is_cyclic_util(bundle_name) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- TODO: improve this function
|
||||
local function resolve_bundle_items(bundles, bundle_name, seen_bundles)
|
||||
seen_bundles = seen_bundles or {}
|
||||
@ -218,6 +255,8 @@ function main_view:prepare(inventories, bundles, result_inventory)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
function main_view:list_filtered_names(items, bundles, name_filter)
|
||||
name_filter = name_filter:lower()
|
||||
|
||||
@ -293,17 +332,21 @@ function main_view:process_movement_keys(store, area)
|
||||
local bundle = self.bundle_details[bundle_name]
|
||||
|
||||
if self.right_pressed and lstore.bundles[bundle_name] > 0 then
|
||||
for item, count in pairs(bundle) do
|
||||
lstore.items[item] = lstore.items[item] - count
|
||||
end
|
||||
local transferred = math.min(lstore.bundles[bundle_name], 1)
|
||||
rstore.bundles[bundle_name] = (rstore.bundles[bundle_name] or 0) + transferred
|
||||
|
||||
elseif self.left_pressed and rstore.bundles[bundle_name] > 0 then
|
||||
for item, count in pairs(bundle) do
|
||||
lstore.items[item] = lstore.items[item] + count
|
||||
lstore.items[item] = lstore.items[item] - math.floor(count * transferred)
|
||||
end
|
||||
rstore.bundles[bundle_name] = (rstore.bundles[bundle_name] or 0) + transferred
|
||||
elseif self.left_pressed and rstore.bundles[bundle_name] > 0 then
|
||||
local transferred
|
||||
if is_integer(rstore.bundles[bundle_name]) then
|
||||
transferred = math.min(rstore.bundles[bundle_name], 1)
|
||||
else
|
||||
transferred = rstore.bundles[bundle_name] % 1
|
||||
end
|
||||
for item, count in pairs(bundle) do
|
||||
lstore.items[item] = lstore.items[item] + math.floor(count * transferred)
|
||||
end
|
||||
local transferred = math.min(rstore.bundles[bundle_name], 1)
|
||||
rstore.bundles[bundle_name] = rstore.bundles[bundle_name] - transferred
|
||||
end
|
||||
else
|
||||
@ -337,9 +380,6 @@ function main_view:display_list(store, area, selected_idx)
|
||||
local function get_number_width(num)
|
||||
return math.floor(math.log(num, 10) + 1)
|
||||
end
|
||||
local function is_integer(num)
|
||||
return num % 1 == 0
|
||||
end
|
||||
|
||||
local count_collumn_width
|
||||
do -- Figure out how wide does the count column need to be
|
||||
@ -427,9 +467,6 @@ function main_view:display_list_with_search(store, area, active)
|
||||
term_stack.pop_cursor()
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
function main_view:move_item(item_name, amount, destination)
|
||||
local item_collection = self.item_registry[item_name]
|
||||
|
||||
@ -488,8 +525,29 @@ function main_view:deposit_items()
|
||||
self:refresh_items()
|
||||
end
|
||||
|
||||
function main_view:save_bundle(name, items)
|
||||
self.bundles[name] = items
|
||||
function main_view:save_bundle(name, items, bundles)
|
||||
local bundle = {}
|
||||
for item, count in pairs(items) do
|
||||
if count > 0 then
|
||||
bundle[item] = count
|
||||
end
|
||||
end
|
||||
for bundle_name, count in pairs(bundles) do
|
||||
if count > 0 then
|
||||
bundle[bundle_name] = count
|
||||
end
|
||||
end
|
||||
self.bundles[name] = bundle
|
||||
if do_bundles_contain_cycle(self.bundles) then
|
||||
self.bundles[name] = nil
|
||||
return false
|
||||
end
|
||||
|
||||
populate_bundle_details(self.bundle_details, self.bundles)
|
||||
self.left_store.bundles = derive_available_bundles(self.left_store.items, self.bundle_details)
|
||||
self:refresh_filtered_names(self.left_store, self.left_area)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function main_view:display_bundle_popup(area)
|
||||
@ -518,7 +576,10 @@ function main_view:display_bundle_popup(area)
|
||||
self.bundle_popup = false
|
||||
elseif self.submit_pressed and #self.bundle_name > 0 then
|
||||
self.bundle_popup = false
|
||||
self:save_bundle(self.bundle_name, self.right_store.items)
|
||||
local success = self:save_bundle(self.bundle_name, self.right_store.items, self.right_store.bundles)
|
||||
if success then
|
||||
self.bundle_name = ""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -534,8 +595,9 @@ function main_view:request_items()
|
||||
for bundle_name, bundle_count in pairs(rstore.bundles) do
|
||||
bundle_count = math.max(bundle_count, 1)
|
||||
for item, count in pairs(self.bundle_details[bundle_name]) do
|
||||
local transferred = self:move_item(item, count*bundle_count, self.result_inventory)
|
||||
lstore.items[item] = lstore.items[item] + (count*bundle_count - transferred)
|
||||
local amount = math.floor(count*bundle_count)
|
||||
local transferred = self:move_item(item, amount, self.result_inventory)
|
||||
lstore.items[item] = lstore.items[item] + (amount - transferred)
|
||||
end
|
||||
end
|
||||
|
||||
@ -548,9 +610,10 @@ function main_view:request_items()
|
||||
local selected_option = lstore.filtered_names[lstore.selected_idx]
|
||||
if is_bundle_name(selected_option) then
|
||||
local bundle_name = selected_option
|
||||
local bundle_count = math.min(lstore.bundles[bundle_name], 1)
|
||||
for item, count in pairs(self.bundle_details[bundle_name]) do
|
||||
local transferred = self:move_item(item, count, self.result_inventory)
|
||||
lstore.items[item] = lstore.items[item] - transferred
|
||||
lstore.items[item] = lstore.items[item] - math.floor(transferred * bundle_count)
|
||||
end
|
||||
else
|
||||
local item = selected_option
|
||||
@ -626,7 +689,7 @@ function main_view:on_key(key)
|
||||
end
|
||||
|
||||
if not self.bundle_popup then
|
||||
if key == keys.n and self:has_selected_items() then
|
||||
if self.ctrl_down and key == keys.n and self:has_selected_items() then
|
||||
self.bundle_popup = true
|
||||
|
||||
elseif key == keys.tab then
|
||||
|
Loading…
Reference in New Issue
Block a user