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

Stackoverflow/IndexOutOfBoundsException

Started by BrunoZockt, 19 August 2016 - 04:42 PM
BrunoZockt #1
Posted 19 August 2016 - 06:42 PM
Hey guys!

As you can see in the title I need help with the Stackoverflow.
The first short question is, if there is a way of getting the actual stack?

And now to my real problem: I am writing a program for mining turtles to automatically dig all the ores. If you are interested you can look at it on pastebin: http://pastebin/gkz5sgZ8 but it doesn't really matter for my problem.
The problem is that I changed my CompareAll function from this:


function CompareAll()
  local boolean, data = turtle.inspect()
  turtle.select(1)
  if data.name == "minecraft:stone" or turtle.detect() == false then
	return CompareLeft
  elseif turtle.compare() == true then
	return CompareLeft
  else
	turtle.select(2)
	if turtle.compare() == true then
	  return CompareLeft
	else
	  turtle.select(3)
	  if turtle.compare() == true then
		return CompareLeft
	  else
		turtle.select(4)
		dig()
		Freeway()
		table.insert(Cache, #Cache+1, direction)
		return CompareAll()
	  end
	end
  end
end

to this:


function CompareAll()
  Compare()
  CompareUp()
  CompareDown()
  CompareLeft()
  CompareRight()
  Zurueck()
end

As you can see, at first I didn't really have a Compare function, it was the CompareForward function which returned to the CompareLeft function if nothing was found. Same with the CompareLeft function: It returned to the CompareRight function and so on…
My new function simply calls them one by one, what has the big advantage that I can use the Compare functions individually.
But it also has a bad thing: It now costs a stack everytime an ore is found. Because if the turtle finds an ore, it digs it, and moves into the new hole comparing all sides again. So the veins are limited at ca. 150 blocks, what obviously is a case that happens never, but I want the program to handle every situation. You know what I mean :P/>/>

So I had the idea of a "double return" , because I don't need the program where in the function CompareAll it was, it can simply start from top again, on the way back.


function Compare()
  local boolean, data = turtle.inspect()
  turtle.select(1)
  if data.name == "minecraft:stone" or turtle.detect() == false then
	return
  elseif turtle.compare() == true then
	return
  else
	turtle.select(2)
	if turtle.compare() == true then
	  return
	else
	  turtle.select(3)
	  if turtle.compare() == true then
		return
	  else
		turtle.select(4)
		dig()
		Freeway()
		table.insert(Cache, #Cache+1, direction)
		return CompareAll()            <-----------it should forget about the old CompareAll function right here
	  end
	end
  end
end

Is there a way of doing something like this?
And if not, has someone a creative idea how to solve this another way?

If there is anything not clear feel free to ask me, if I made misleading spelling or grammar mistakes comment them aswell, I am german and don't speak the best english :D/>/>

Thanks in advance!

Bruno
Edited on 19 August 2016 - 08:38 PM
Bomb Bloke #2
Posted 20 August 2016 - 09:07 AM
The first short question is, if there is a way of getting the actual stack?

No. The best you can do is count up the number of calls your particular script has made / returned.

It's worth noting that if you do:

return someFunction()

… then the current function is bumped out of the stack before the new one is called, meaning the depth doesn't increase. This technique is called a "tail call".

Personally, I prefer to avoid recursive function calls, instead using a table to track my progress within a "while" loop. For example, you could create a loop that goes to the first location specified in a table, searches around it, then removes it - whenever it finds new locations it can dig out (ore), add them to the end of the table. The loop would repeat until the whole ore cluster was removed, and there'd be no need for recursion.

The functions you've posted here could be simplified a little. One way is via a lookup table - say there are a few types of block you want to ignore, you might do this:

local ignore = {"minecraft:stone" = true, "minecraft:dirt" = true, "minecraft:sand" = true, "minecraft:gravel" = true}

.
.
.

local found, data = turtle.inspect()

if not found or ignore[data.name] then
	return
else
	...

If you really want to compare blocks to the one's in the turtle's inventory, a separate function for that could help simplify the code:

local function compareSlot(slotNum)
	turtle.select(slotNum)
	return turtle.compare()
end

.
.
.

if compareSlot(1) or compareSlot(2) or compareSlot(3) then
	...
BrunoZockt #3
Posted 20 August 2016 - 02:46 PM
The first short question is, if there is a way of getting the actual stack?

No. The best you can do is count up the number of calls your particular script has made / returned.

It's worth noting that if you do:

return someFunction()

… then the current function is bumped out of the stack before the new one is called, meaning the depth doesn't increase. This technique is called a "tail call".

Personally, I prefer to avoid recursive function calls, instead using a table to track my progress within a "while" loop. For example, you could create a loop that goes to the first location specified in a table, searches around it, then removes it - whenever it finds new locations it can dig out (ore), add them to the end of the table. The loop would repeat until the whole ore cluster was removed, and there'd be no need for recursion.

The functions you've posted here could be simplified a little. One way is via a lookup table - say there are a few types of block you want to ignore, you might do this:

local ignore = {"minecraft:stone" = true, "minecraft:dirt" = true, "minecraft:sand" = true, "minecraft:gravel" = true}

.
.
.

local found, data = turtle.inspect()

if not found or ignore[data.name] then
	return
else
	...

If you really want to compare blocks to the one's in the turtle's inventory, a separate function for that could help simplify the code:

local function compareSlot(slotNum)
	turtle.select(slotNum)
	return turtle.compare()
end

.
.
.

if compareSlot(1) or compareSlot(2) or compareSlot(3) then
	...
Thanks for your Help!
I already thought about simplifying the code, but was too lazy …
About your suggestion with building a table. I don't really understand how the while loop should look like and what you mean by saving locations in it. Could you give me a short example?

Bruno
Edited on 20 August 2016 - 12:47 PM