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

Loop without causing "Too long without yielding" error

Started by DavEdward, 16 March 2013 - 11:59 AM
DavEdward #1
Posted 16 March 2013 - 12:59 PM
I'm trying to make myself a 9x6x9 mob trap and as part of it I'd like to avoid the need to use pressure plates or trip wires to tell the turtle when to attack a mob. I'd rather it just blindly keep attacking every few seconds as long as it keeps recieving a redstone signal from my on/off lever.

However no matter how hard I try, when I try to make a loop to keep attacking I eventually get the error 'too long without yielding' is there a way to resolve this?

My code is below


local totalloot
totalloot = 0
local function updateterm()
  term.clear()
  print("----Dav's Mob Grinder Turtle----")
  write("Total Items Looted: ")
  write(totalloot)
  print("--------------------------------")
  print("")
  print("")
  print("Status:")
end
updateterm()
print("Mob grinder ready")
while true do
    while redstone.getInput("left") == false do
	 turtle.attack()
  for i=1,16,1 do
   if turtle.getItemCount(i) > 0 then
    totalloot = totalloot + turtle.getItemCount(i)
    turtle.select(i)
    turtle.dropDown()
    updateterm()
    print("Waiting for mob to spawn..")
   end
  end
sleep(2)
    end
end

*EDIT* I see where my problem is now. It's not the turtle running that's the problem, it's when it's not running. If I have a redstone signal on (which tells the turtle to do nothing at the "while redstone.getInput("left") == false do" line) the turtle cycles on the false line over and over again rapidly and that's what makes it throw that error.

I can't work out in my head how to make it wait for a os pull event for the lever to be turned off, but while it's off continue it's loop on it's marry way until the redstone signal starts again. Any suggestions?
Engineer #2
Posted 16 March 2013 - 01:40 PM
do a sleep(0) in your second while loop.
Also try something like this:

while true do
   if not redstone.getInput("left") then
	   -- Your code
   end
   sleep(0) --or longer, I suggest 0.4 if you use turtle.attack()
end

This does the same but uses you just one while loop. Now you can also detect other things, like if its true.

You do not have to do:

local totalloot
totalloot = 0

Instead you can do

local totalloot = 0
immibis #3
Posted 16 March 2013 - 02:32 PM
When you do this, or something like it:

while rs.getInput("side") == true do
  sleep(0)
end
your code is the kids in the backseat shouting "Are we there yet?" every 2 seconds, and possibly causing lag for no good reason.

This waits for a redstone signal to change:

os.pullEvent("redstone")

If you want to wait for a specific redstone state:

while rs.getInput("side") == true do
  os.pullEvent("redstone")
end
DavEdward #4
Posted 16 March 2013 - 02:36 PM
do a sleep(0) in your second while loop.
Also try something like this:

while true do
   if not redstone.getInput("left") then
	   -- Your code
   end
   sleep(0) --or longer, I suggest 0.4 if you use turtle.attack()
end

Thanks, I'll test it now. This is the code I'll try out right now:


local totalloot = 0
local function updateterm()
  term.clear()
  print("----Dav's Mob Grinder Turtle----")
  write("Total Items Looted: ")
  write(totalloot)
  print("--------------------------------")
  print("")
  print("")
  print("Status:")
end
updateterm()
print("Mob grinder ready")
while true do
    if not redstone.getInput("left") == then
	 turtle.attack()
  for i=1,16,1 do
   if turtle.getItemCount(i) > 0 then
    totalloot = totalloot + turtle.getItemCount(i)
    turtle.select(i)
    turtle.dropDown()
    updateterm()
    print("Waiting for mob to spawn..")
   end
  end
sleep(0.5)
    end
end
Engineer #5
Posted 16 March 2013 - 02:39 PM
do a sleep(0) in your second while loop.
Also try something like this:

while true do
   if not redstone.getInput("left") then
	   -- Your code
   end
   sleep(0) --or longer, I suggest 0.4 if you use turtle.attack()
end

Thanks, I'll test it now. This is the code I'll try out right now:


local totalloot = 0
local function updateterm()
  term.clear()
  print("----Dav's Mob Grinder Turtle----")
  write("Total Items Looted: ")
  write(totalloot)
  print("--------------------------------")
  print("")
  print("")
  print("Status:")
end
updateterm()
print("Mob grinder ready")
while true do
	if not redstone.getInput("left") == then
	 turtle.attack()
  for i=1,16,1 do
   if turtle.getItemCount(i) > 0 then
	totalloot = totalloot + turtle.getItemCount(i)
	turtle.select(i)
	turtle.dropDown()
	updateterm()
	print("Waiting for mob to spawn..")
   end
  end
sleep(0.5)
	end
end

you should replace this line

if not redstone.getInput("left") == then
with this:

if not redstone.getInput("left")  then

You can also do what immibis said, as it reduces lagg.
DavEdward #6
Posted 16 March 2013 - 02:39 PM
When you do this, or something like it:

while rs.getInput("side") == true do
  sleep(0)
end
your code is the kids in the backseat shouting "Are we there yet?" every 2 seconds, and possibly causing lag for no good reason.

This waits for a redstone signal to change:

os.pullEvent("redstone")

If you want to wait for a specific redstone state:

while rs.getInput("side") == true do
  os.pullEvent("redstone")
end

I understand the purpose of the OS pull event, but I can't figure out where to put it to work in the right case. The spot I kept putting it made it so that the turtle wouldn't repeatedly attack. It would wait for a redstone signal each time before attacking.
I can't figure out where I'd put that OS pull event so that it repeatedly attacks, keeping it's loop going, but once it sees a redstone signal, it then switches to an OS pull event to wait until the redstone signal is turned off. If it turns off, then it can go back to looping again until the next time it sees a redstone signal.
DavEdward #7
Posted 16 March 2013 - 02:41 PM
you should replace this line

if not redstone.getInput("left") == then
with this:

if not redstone.getInput("left")  then

You can also do what immibis said, as it reduces lagg.

Thanks Engineer. I missed leaving in that == as for the OS pull event, I can't work out where to put it. I posted about that the same time you posted.
DavEdward #8
Posted 16 March 2013 - 02:43 PM
I think I figured it out. I put the OS pull event in the else statement at the bottom.


local totalloot = 0
local function updateterm()
  term.clear()
  print("----Dav's Mob Grinder Turtle----")
  write("Total Items Looted: ")
  write(totalloot)
  print("--------------------------------")
  print("")
  print("")
  print("Status:")
end
updateterm()
print("Mob grinder ready")
while true do
	if not redstone.getInput("left") then
	 turtle.attack()
  for i=1,16,1 do
   if turtle.getItemCount(i) > 0 then
	totalloot = totalloot + turtle.getItemCount(i)
	turtle.select(i)
	turtle.dropDown()
	updateterm()
	print("Waiting for mob to spawn..")
   end
  end
sleep(0.5)
elseif redstone.getInput("left") then
  print("Grinder disabled. Waiting..")
  event = os.pullEvent("redstone")
end
end
Edited on 16 March 2013 - 01:47 PM
DavEdward #9
Posted 16 March 2013 - 03:13 PM
Success, my new code is working properly now.
Thanks immibis and Engineer for your help.

Here's the final version of my code (I hope)

http://pastebin.com/TwTkMmnz


local totalloot = 0
local function updateterm()
  term.clear()
  print("----Dav's Mob Grinder Turtle----")
  write("Total Items Looted: ")
  write(totalloot)
  print("--------------------------------")
  print("")
  print("")
  print("Status:")
end
updateterm()
print("Mob grinder ready")
while true do
    if not redstone.getInput("left") then
	 turtle.attack()
  for i=1,16,1 do
   if turtle.getItemCount(i) > 0 then
    totalloot = totalloot + turtle.getItemCount(i)
    turtle.select(i)
    turtle.dropDown()
    updateterm()
    print("Waiting for mob to spawn..")
   end
  end
sleep(0.5)
    elseif redstone.getInput("left") then
  print("Grinder disabled: Waiting..")
  event = os.pullEvent("redstone")
  print("Grinder enabled:")
  print("Waiting for mob to spawn..")
 
end
end