---(( Types ))--- ---@class ItemInfoX : ItemInfo ---@field slot integer ---(( Functions ))--- ---@param inv inventory ---@return table local function listItems(inv) local items = inv.list() for key, item in pairs(items) do item.slot = key end return items end ---@param item ItemInfo ---@return string local function getItemNormalizedName(item) if item.displayName then return item.displayName:lower() end return select(1, item.name:gsub("[^:]+:", "")) end ---@param a ItemInfoX ---@param b ItemInfoX ---@return boolean local function compareItems(a, b) local nameA = getItemNormalizedName(a) local nameB = getItemNormalizedName(b) if nameA ~= nameB then return nameA < nameB end if a.count ~= b.count then return a.count > b.count end return a.slot < b.slot end ---@param unsorted table local function sortItemsTable(unsorted) ---@type ItemInfoX[] local items = {} for _, item in pairs(unsorted) do table.insert(items, item) end table.sort(items, compareItems) return items end ---@param inv inventory ---@param state table local function findEmptySlot(inv, state) local nextEmpty = #state + 1 if nextEmpty > inv.size() then error("Failed to find empty slot in inventory") end return nextEmpty end ---@param inv inventory ---@param state table ---@param fromSlot integer ---@param toSlot integer local function moveItems(inv, state, fromSlot, toSlot) if not state[fromSlot] then error(string.format("move items from slot %d to %d: source slot is empty", fromSlot, toSlot)) end if state[toSlot] then error(string.format("move items from slot %d to %d: target slot is not empty", fromSlot, toSlot)) end local invName = peripheral.getName(inv) inv.pushItems(invName, fromSlot, nil, toSlot) state[toSlot] = state[fromSlot] state[fromSlot] = nil state[toSlot].slot = toSlot end ---@param inv inventory ---@param state table ---@param item ItemInfoX ---@param toSlot integer local function performSortItem(inv, state, item, toSlot) if state[toSlot] then local empty = findEmptySlot(inv, state) moveItems(inv, state, toSlot, empty) end moveItems(inv, state, item.slot, toSlot) end ---@param key integer ---@param item ItemInfoX ---@return boolean local function shouldSort(key, item) return key ~= item.slot end ---@param inv inventory ---@param state table ---@param sorted ItemInfoX[] ---@param sortOps integer local function performSort(inv, state, sorted, sortOps) local fgColor = term.getTextColor() term.setTextColor(colors.gray) local lines = write(string.format("|%s|", string.rep("-", sortOps))) term.setTextColor(colors.yellow) local _, y = term.getCursorPos() term.setCursorPos(1, y - lines) write("|") for key, item in ipairs(sorted) do if shouldSort(key, item) then performSortItem(inv, state, item, key) write("=") end end write("|") print() term.setTextColor(fgColor) end ---@param side string? ---@return inventory local function findChest(side) if side then local p = peripheral.wrap(side) if not p then error(string.format('No peripheral at "%s"', side)) end if not peripheral.hasType(p, "inventory") then error(string.format('Peripheral at "%s" is not an "inventory" type', side)) end return p end if peripheral.hasType("front", "inventory") then return peripheral.wrap("front") end local chest = peripheral.find("inventory") return chest end ---(( Program ))--- local chest = findChest(...) if chest == nil then print("No inventory peripheral found.") return end local origItems = listItems(chest) local sortedItems = sortItemsTable(origItems) print(string.format('Sorting "%s" with %d items...', peripheral.getName(chest), #sortedItems)) local sortOps = 0 for key, item in ipairs(sortedItems) do if shouldSort(key, item) then sortOps = sortOps + 1 end end if sortOps == 0 then print("Already sorted.") return end performSort(chest, origItems, sortedItems, sortOps) print("Sorting done")