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

Can someone help fixing this error for me.

Started by johnneijzen, 05 April 2014 - 07:07 AM
johnneijzen #1
Posted 05 April 2014 - 09:07 AM
every 30 to 50 min it crash with java.lang.ArrayIndexOutOfBoundsException. i know that it is function after 255 times it cant be called but i cant way to fix this probleem i have try other stuff but still it crashed.

this is code
http://pastebin.com/rR9JXSvy (This Is One i want to fix)

Github if you how to pull request.
Here
Edited on 05 April 2014 - 07:11 AM
theoriginalbit #2
Posted 05 April 2014 - 09:54 AM
Your problem is due to the fact that Lenght (typo btw, you spelt it wrong) invokes wide which then invokes Lenght again, etc. This is called cyclic recursion. It would require a bit of a rewrite but you can fix this with loops. However if you want the 'quick-and-dirty' method you can use tail calls to fix this. Basically add a 'return' before each of the calls and it'll fix your problem. I do suggest attempting to fix your code and use loops however, it promotes a better program design.

Some suggestions unrelated to the bug

I see you understand local variables, as you've used them in your program, I also suggest you make use of local functions. It will require a change of order so they work, and it will also require you to change your program to the suggestion of loops to fix your cyclic recursion problem.

Another suggestion I can make is to make use of the turtle_inventory event when waiting for more items from the user, instead of refreshing after 15 seconds.
johnneijzen #3
Posted 05 April 2014 - 10:09 AM
okey now understand my problem. thanks for tip about turtle_inventory event. :)/> i`m go start working on change code in 3 days because still staff to do.
Bomb Bloke #4
Posted 05 April 2014 - 10:15 AM
I've been ninja'd while typing, and BIT's covered all this already, but I've started so I'll finish.

Let's chop out most of the script to make it easier to read the flow:

Spoiler
-- Checking
function check()
  ..
  if Error == 1 then
    ..
    recheck()
  else
    ..
    Lenght()
  end
end

-- Recheck  if user forget something turtle will check after 15 sec
function recheck()
  ..
  check()
end

-- Run Command aka start up command
function run()
  ..
  if High == Hc then
    print("done")
  else
    Lenght()
  end
end

-- Mining for length
function Lenght()
  ..
  if Wide == Wc then
    ..
    run()
  else
    wide()
  end
end

-- Mining Wide
function wide()
  ..
  if Wide == WC then
    ..
    run()
  else
    Lenght()
  end
end

..
check()

As you've realised, the problem is that your script calls function after function after function… without ever allowing any of the previous functions to end. Eventually the built-up trail of calls crashes down.

You should be able to get around this easily by using tail calls - have each function attempt to return a theoretical result from the next. Doing this means that each new call replaces the previous one in the stack, saving it from filling up and overflowing.

The process basically involves determining where the last function call in each function is, and turning that into a return. Eg:

-- Mining Wide
function wide()
  ..
  if Wide == WC then
    ..
    return run()
  else
    return Lenght()
  end
end

It doesn't really matter whether the last function at the end of the trail returns anything. The point is that Lua now knows that since this function instance is only going to return whatever the next function does, it doesn't need to remember this function anymore.

However: Ideally you'd ditch the need for recursion, which again is made easy by having functions return data and by implementing a few while loops. Compare this to the paraphrased outline of your code I quoted above, and feel free to ask questions about whatever bits don't make sense to you:

Spoiler
-- Checking
function check()
  while Error == 1
    ..

    if Error == 1 then recheck() end
  end

  ..
  while true do
    while true do
      if Lenght() then break end
      if wide() then break end
    end

    if run() then break end
  end

  print("done")
end

-- Recheck  if user forget something turtle will check after 15 sec
function recheck()
  ..
end

-- Run Command aka start up command
function run()
  ..
  return High == Hc
end

-- Mining for length
function Lenght()
  ..
  return Wide == Wc
end

-- Mining Wide
function wide()
  ..
  return Wide == WC
end

..
check()
theoriginalbit #5
Posted 05 April 2014 - 10:28 AM

if Lenght() then break end
if wide() then break end
taking a look i think the logic that better matches OP code would be

if Lenght() and wide() then break end
Bomb Bloke #6
Posted 05 April 2014 - 10:33 AM
Nah. "or" might work, though.
johnneijzen #7
Posted 05 April 2014 - 10:51 AM
i have one question still what with 2 while true? can some one explain
Code:
while true do
while true do
if Lenght() then break end
if wide() then break end
end

if run() then break end
end
Bomb Bloke #8
Posted 05 April 2014 - 11:39 AM
  while true do                   -- Start a loop that repeats indefinitely.
    while true do                 -- Start another loop that repeats indefinitely.
      if Lenght() then break end  -- If the value returned by Lenght() is true, then jump out of the second loop.
      if wide() then break end    -- If the value returned by wide() is true, then jump out of the second loop.
    end                           -- This marks the end of the second loop.

    if run() then break end       -- If the value returned by run() is true, then jump out of the first loop.
  end                             -- This marks the end of the first loop.

So say we call the Lenght() function, and it finishes up by performing "return Wide == Wc". It checks to see if Wide is the same as Wc, and if so, the value it passes back is true; if not, the value will be false. We can hence use the called function as a value.

For example, this allows us to perform a true/false test by performing "if Lenght() then …".

For more on loops, have a read through this.
Edited on 05 April 2014 - 09:51 AM
johnneijzen #9
Posted 05 April 2014 - 11:46 AM
okey.
Bomb Bloke #10
Posted 05 April 2014 - 11:51 AM
I kinda used some verbose coding to try to make the logic of the loops a little simpler for you, but that may've had the opposite effect. If it helps, this should do the same thing:

  repeat
    repeat until Lenght() or wide()
  until run()
johnneijzen #11
Posted 06 April 2014 - 06:27 PM
i spent about 2 day rewritten the program i think i`m almost done with programs
http://pastebin.com/rR9JXSvy
Edited on 06 April 2014 - 06:40 PM
theoriginalbit #12
Posted 07 April 2014 - 02:08 AM
i spent about 2 day rewritten the program i think i`m almost done with programs
http://pastebin.com/rR9JXSvy
is there currently a problem, or are you just giving an update on progress?

so I got a little bored and wrote an example of using the turtle_inventory event, but also at the same time making the checking process easier for you, especially since I noticed on your GitHub that you use it in different programs. You can add more checks with one line of code (just add a new table entry), no need to go and write more if statements, no need for your recheck function, and other little things that you can read in the commented version
Code

local requirements = {
  {func = turtle.getItemCount, args = {1}, compare = 0, success = false, trueMessage = "Turtle has fuel", failMessage = "Turtle has no fuel\nPut fuel in slot 1 and 2"};
  {func = turtle.getItemCount, args = {2}, compare = 0, success = false, trueMessage = "", failMessage = "Turtle has no extra fuel\nBut if it is a short job it's okay"};
  {func = turtle.getItemCount, args = {3}, compare = 0, success = false, trueMessage = "Turtle has chest", failMessage = "No chest in Turtle\nPut chest in slot 3"};
}

local function check()
  local success = true
  repeat
	term.clear()
	term.setCursorPos(1,1)
	for _,condition in ipairs(requirements) do
	  local pass = condition.func(unpack(args)) == condition.comp
	  if condition.success ~= pass then
		condition.success = pass
	  end
	  if condition.success and condition.trueMessage ~= "" then
		print(condition.trueMessage)
	  elseif condition.failMessage ~= "" then
		print(condition.failMessage)
		success = false
	  end
	end
	if not success then
	  print("Missing items. Waiting...")
	  os.pullEventRaw("turtle_inventory")
	end
  until success
  print("All items are present. Starting...")
end

--# other program code

check()
run()
Commented Code

--[[
# define a table of all the conditions to check
#
# the first key 'func' is a function to call, this can be any function you wish, even one of your own
# the second key 'args' is the arguments to give to the function when calling it, you can have any amount you wish as long as it exists
#	 e.g. args = {1,5,'foo'} will give 1, 5, and 'foo' to the function
# the third key 'compare' is what value should be to the right of the if statement conditional
#	 e.g. compare = 'foo' will check that the result returned from the function was a string 'foo' (func() == 'foo')
# the fourth key 'success' is used internally to see if it has previously passed
# the fifth key 'trueMessage' is the message if the conditional passed
# the sixth key 'failMessage' is the message if the conditional fails
#
# basic example (no args):
# {func = turtle.getFuelLevel, args = {}, compare = 0, success = false, trueMessage = "Turtle does not have fuel", failMessage = "Turtle has fuel"};
#
# example (with args):
# {func = turtle.getItemCount, args = {2}, compare = 0, success = false, trueMessage = "", failMessage = "Turtle has no extra fuel\nBut if it is a short job it's okay"};
--]]
local requirements = {
  {func = turtle.getItemCount, args = {1}, compare = 0, success = false, trueMessage = "Turtle has fuel", failMessage = "Turtle has no fuel\nPut fuel in slot 1 and 2"};
  {func = turtle.getItemCount, args = {2}, compare = 0, success = false, trueMessage = "", failMessage = "Turtle has no extra fuel\nBut if it is a short job it's okay"};
  {func = turtle.getItemCount, args = {3}, compare = 0, success = false, trueMessage = "Turtle has chest", failMessage = "No chest in Turtle\nPut chest in slot 3"};
}

--# we define the function as local, anywhere it is called must be below this function!
local function check()

  --# we use this to know when to stop checking
  local success = true
  repeat
	--# clear the screen ready to output the latest information
	term.clear()
	term.setCursorPos(1,1)

	--# go through the requirements
	for _,condition in ipairs(requirements) do

	  --# run the check, call the function with all the args and make sure it returns what we're expecting
	  local pass = condition.func(unpack(args)) == condition.comp

	  --# if it has a different result to last time then update the result
	  if condition.success ~= pass then
		condition.success = pass
	  end

	  --# output messages
	  --# if it has passed tests and there is a message
	  if condition.success and condition.trueMessage ~= "" then
		--# output the message
		print(condition.trueMessage)
	  --# it has clearly failed, if there is a failure message then
	  elseif condition.failMessage ~= "" then
		--# output the message
		print(condition.failMessage)
		--# make sure the loop runs again, this test failed
		success = false
	  end
	end

	--# did we get through all the checking successfully?
	if not success then
	  print("Missing items. Waiting...")
	  --# wait until the user changes something in the inventory
	  os.pullEventRaw("turtle_inventory")
	end

  --# loop again if we didn't have everything we're waiting for
  until success
  print("All items are present. Starting...")
end

--# other program code

check()
--# start the program running here, for example like below
run()
Edited on 07 April 2014 - 12:10 AM
johnneijzen #13
Posted 07 April 2014 - 05:51 PM
it was just giving an update on progress. it work like Charm after fixing some minor bug it mine fast as hell.

Edited on 07 April 2014 - 05:13 PM