glitchdetector icon

EMC Graphing

glitchdetector | PRO | 10/14/23 09:02:56 PM UTC (Edited) | 0 ⭐ | 1205 👁️ | Never ⏰ | []
Lua |

7.76 KB

|

None

|

0 👍

/

0 👎

-- Computercraft Program
-- by glitchdetector
 
function ReadableNumber(num, places, full)
    num = tonumber(num)
    if not num then return 0 end
    local ret
    local placeValue = ("%%.%df"):format(places or 0)
    local isNegative = num < 0
    num = math.abs(num)
    if num >= 1000000000000 then
        ret = placeValue:format(num / 1000000000000) .. (full and " trillion" or "T") -- trillion
    elseif num >= 1000000000 then
        ret = placeValue:format(num / 1000000000) .. (full and " billion" or "B") -- billion
    elseif num >= 1000000 then
        ret = placeValue:format(num / 1000000) .. (full and " million" or "M") -- million
    elseif num >= 1000 and not full then
        ret = placeValue:format(num / 1000) .. "k" -- thousand
    elseif num >= 1 then
        ret = ("%.0f"):format(num) -- hundreds
    else
        ret = num
    end
    return (isNegative and "- " or "") .. ret
end
 
function GetEMC(link)
    local items = link.list()
    if not items then return 0 end
    if not items[1] then return 0 end
    return items[1].count or 0
end
 
function ClearScreen(monitor)
    monitor.clear()
    monitor.setCursorPos(1, 1)
end
 
function NextLine(monitor)
    local x, y = monitor.getCursorPos()
    monitor.setCursorPos(1, y + 1)
end
 
function WriteCenterAligned(monitor, text)
    local w, h = monitor.getSize()
    local x, y = monitor.getCursorPos()
    monitor.setCursorPos(math.ceil(w / 2 - #text / 2), y)
    monitor.write(text)
end
 
function WriteLeftAligned(monitor, text)
    local x, y = monitor.getCursorPos()
    monitor.setCursorPos(1, y)
    monitor.write(text)
end
 
function WriteRightAligned(monitor, text)
    local w, h = monitor.getSize()
    local x, y = monitor.getCursorPos()
    monitor.setCursorPos(w - #text + 1, y)
    monitor.write(text)
end
 
-- Program Code
 
local Users = {
    {"top", "Glitch"},
    {"right", "Collins"},
}
 
for _, user in next, Users do
    user[3] = peripheral.wrap(user[1])
end
 
local monitor = peripheral.wrap("monitor_0")
local graph = peripheral.wrap("monitor_2")
local last = 0
local timespan = 1
local timespanFactor = 60 / timespan
 
local Histories = {}
function CalculateHistory(name, new, limit)
    if not Histories[name] then Histories[name] = {} end
    local history = Histories[name]
 
    table.insert(history, new)
    while #history > limit do
        table.remove(history, 1)
    end
    local sum = 0
    for _, v in next, history do
        sum = sum + v
    end
    return sum / #history
end
 
function GraphData(monitor, data, title)
    local w, h = monitor.getSize()
    local max = -math.huge
    local min = math.huge
    for _, v in next, data do
        if v > max then max = v end
        if v < min then min = v end
    end
 
    local range = max - min
    min = min - range * 0.1
    max = max + range * 0.1
    range = max - min
 
    local scale = h / range
    if range == 0 then scale = 1 end
    
    local nData = #data
    local dataScale = nData / w
    local lastPos = 0
    for i = 1, w do
        print("monitor " .. i .. " of " .. w)
        -- get data closest to i
        local dataIndex = math.floor(i * dataScale)
        local v = data[dataIndex] or 0
        
        local bar = math.ceil((v - min) * scale)
        local vPos = math.floor(h - bar + 1)
        
        if i > 1 then
            for j = math.min(vPos, lastPos), math.max(vPos, lastPos) do
                monitor.setCursorPos(i - 1, j)
                monitor.blit(" ", "f", "0")
            end
        end
        lastPos = vPos
 
        monitor.setCursorPos(i, vPos)
        monitor.blit(" ", "f", "0")
    end
 
    -- Draw min and max values
    monitor.setCursorPos(1, 1)
    monitor.write(ReadableNumber(max, 2, false))
    monitor.setCursorPos(1, h)
    monitor.write(ReadableNumber(min, 2, false))
 
    -- Draw current value
    local current = data[#data]
    local currentV = lastPos
    local text = ReadableNumber(current, 2, false)
    local textLen = #text
    local textX = math.floor(w - textLen - 2)
    monitor.setCursorPos(textX, currentV)
    monitor.write(text)
 
    -- Draw title
    local titleLen = #title
    local titleX = math.floor(w / 2 - titleLen / 2)
    monitor.setCursorPos(titleX, 1)
    monitor.write(title)
end
 
function Graph(monitor, data, title, timeName)
    local w, h = monitor.getSize()
    local x, y = monitor.getCursorPos()
    local max = -math.huge
    local min = math.huge
    for _, v in next, data do
        if v > max then max = v end
        if v < min then min = v end
    end
 
    local range = max - min
    min = min - range * 0.1
    max = max + range * 0.1
    range = max - min
 
    local scale = h / range
    if range == 0 then scale = 1 end
    local lastPos = 0
    for i = 1, #data do
        local v = data[i]
        local bar = math.ceil((v - min) * scale)
        local vPos = math.floor(h - bar + 1)
        if i > 1 then
            for j = math.min(vPos, lastPos), math.max(vPos, lastPos) do
                monitor.setCursorPos(i - 1, j)
                monitor.blit(" ", "f", "0")
            end
        end
        lastPos = vPos
        monitor.setCursorPos(i, vPos)
        monitor.blit(" ", "f", "0")
    end
    -- Draw min and max values
    monitor.setCursorPos(1, 1)
    monitor.write(ReadableNumber(max, 2, false))
    monitor.setCursorPos(1, h)
    monitor.write(ReadableNumber(min, 2, false))
 
    -- Draw current value
    local current = data[#data]
    local currentV = lastPos
    local text = ReadableNumber(current, 2, false)
    local textLen = #text
    local textX = math.floor(w - textLen - 2)
    monitor.setCursorPos(textX, currentV)
    monitor.write(text)
 
    -- Draw title
    local titleLen = #title
    local titleX = math.floor(w / 2 - titleLen / 2)
    monitor.setCursorPos(titleX, 1)
    monitor.write(title)
 
    -- Footer with time name
    local footer = ("<- %s %s ->"):format(#data, timeName)
    local footerLen = #footer
    local footerX = math.floor(w / 2 - footerLen / 2)
    monitor.setCursorPos(footerX, h)
    monitor.write(footer)
end
 
-- load list of minutes from file
local minutes = {}
local log = fs.open("minutes.log", "r")
if log then
    Histories["sum"] = {}
    local line = log.readLine()
    while line do
        table.insert(Histories["sum"], tonumber(line))
        line = log.readLine()
    end
    log.close()
end
 
local tick = 0
while true do
    ClearScreen(monitor)
    WriteCenterAligned(monitor, "Energy Matter Covalence")
    NextLine(monitor)
    local sum = 0
    for n, user in next, Users do
        WriteLeftAligned(monitor, user[2])
        local EMC = GetEMC(user[3])
        sum = sum + EMC
        WriteRightAligned(monitor, ReadableNumber(EMC, 2, false) .. " EMC")
        NextLine(monitor)
    end
    WriteCenterAligned(monitor, ReadableNumber(sum, 2, true) .. " EMC")
 
    NextLine(monitor)
    local difference = (sum - last)
    local avgDiff = CalculateHistory("diff", difference, timespanFactor)
    local isNeg = avgDiff < 0
    if isNeg then
        monitor.setTextColour(colors.red)
    else
        monitor.setTextColour(colors.green)
    end
    last = sum
    WriteCenterAligned(monitor, (isNeg and "" or "+ ") .. ReadableNumber(avgDiff, 2, true) .. " / minute")
    monitor.setTextColour(colors.white)
 
    graph.setBackgroundColor(colors.black)
 
    if tick % timespanFactor == 0 then
        local w, h = graph.getSize()
        CalculateHistory("sum", sum, w)
        ClearScreen(graph)
        Graph(graph, Histories["sum"], "EMC HISTORY", " minutes")
 
        local log = fs.open("minutes.log", "a")
        log.writeLine(sum)
        log.close()
    end
    
    tick = tick + 1
    sleep(timespan)
end

Comments