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

[Lua] Nested if Interrupting while true do Loop

Started by Rotaretilbo, 21 July 2012 - 11:16 PM
Rotaretilbo #1
Posted 22 July 2012 - 01:16 AM
Me again. Now that I've got the refreshing clock working (thanks to input from Grim Reaper in my previous thread), I've set about creating a news system, by which a player can send news updates to a computer, which are stored on a floppy disk in an adjacent disk drive, and then grabbed by the clock program. I've almost finished the second bit of code (the news program that grabs the data), but I ran into a slight problem towards the end, which confused me. Towards the end, I use a nested for loop with an if statement to print out the actual news. While the program works, for whatever reason, the program itself does not loop. Here is the file being accessed and code:

Test File
Recent News:
Test News 1
Test News 2
Test News 3

Clock/News Code
mon = peripheral.wrap("top")
while true do
mon.clear()
News = {}
file = io.open("/disk/news", "r")
count = 0
for line in file:lines() do
  table.insert(News, line)
  count = count+1
end
file:close()
mon.setTextScale(1)
mon.setCursorPos(21,1)
mon.write("Current time is:")
mon.setCursorPos(26,3)
mon.write(textutils.formatTime(os.time(), false))
mon.setCursorPos(2,5)
mon.write(News[1])
for x=1,21 do
  mon.setCursorPos(2,x+5)
  if count < 22 then --Another aside; 20 lines of actual news is the max amount that will fit on the screen we built; thus, count being greater than 21 means that older news needs to be skipped
   mon.write(News[x+1])
  else
   mon.write(News[count-(20-x)])
  end
end
os.sleep(0.1)
end

When I run this program, everything displays correctly as intended, but the program does not loop, so the screen does not refresh. Now, I've been testing it bit by bit, so I knew that this problem was introduced when I added the for loop with the nested if. Thus, I ran some tests.

Trial and Error Test 1
mon = peripheral.wrap("top")
while true do
mon.clear()
News = {}
file = io.open("/disk/news", "r")
count = 0
for line in file:lines() do
  table.insert(News, line)
  count = count+1
end
file:close()
mon.setTextScale(1)
mon.setCursorPos(21,1)
mon.write("Current time is:")
mon.setCursorPos(26,3)
mon.write(textutils.formatTime(os.time(), false))
mon.setCursorPos(2,5)
mon.write(News[1]) --An aside; the first line in /disk/logs is predetermined to be "Recent News:"
-- for x=1,21 do
--  mon.setCursorPos(2,x+5)
--  if count < 22 then --Another aside; 20 lines of actual news is the max amount that will fit on the screen we built; thus, count being greater than 21 means that older news needs to be skipped
--   mon.write(News[x+1])
--  else
--   mon.write(News[count-(20-x)])
--  end
-- end
os.sleep(0.1)
end

Just to confirm what I already knew, that the problem was introduced by the for loop. As expected, the program loops as expected. So I ran another test.


Trial and Error Test 2
mon = peripheral.wrap("top")
while true do
mon.clear()
News = {}
file = io.open("/disk/news", "r")
count = 0
for line in file:lines() do
  table.insert(News, line)
  count = count+1
end
file:close()
mon.setTextScale(1)
mon.setCursorPos(21,1)
mon.write("Current time is:")
mon.setCursorPos(26,3)
mon.write(textutils.formatTime(os.time(), false))
mon.setCursorPos(2,5)
mon.write(News[1]) --An aside; the first line in /disk/logs is predetermined to be "Recent News:"
for x=1,21 do
  mon.setCursorPos(2,x+5)
--  if count < 22 then --Another aside; 20 lines of actual news is the max amount that will fit on the screen we built; thus, count being greater than 21 means that older news needs to be skipped
--   mon.write(News[x+1])
--  else
--   mon.write(News[count-(20-x)])
--  end
end
os.sleep(0.1)
end

Again, this program loops as expected. So, I ran another test.


Trial and Error Test 3
mon = peripheral.wrap("top")
while true do
mon.clear()
News = {}
file = io.open("/disk/news", "r")
count = 0
for line in file:lines() do
  table.insert(News, line)
  count = count+1
end
file:close()
mon.setTextScale(1)
mon.setCursorPos(21,1)
mon.write("Current time is:")
mon.setCursorPos(26,3)
mon.write(textutils.formatTime(os.time(), false))
mon.setCursorPos(2,5)
mon.write(News[1]) --An aside; the first line in /disk/logs is predetermined to be "Recent News:"
for x=1,21 do
  mon.setCursorPos(2,x+5)
  if count < 22 then --Another aside; 20 lines of actual news is the max amount that will fit on the screen we built; thus, count being greater than 21 means that older news needs to be skipped
   mon.write(News[x+1])
--  else
--   mon.write(News[count-(20-x)])
  end
end
os.sleep(0.1)
end

In this case, the program does not loop as expected. Thus, I determined that the nested if was what was interrupting my while true do loop. However, what I don't understand is why. Curious, I ran another test.


Trial and Error Test 4
mon = peripheral.wrap("top")
while true do
mon.clear()
News = {}
file = io.open("/disk/news", "r")
count = 0
for line in file:lines() do
  table.insert(News, line)
  count = count+1
end
file:close()
mon.setTextScale(1)
mon.setCursorPos(21,1)
mon.write("Current time is:")
mon.setCursorPos(26,3)
mon.write(textutils.formatTime(os.time(), false))
mon.setCursorPos(2,5)
mon.write(News[1]) --An aside; the first line in /disk/logs is predetermined to be "Recent News:"
for x=1,21 do
  mon.setCursorPos(2,x+5)
  if count < 22 then --Another aside; 20 lines of actual news is the max amount that will fit on the screen we built; thus, count being greater than 21 means that older news needs to be skipped
   mon.write(News[x+1])
--  else
--   mon.write(News[count-(20-x)])
  end
end
mon.setCursorPos(1,1)
mon.write("TEST")
os.sleep(0.1)
end

As expected, the program does not display TEST in the top left corner. The program is not executing everything after the if statement. Confused, I ran another test.


Trial and Error Test 5
mon = peripheral.wrap("top")
while true do
mon.clear()
News = {}
file = io.open("/disk/news", "r")
count = 0
for line in file:lines() do
  table.insert(News, line)
  count = count+1
end
file:close()
mon.setTextScale(1)
mon.setCursorPos(21,1)
mon.write("Current time is:")
mon.setCursorPos(26,3)
mon.write(textutils.formatTime(os.time(), false))
mon.setCursorPos(2,5)
mon.write(News[1]) --An aside; the first line in /disk/logs is predetermined to be "Recent News:"
for x=1,21 do
  mon.setCursorPos(2,x+5)
  if count < 22 then --Another aside; 20 lines of actual news is the max amount that will fit on the screen we built; thus, count being greater than 21 means that older news needs to be skipped
   mon.write(News[x+1])
--  else
--   mon.write(News[count-(20-x)])
  end
end
mon.setCursorPos(1,1)
mon.write("TEST")
os.sleep(0.1)
--end

Error Code for Test 5
> /disk/news
bios:206: [string "news"]:30: 'end' expected (to
close 'while' at line 2)
>

So, clearly, the program recognizes that there's code down there, but it's not executing it. Now, unlike before, I can probably work around this quirk, because once /disk/logs has more than 20 legit news entries, I no longer need the if statement at all. However, I thought it was quite curious, so I figured I'd pose the question here.
Lyqyd #2
Posted 22 July 2012 - 01:52 AM
You know, when it tells you "']' expected", you should probably listen. ;-)


mon = peripheral.wrap("top")
while true do
mon.clear()
News = {}
file = io.open("/disk/news", "r")
count = 0
for line in file:lines() do
  table.insert(News, line)
  count = count+1
end
file:close()
mon.setTextScale(1)
mon.setCursorPos(21,1)
mon.write("Current time is:")
mon.setCursorPos(26,3)
mon.write(textutils.formatTime(os.time(), false))
mon.setCursorPos(2,5)
mon.write(News[1])
for x=1,21 do
  mon.setCursorPos(2,x+5)
  if count < 22 then --Another aside; 20 lines of actual news is the max amount that will fit on the screen we built; thus, count being greater than 21 means that older news needs to be skipped
   mon.write(News[x+1])
  else
   --added two characters; runs fine on my machine now.
   mon.write(News[count-(20-x)])
  end
end
os.sleep(0.1)
end
Rotaretilbo #3
Posted 22 July 2012 - 01:57 AM
Sorry, that was a typo and copy pasta error on my part. Updated OP to represent actual code. Sorry about that.
Lyqyd #4
Posted 22 July 2012 - 02:35 AM
Found the issue.


mon = peripheral.wrap("top")
while true do
    mon.clear()
    local News = {}
    file = io.open("/disk/news", "r")
    local line = file:read()
    while line do
        table.insert( News, line )
        line = file:read()
    end
    file:close()
    mon.setTextScale(1)
    mon.setCursorPos(21,1)
    mon.write("Current time is:")
    mon.setCursorPos(26,3)
    mon.write(textutils.formatTime(os.time(), false))
    mon.setCursorPos(2,5)
    mon.write(News[1])
    for x=1,21 do
        mon.setCursorPos(2,x+5)
        if #News < 22 then --Another aside; 20 lines of actual news is the max amount that will fit on the screen we built; thus, count being greater than 21 means that older news needs to be skipped
            if x + 1 > #News then break end
            --If you let it index things beyond the scope of the News table, it silently fails.
            mon.write(News[x+1])
        else
            mon.write(News[#News-(20-x)])
        end
    end
    sleep(0.1)
end

Got rid of an unnecessary variable, but the fix is just the one line that checks whether or not we'll be attempting to write an entry that actually exists or not.
Rotaretilbo #5
Posted 22 July 2012 - 08:35 AM
Ah, that makes sense. I thought I'd tested it before, but I must have done it a different way before. Thank you.