-- 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