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

[Request] Counter that keeps its state on world reload?

Started by AEtherchild, 09 February 2013 - 02:54 PM
AEtherchild #1
Posted 09 February 2013 - 03:54 PM
Howdy.

So I've recently set up a Wither farming Mystcraft world. Wither Skeleton Soul Shard spawner that provides me with Skulls, to assemble and fight Withers in a blastproof room.

I've been trying to get a computer "counter" that, upon hearing a Redstone Signal to its left, increases a variable by 1 and overwrites the count line on a 3x2 monitor on its front to display the total number of Wither kills. I'm also hoping to have this somehow keep the variable's value upon world reload, as I play LAN as opposed to servers.

For the counter to keep its number, I'm not too sure how to accomplish this. One method could be to have a WR-CBE transmitter next to the computer, and treat the Transmitter's frequency as the solid-state "kill" variable. Not sure if there's an inherent CC way of keeping values over world reload, but this would work for me.

Question is. How best would I construct a program that runs indefinitely and listens for Redstone signals?

EDIT: Okay, I figured out <something>. This, however, will return a "Too long without yielding" error after around 10 seconds of non-use. Here's my startup program:


monitor = peripheral.wrap("front")
trans = peripheral.wrap("back")
kill = trans.getFreq()
monitor.clear()
monitor.setCursorPos(1,1)
monitor.write("Wither Kill Count: "..tostring(kill))
while true do
 if redstone.getInput("right") == true then do
   trans.setFreq(kill + 1)
   kill = trans.getFreq()
   monitor.clear()
   monitor.setCursorPos(1,1)
   monitor.write("Wither Kill Count: "..tostring(kill))
   os.sleep(1)
  end
end
end

The error suggests that "while true do" is inappropriate for what I am hoping to do here. Nobody likes infinite loops that do basically nothing for ages.
Kingdaro #2
Posted 09 February 2013 - 04:01 PM
Could just save it to a file every time the count increases.


local function saveCount(num)
  local file = fs.open('rs-count','w')
  file.write(tostring(num))
  file.close()
end

local function loadCount()
  local file = fs.open('rs-count','r')
  if file then
    return tonumber(file.readAll()), file.close()
  else
    return 0
  end
end

Example use in your main code:


local count = loadCount()

while true do
  os.pullEvent 'redstone'
  if rs.getInput 'left' then
    count = count + 1
    saveCount(count)
  end
end

Though this could be taxing on the hard drive.
AEtherchild #3
Posted 09 February 2013 - 04:21 PM
Okay, got it sorted now. Using a WR-CBE Transmitter as a solid-state variable definitely seems to be the easiest and most pleasant way. It's awkward that I had to use a recursive loop to avoid the "Too long without yielding" error, but it works. Here's startup now:


monitor = peripheral.wrap("front")
trans = peripheral.wrap("back")
kill = trans.getFreq()

function increment()
trans.setFreq(kill + 1)
kill = kill + 1
monitor.clear()
monitor.setCursorPos(1,1)
monitor.write("Wither Kill Count: "..tostring(kill))
os.sleep(1)
check()
end

function check()
if redstone.getInput("right") == true then do
   increment()
  end else do
   os.sleep(1)
   check()
  end
end
end

monitor.clear()
monitor.setCursorPos(1,1)
monitor.write("Wither Kill Count: "..tostring(kill))
check()

Ah. After 256 iterations of check() returning false, the Computer returns java.lang.ArrayOutOfBoundsException:256 and stops. Is there even a way around this?
Kingdaro #4
Posted 09 February 2013 - 04:40 PM
It's probably because you're using a recursive loop. Try using a while loop instead. Those extra "do"s and "end"s aren't necessary either. Should also probably pause the program and wait for a redstone event to prevent that "too long without yielding" error as well.


function check()
  while true do
    os.pullEvent('redstone')
    if redstone.getInput("right") == true then
      increment()
    end
  end
end
AEtherchild #5
Posted 09 February 2013 - 05:13 PM
Ahh, okay. I've not used os.pullEvent() before so I wasn't too sure on the usage, thanks for letting me know such a useful thing existed :)/> So the tidied up code should resemble this? Also, moved the monitor to the left so I could actually access the computer ^^


function check()
 while true do
  os.pullEvent('redstone')
  if redstone.getInput("right") == true then
   increment()
  end
 end
end

function increment()
 trans.setFreq(trans.getFreq() + 1)
 kill = kill + 1
 refresh()
 os.sleep(1)
end

function refresh()
 monitor.clear()
 monitor.setCursorPos(1,1)
 monitor.write("Wither Kill Count: "..tostring(kill))
end

monitor = peripheral.wrap("left")
trans = peripheral.wrap("back")
kill = trans.getFreq()
refresh()
check()

EDIT: Minor change to increment() so that I can manually change the kill variable by changing the Receiver's frequency if needed.