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

Stack overflow

Started by Vattic, 17 May 2013 - 09:04 PM
Vattic #1
Posted 17 May 2013 - 11:04 PM
The acctual error message:
main2:254: vm error: java.lang.ArrayIndexOutOfBoundsException: 256

I've not had much experience with CC before now and I'm a hobbiest programmer at best. I can't figure out what I'm doing wrong. Would anyone mind having a look for me? I know it's a bit messy in places and that there is a fair bit of it, but I'd really appreciate some help.

Lines 254 - 256 are in the checkIfFull() function which is supposed to loop through all the inventory slots that aren't being used for identifying unwanted blocks (dirt, stone, sand, gravel) and tell if they contain items. If they all do it'll place an ender chest and deposit them.

The Code:
Spoiler

-- quarry
local centerX = 0
local centerY = 0
local size = 20

-- turtle
local status = 0
local curDir = "x"
local moveDir = 1
local justTurned = 0
local travelHeight = 0
local ignoreList = 0
local surfaceZ = 249
local startup = false

  --[[-------
  Param.txt
  -----------
  status
  moveDir
  justTurned
  ignoreList
  surfaceZ
  ]]---------

patMap = {
{0, 0, 0, 1, 0},
{1, 0, 0, 0, 0},
{0, 0, 2, 0, 0},
{0, 0, 0, 0, 1},
{0, 1, 0, 0, 0}};

-- #######################################################################
-- Basic movement and navigation
-- #######################################################################
function refuelTurtle()
  if turtle.getFuelLevel() < 10 then
	-- keeps digging up until it can place the ender chest
	while turtle.detectUp() do turtle.digUp() os.sleep(1) end
	turtle.select(13)
	turtle.placeUp()
	-- keeps trying to get and use fuel until it manages
	while true do
	  turtle.select(12)
	  turtle.suckUp()
	  if turtle.getItemCount(12) > 0 then break end
	  os.sleep(5)
	end
	-- uses some of the fuel and keeps trying to return the rest
	turtle.refuel(1)
	while true do
	  turtle.dropUp()
	  if turtle.getItemCount(12) == 0 then break end
	  os.sleep(5)
	end
	-- breaks the ender chest
	turtle.select(13)
	turtle.digUp()
  end
end
-- #######################################################################
function dig(dir)
  if checkIfFull() then depositOres() end

  -- keeps breaking blocks until their are no blocks or it is unbreakable
  if dir == "up" then
	-- keeps trying to dig the block in front
	while turtle.detectUp() do
	  -- if it is not mineable then return false
	  if not turtle.digUp() then return false end
	  -- wait for sand / gravel to fall
	  os.sleep(1)
	  -- if there is still no block then return true
	  if not turtle.detectUp() then return true end
	end
	-- if there was never any block then return false
	return false
  elseif dir == "down" then
	while turtle.detectDown() do
	  if not turtle.digDown() then return false end
	  os.sleep(1)
	  if not turtle.detectDown() then return true end
	end
	return false
  else
	while turtle.detect() do
	  if not turtle.dig() then return false end
	  os.sleep(1)
	  if not turtle.detect() then return true end
	end
	return false
  end
end
-- #######################################################################
function moveTurtle(dir,mining)
  refuelTurtle()
  if mining and dir ~= "back" then dig(dir) end
  if dir == "up" then
	while not turtle.up() do os.sleep(2) end
  elseif dir == "down" then
	while not turtle.down() do os.sleep(2) end
  elseif dir == "back" then
	while not turtle.back() do os.sleep(2) end
  else
	while not turtle.forward() do os.sleep(2) end
  end
end
-- #######################################################################
function turnTurtle(dir)
  if dir == "right" or nil then
	turtle.turnRight()
	if curDir == "n" then curDir = "e"
	elseif curDir == "e" then curDir = "s"
	elseif curDir == "s" then curDir = "w"
	elseif curDir == "w" then curDir = "n"
	end
  elseif dir == "left" then
	turtle.turnLeft()
	if curDir == "n" then curDir = "w"
	elseif curDir == "w" then curDir = "s"
	elseif curDir == "s" then curDir = "e"
	elseif curDir == "e" then curDir = "n"
	end
  end
end
-- #######################################################################
function turnTurtleTo(dir)
  -- turn right if that is fastest
  if curDir == "n" and dir == "e" then turnTurtle("right")
  elseif curDir == "e" and dir == "s" then turnTurtle("right")
  elseif curDir == "s" and dir == "w" then turnTurtle("right")
  elseif curDir == "w" and dir == "n" then turnTurtle("right") end
  -- turn left if that is fastest
  if curDir == "n" and dir == "w" then turnTurtle("left")
  elseif curDir == "w" and dir == "s" then turnTurtle("left")
  elseif curDir == "s" and dir == "e" then turnTurtle("left")
  elseif curDir == "e" and dir == "n" then turnTurtle("left") end
  -- default to turn right if neither right or left is fastest
  while curDir ~= dir do turnTurtle("right") end
end
-- #######################################################################
function getDirection()
  -- take gps reading 1
  local x1, y1, z1 = gps.locate(5)
  -- move turtle and take reading 2
  moveTurtle("forward",true)
  local x2, y2, z2 = gps.locate(5)
  -- return turtle to starting position
  moveTurtle("back",true)
  -- compare reading 1 and 2 to figure out the turtles direction
  if x2 > x1 then curDir = "e"
  elseif x2 < x1 then curDir = "w"
  elseif y2 > y1 then curDir = "s"
  else curDir = "n" end
end
-- #######################################################################
function moveTurtleTo(desX,desY,desZ)

  local curX,curY,curZ = gps.locate(5)

  -- Z / vertical movement
  local zDif = desZ - curZ
  local zDir = -1
  if desZ > curZ then zDir = 1 end

  for i = curZ+zDir, desZ, zDir do
	if zDir == 1 then
	  moveTurtle("up",true)
	else
	  moveTurtle("down",true)
	end
  end

  -- X movement (+east/-west)
  local xDif = desX - curX
  local xDir = -1
  if desX > curX then
	xDir = 1
	turnTurtleTo("e")
  elseif desX < curX then
	turnTurtleTo("w")
  end

  for i = curX+xDir, desX, xDir do
	moveTurtle("forward",true)
  end

  -- Y movement (-north/+south)
  local yDif = desY - curY
  local yDir = -1
  if desY > curY then
	yDir = 1
	turnTurtleTo("s")
  elseif desX < curY then
	turnTurtleTo("n")
  end

  for i = curY+yDir, desY, yDir do
	moveTurtle("forward",true)
  end
end
-- #######################################################################

-- #######################################################################
-- Quarry Specific
-- #######################################################################
function changeStatus(str)
  if str == "start" then status = 0
  elseif str == "row" then status = 1
  elseif str == "corner" then status = 2
  elseif str == "dig" then status = 3
  elseif str == "surface" then status = 4
  end
  saveParams()
  print("status changed to: "..str)
end
-- #######################################################################
function checkOres()
print ("checking ores")

  for i = 0, 3 do
	for ii = 1, ignoreList do
	  turtle.select(ii)
	  if turtle.compare() then break end
	  if ii == ignoreList then
		dig("forward")
	  end
	end
	turnTurtle("right")
  end






end
-- #######################################################################
function depositOres()
  dig("up")
  turtle.select(14)
  turtle.placeUp()
  for i = ignoreList + 1, 11 do
	if turtle.getItemCount(i) > 0 then
	  turtle.select(i)
	  while not turtle.dropUp() do os.sleep(5) end
	end
  end
end
-- #######################################################################
function checkIfFull()
  for i = ignoreList+1, 11 do
	if turtle.getItemCount(i) == 0 then return false end
	if i == 11 then return true end
  end
end
-- #######################################################################
function checkColumn()
  local curX,curY,curZ = gps.locate(5)
  if patMap[(curX % 5)+1][(curY % 5)+1] > 0 then return true end
end
-- #######################################################################
function digColumn()
  changeStatus("dig")
  -- find surface
  if not startup then
	while not turtle.detectDown() do
	  moveTurtle("down")
	end
  end
  -- remeber surface Z (might sometimes end up in a tree or similar)
  local curX,curY,curZ = gps.locate(5)
  --surfaceZ = curZ
  -- dig down to bedrock
  while true do
	checkOres()
	turtle.digDown()
	if not turtle.down() then
	  returnToSurface()
	  break
	end
  end
end
-- #######################################################################
function returnToSurface()
  changeStatus("surface")
  local curX,curY,curZ = gps.locate(5)
  for i = curZ, surfaceZ-1 do
	moveTurtle("up",true)
  end
  if startup then
	getDirection()
	startup = false
  end
  turnTurtleTo(moveDir)
  moveTurtle("forward",true)
  changeStatus("row")
end
-- #######################################################################
function nextRow()
  if startup then getDirection() startup = false end
  local curX,curY,curZ = gps.locate(5)
  if curX == 10 and justTurned == 0 then
	changeStatus("corner")
	moveTurtleTo(curX,curY+1,249)
	justTurned = 1
	moveDir = "w"
	changeStatus("row")
  elseif curX == -10 and justTurned == 0 then
	changeStatus("corner")
	moveTurtleTo(curX,curY+1,249)
	justTurned = 1
	moveDir = "e"
	changeStatus("row")
  else
	changeStatus("row")
  end
end
-- #######################################################################
function populateIgnoreList()
  for i = 1, 11 do
	if turtle.getItemCount(i) == 0 then break end
	ignoreList = ignoreList + 1
  end
end
-- #######################################################################

-- #######################################################################
-- File management and startup
-- #######################################################################
function makeStartupFile()
  outputFile = io.open("startup", "a")
  outputFile:write("\nshell.run(\"")
  outputFile:write(shell.getRunningProgram())
  outputFile:write("\")\n")
  outputFile:close()
end
-- #######################################################################
function readLine(file)
  nextLine = file.readLine()
  if (nextLine ~= nil) then
	return tonumber(nextLine)
  end
end
-- #######################################################################
function saveParams()
  outputFile = io.open("Params.txt", "w")
  outputFile:write(status)
  outputFile:write("\n")
  local temp
  if moveDir == "n" then temp = 0
  elseif moveDir == "e" then temp = 1
  elseif moveDir == "s" then temp = 2
  elseif moveDir == "w" then temp = 3
  end
  outputFile:write(temp)
  outputFile:write("\n")
  outputFile:write(justTurned)
  outputFile:write("\n")
  outputFile:write(ignoreList)
  outputFile:write("\n")
  --outputFile:write(surfaceZ)
  --outputFile:write("\n")
  --[[
  outputFile:write(status)
  outputFile:write("\n")
  ]]--
  outputFile:close()
end
-- #######################################################################
function loadParams()
  file = fs.open("Params.txt", "r")
  if file ~= nil then
	status = readLine(file)
	temp = readLine(file)
	if temp == 0 then moveDir = "n"
	elseif temp == 1 then moveDir = "e"
	elseif temp == 2 then moveDir = "s"
	elseif temp == 3 then moveDir = "w"
	end
	print("moveDir: "..moveDir)
	justTurned = readLine(file)
	ignoreList = readLine(file)
	--surfaceZ = readLine(file)
	
	file.close()
  end
end

-- #######################################################################
-- Program Proper
-- #######################################################################

  -- if there is a startup file then wait for the world to load
  if fs.exists("startup") then
	print("waiting for world to load")
	startup = true
	sleep(5)
	loadParams()
  else
	populateIgnoreList()
	saveParams()
	makeStartupFile()
  end

  -- program loop
  while true do
	
	-- STARTING POSITION
	if status == 0 then
	  changeStatus("start")
	  getDirection()
	  moveTurtleTo(centerX-9,centerY-10,249)
	  turnTurtleTo("e")
	  moveDir = "e"
	  changeStatus("row")
	end
	
	-- ROW
	while status == 1 do
	  local curX,curY,curZ = gps.locate(5)
	  
	  -- check if column is to be mined
	  print("checking if column needs mining")
	  if checkColumn() then digColumn() end
	  
	  print("checking if last column is finished")
	  -- stop if at end of last row
	  if curX == 10 and curY == 10 then
		status = 10
		break
	  end
	  
	  -- cornering: move to start of next row if at end of current
	  nextRow()
	  
	  -- face the right direction and move forward
	  turnTurtleTo(moveDir)
	  moveTurtle("forward",true)
	  
	  justTurned = 0
	end
	
	-- CORNERING
	if status == 2 then
	  print("resuming cornering")
	  nextRow()
	end
	
	-- DIG DOWN
	if status == 3 then
	  print("resuming digging down")
	  digColumn()
	end
	
	-- SURFACE
	while status == 4 do
	  print("resuming returning to surface")
	  returnToSurface()
	end
	
	--
	
	
	-- END PROGRAM
	if status == 10 then break end
	
  end

  -- clean up after turtle has finished routine
  if fileExists("startup") then fs.delete("startup") end
  if fileExists("Params.txt") then fs.delete("Params.txt") end

Cheers,
Lyqyd #2
Posted 18 May 2013 - 01:37 AM
Split into new topic.
tesla1889 #3
Posted 18 May 2013 - 02:32 AM
idk if you still care about this, but this could have to do with the number of global variables you are declaring. because this isn't an API file, i suggest trying it with local functions. anything to cut down on stack usage is a good thing in this case

in case you're wondering, when lua defines a new function, it pushes a string and a function to the stack before setting the string as an index in the environment to the function, sort of like this:


.const 'checkIfFull'
.function
; define checkIfFull function
.end
push 0 ; push the first constant to the stack
push 1 ; push the function to the stack
setglobal 1 0 ; set the function as a global

if you get a whole bunch of functions, the stack can get really big
BigSHinyToys #4
Posted 18 May 2013 - 04:28 AM
I would say localizing the functions / variables is a good practice but that still docent explain this error I heard soothing like this was a but and that selecting the slot before getting its content is a workaround or try the latest beta. I am using the beta and this seams to run fine.
Vattic #5
Posted 18 May 2013 - 09:08 AM
It turns out I missed something that should have been obvious because of how messy my code is. I have it checking if the inventory is full before each time it digs, when it is full it tries to dig out the space above it to place an ender chest, when it tries to dig it checks to see if the inventory is full. This goes around and around until it fills the stack.

idk if you still care about this, but this could have to do with the number of global variables you are declaring. because this isn't an API file, i suggest trying it with local functions. anything to cut down on stack usage is a good thing in this case

in case you're wondering, when lua defines a new function, it pushes a string and a function to the stack before setting the string as an index in the environment to the function, sort of like this:


.const 'checkIfFull'
.function
; define checkIfFull function
.end
push 0 ; push the first constant to the stack
push 1 ; push the function to the stack
setglobal 1 0 ; set the function as a global

if you get a whole bunch of functions, the stack can get really big
I'm going to have to look into local functions again. I only read about it breifly and had problems getting local functions calling eachother. Would it not require a large rework of what I've already got?

I would say localizing the functions / variables is a good practice but that still docent explain this error I heard soothing like this was a but and that selecting the slot before getting its content is a workaround or try the latest beta. I am using the beta and this seams to run fine.
I forgot to mention that you have to let it fill with ores before the problem appears. I'd imagine this would be the same with the beta too.

Cheers for your help guys,