jille_Jr icon

CC: Sort chest

jille_Jr | PRO | 07/02/22 01:30:23 PM UTC | 0 ⭐ | 1102 👁️ | Never ⏰ | []
Lua |

4.24 KB

|

None

|

0 👍

/

0 👎

---(( Types ))---
 
---@class ItemInfoX : ItemInfo
---@field slot integer
 
---(( Functions ))---
 
---@param inv inventory
---@return table<integer, ItemInfoX>
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<integer,ItemInfoX>
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<integer, ItemInfoX>
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<integer, ItemInfoX>
---@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<integer, ItemInfoX>
---@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<integer, ItemInfoX>
---@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")
 

Comments