This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Lamdax's profile picture

[1.58] Computer crashes at certain point - no error.

Started by Lamdax, 24 October 2014 - 10:45 PM
Lamdax #1
Posted 25 October 2014 - 12:45 AM
Hi,

I have recently started writing quite a large program for my reactor (basically gets your energy cells, RF/t output, etc and places it on a monitor).

Problem is, as soon as it gets to the point where it has to write data to the monitor, it pauses for a moment and then shuts down the computer. If I restart the computer, same thing happens.
I have set up a few 'debugging' prints where major events happen, and it seems to stall at 'displayInfo()'. It doesn't run the function, as one of the first things in 'displayInfo()' is a print, and it doesn't actually print anything so the problem occurs either:

1. Before the program runs displayInfo(), but after the print saying that displayInfo() is running (unlikely),
2. After displayInfo() is called, but before the print inside displayInfo() (maybe).

I have a hunch that it is some kind of memory error (which is likely, I'm not very good with Lua and I probably have a memory leak somewhere).

Here is the code, and also my computer output so you can see where it stalls:

CODE:
Spoiler

--# Projection on Monitor and Energy Calculation

--# Initialization of variables.
local monitor = 'monitor_0'
local modem_side = 'top'
local prefix = 'cofh_thermalexpansion_energycell'
local cubeWrap = {}
local proto = 'reactor_control'

--# FUNCTIONS


--# Wrapping all energy cube peripherals (and placing them in cubeWrap).
local function wrapCubes()
for i = 0, 100 do
if peripheral.getType(prefix..'_'..i) == prefix then
print('Found one!')
table.insert(cubeWrap, peripheral.wrap(prefix..'_'..i))
end
if peripheral.getType('monitor_'..i) == 'monitor' then
print('Got a monitor!')
monitor = 'monitor_'..i
end
end
end

--# Adds current and max RF levels.
local function addLevels()
local currentLevel, maxLevel = 0, 0
for i = 1, #cubeWrap do
currentLevel = currentLevel + cubeWrap[i].getEnergyStored("unknown")
maxLevel = maxLevel + cubeWrap[i].getMaxEnergyStored("unknown")
end
return currentLevel, maxLevel
end

--# Resets the screen of monitor mon to colorB background and colorT text.
local function resetScreen(mon, colorT, colorB)
mon.setBackgroundColor(colorB or colors.black)
mon.clear()
mon.setTextColor(colorT or colors.white)
mon.setCursorPos(1,1)
return
end

--# Grabs the position needed to keep text in the center.
local function getCenter(text, mon_s)
local halfX = math.floor(mon_s.x/2)
local halfY = math.floor(mon_s.y/2)
halfX = halfX - (math.floor(#text/2))
return halfX, halfY
end

--# Displays a table of information that is input into the function, onto mon screen.
--# Table SHOULD contain 'currentEnergy, maxEnergy, amountCubes, profitEnergy'
local function displayInfo(mon, info, size, tim)
local currentE, maxE, amntC, prof = info.currentEnergy, info.maxEnergy, info.amountCubes, info.profitEnergy
local timeR = tim
print('Got vars.')
if prof > 999 or prof < -999 then
prof = (prof/1000)..'K'
end

prof = math.floor(prof+0.5)

if currentE > 999999 then
currentE = math.floor(currentE/1000000)..'M'
elseif currentE > 999 then
currentE = math.floor(currentE/1000)..'K'
end

if maxE > 999999 then
maxE = math.floor(maxE/1000000)..'M'
elseif maxE > 999 then
maxE = math.floor(maxE/1000)..'K'
end
print('Changed nums.')
local stringTab = {
'Energy: '..currentE..'/'..maxE..' RF',
'Amount of Cubes: '..amntC,
'Profit: '..prof..' RF/sec'
}
print('Made table.')
if prof > 0 then
stringTab[4] = 'Time Remaining To Fill: '..timeR.text
elseif prof <= 0 then
stringTab[4] = 'Time Remaining To Empty: '..timeR.text
end
print('Added refill times.')
term.setCursorPos(1,1)
local temp = string.rep('-', size.x-2)
local lineTopper = '|'..temp..'|'
print('Made line topper.')
mon.write(lineTopper)
print('Written line topper.')
local centerx, centery = getCenter(stringTab[1], size)
local center2x, center2y = getCenter(stringTab[2], size)
local center3x, center3y = getCenter(stringTab[3], size)
local center4x, center4y = getCenter(stringTab[4], size)
print('Got centers.')
mon.setCursorPos(centerx, centery-2)
mon.write(stringTab[1])
mon.setCursorPos(center2x, center2y-1)
mon.write(stringTab[2])
mon.setCursorPos(center3x, center3y+1)
mon.setTextColor(timeR.color)
mon.write(stringTab[3])
mon.setCursorPos(center4x, center4y+2)
mon.write(stringTab[4])
mon.setTextColor(colors.black)
print('WRITTEN DATA')
mon.setCursorPos(1, size.y)
mon.write(lineTopper)
print('Done.')
end

--# This function inputs the current energy, max energy, and RF/t and outputs the time to refill. -----
local function getTimeToRefill(rft, cEnergy, mEnergy)
local rfPerSecond = rft * 10
local remainEnergy = mEnergy - cEnergy

local remainTimeSeconds, remainTimeMinutes, remainTimeHours = 0, 0, 0

remainTimeSeconds = remainEnergy/rfPerSecond
while remainTimeSeconds >= 60 do
if remainTimeMinutes >= 59 then
remainTimeMinutes = 0
remainTimeHours = remainTimeHours + 1
else
remainTimeMinutes = remainTimeMinutes + 1
end
remainTimeSeconds = math.floor(remainTimeSeconds - 60)
end

if rfPerSecond > 0 then
if remainTimeHours > 0 then
return {color=colors.lime, text=remainTimeHours..':'..remainTimeMinutes..':'..remainTimeSeconds}
else
return {color=colors.lime, text=remainTimeMinutes..':'..remainTimeSeconds}
end
else
if remainTimeHours > 0 then
return {color=colors.red, text='-'..remainTimeHours..':'..remainTimeMinutes..':'..remainTimeSeconds}
else
return {color=colors.red, text='-'..remainTimeMinutes..':'..remainTimeSeconds}
end
end

return 'ERROR'
end

--# Get information from a rednet sender.
local function receiveInfo()
repeat
sender, message, dist = rednet.receive()
until message.protocol == proto

return message
end

--# END FUNCTIONS

--# Main workflow.
local function main()
rednet.open(modem_side)
wrapCubes()
local m = peripheral.wrap(monitor)
local mon_size = {}
mon_size.x, mon_size.y = m.getSize()
local currentL, maxL, profi = 0, 0, 0
while rs.getInput('bottom') == false do
currentL, maxL = addLevels()
print('Receiving info...')
local data = receiveInfo()
print('Info received.')
profi = data.energyOut
print('Resetting screen...')
resetScreen(m, colors.black, colors.white)
print('Reset screen.')
print('Displaying info...')
local infoTable = {
currentEnergy = currentL,
maxEnergy = maxL,
amountCubes = #cubeWrap,
profitEnergy = profi
}
local refill = getTimeToRefill(profi, currentL, maxL)
displayInfo(m, infoTable, mon_size, refill)
print('Displayed info. Rounds done.')
sleep(1)
end
end

--# Calling main workflow.
main()

OUTPUT:
Spoiler

--# Random jargon about finding peripherals. #--

Receiving info...
Info received.
Resetting screen...
Reset screen.
Displaying info...
And there is where it pauses for about a second, before shutting down without an error.

I hope I can get an answer soon (I'm guessing it will be about shortening my code).

Thank you in advance for your help, CC community!
Dragon53535 #2
Posted 25 October 2014 - 01:35 AM
While looking through your code (haven't found your error just yet)

while remainTimeSeconds >= 60 do
if remainTimeMinutes >= 59 then
remainTimeMinutes = 0
remainTimeHours = remainTimeHours + 1
else
remainTimeMinutes = remainTimeMinutes + 1
end
remainTimeSeconds = math.floor(remainTimeSeconds - 60)
end
You can easily use the modulus operator.

local sec = 122 --#Just to show

local min = math.floor(sec/60) --#This will be 2.

sec = sec % 60 --# This divides by 60, however the remainder is set as sec, not the actual quotient. So sec is now 2 since 122 / 60 has a 2 remainder.

Will edit post when i do find answer though :D/>

EDIT: Your getTimeToRefill function, add a print to see if that finishes, as i suspect the error may be in there.
Edited on 24 October 2014 - 11:41 PM
Bomb Bloke #3
Posted 25 October 2014 - 03:13 AM
I agree with Dragon; my best guess is that getTimeToRefill function. That loop he pointed out, specifically.

If a system fails to yield for an extended period (typically about ten seconds), ComputerCraft will attempt to crash the script. Sometimes it's unable to make it "error out", and so it instead crashes the whole computer.

So my assumption is that it's taking too long to get through that rather inefficient loop (after doing everything else leading up to it since whenever the last yield was). It wouldn't surprise me if implementing a couple of modulus operations in its place fixes the issue.

By the way, you seem to be using math.floor() an awful lot more often than you need to. For example, in the aforementioned loop, better to make sure remainTimeSeconds is an integral number before it even starts instead of repeating redundant math.floor() calls inside it.