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

[Solved] Weird random bug unable to squash

Started by archit, 09 June 2012 - 04:44 PM
archit #1
Posted 09 June 2012 - 06:44 PM
Hello my fellow coders :)/>/>

I consider myself a pretty decent coder, after I have been programming for several years. I have been trying to squash a bug in my turtle mining program for the last many hours, and for the life of me can't track it down.

I have been building an api for my programs, and each function in it has been tested as working before adding it to the final api code. With this api, I already managed to build a program like the one I am attempting again, that was working flawlessly. But, with bad luck, I lost it as it was only saved on computers and disks in that game world. Which is no longer running.

The basics of this program is to ask you the dimensions you want to dig on an x,y,z format, which directions (up/down and left/right), as well as however you want to configure comparing. Then it will return to any world x,y,z coord when all slots have something in them and drop everything off in a specific direction. Finally returning to it's last position and continuing on till finished. Once done it will head back to the "dropoff" location till retrieved.

Everything is working, except when going to the dropoff point, or when finished, sometimes (randomely as far as I have been able to test) will go an extra few blocks (- or +) on the x axis within minecraft. It has also missed the z axis only 1 time out of over 10 tests. I have put in several checks and logging with no avail of tracking it down.

Here is the relevant code for the problem:

snippet of code from the program with the problem: (With the debug print commands, I know the "world location" is always correct where it stops for it's current xyz and its return pos xyz. The only thing left is the call gotoPosition in my api. However, thats confusing as well, as that function has worked flawlessly on the other program when it was running.


print("finished!")
print("at pos: "..currentPos_x..":"..currentPos_y..":"..currentPos_z)
print("heading to: "..returnPos_x..":"..returnPos_y..":"..returnPos_z)
sprystudio.gotoPosition(currentPos_x, currentPos_y, currentPos_z, returnPos_x, returnPos_y, returnPos_z, currentPos_dir, returnPos_dir)

Here is the relevant code referenced from the API:

--[[
	turtle will go to a specific vector(x,y,z) and face a specific direction
	@param currentPos (current position in x,y,z format, whether local or world coords [world can be gotten from f3])
	@param destination (the position you want your turtle to end up at, in x,y,z format, in relation to currentPos.)
	@param currentDirection (which direction the turtle is facing right now (0=south, 1=west, 2=north, and 3=east [f under xyz in f3])
	@param endingDirection (which direction you want turtle facing when reaches destination, same format as currentDirection)
--]]
function gotoPosition(currentPos_x, currentPos_y, currentPos_z, destination_x, destination_y, destination_z, currentDirection, endingDirection)
  while currentPos_x ~= destination_x do
	if currentPos_x > destination_x then
	  currentDirection = faceDirection(1, currentDirection)
	  if digForward(1) then currentPos_x = currentPos_x - 1 end
	else
	  currentDirection = faceDirection(3, currentDirection)
	  digForward(1)
	  if digForward(1) then currentPos_x = currentPos_x + 1 end
	end
  end
  while currentPos_z ~= destination_z do
	if currentPos_z > destination_z then
	  currentDirection = faceDirection(2, currentDirection)
	  if digForward(1) then currentPos_z = currentPos_z - 1 end
	else
	  currentDirection = faceDirection(0, currentDirection)
	  if digForward(1) then currentPos_z = currentPos_z + 1 end
	end
  end
  while currentPos_y ~= destination_y do
	if currentPos_y > destination_y then
	  if digDown(1) then currentPos_y = currentPos_y - 1 end
	else
	  if digUp(1) then currentPos_y = currentPos_y + 1 end
	end
  end
  faceDirection(endingDirection, currentDirection)
end

--[[
	will turn the turtle so it is facing a specific direction.
	@param direction (which direction you want to face: 0=south, 1=west, 2=north, and 3=east [f under xyz in f3])
	@param currentDirection (current direction you are facing)
--]]
function faceDirection(direction, currentDirection)
  while currentDirection ~= direction do
	currentDirection = turnLeft(currentDirection)
  end
  return currentDirection
end

--[[
	A turtle attempts to dig forward a set amount of blocks, or until unable. Tries to handle any obstructions, by trying to attempt it again 20 times in 5 seconds(gravel), then by waiting 30 seconds for final attempt. If successful it returns the new inventoryArray if set, otherwise true. If not successful it returns the number of spaces it has moved forward so your able to still update it's new location.
	Needed Params:
	@param amount (# of blocks, 0 = dig but doesn't move, -1 = until unable)
	Optional Params:
	@param inventoryArray (a table containing the amounts in each inventory slot of the turtle. needed if using compare to control inventory)
	@param compareType (which type of compare we want to perform: same = equals one of the blocks, different = not equal to one of the blocks)
	@param one-nine (slots representing turtle's inventory, 1 = use that slot, 0 = dont. If any are set, then comparing will be done each dig.)
--]]
function digForward(amount, inventoryArray, compareType, one, two, three, four, five, six, seven, eight, nine)
  local compareResult, compareOnDig, zeroCheck = false, false, false
  if inventoryArray and compareType and one and two and three and four and five and six and seven and eight and nine then compareOnDig = true end
  if amount == 0 then
	zeroCheck = true
	amount = 1
  end
  if amount >= 0 then
	for y = 1, amount, 1 do
	  if turtle.detect() then
		if compareOnDig then compareResult = compare("forward", one, two, three, four, five, six, seven, eight, nine) end
		if not turtle.dig() then
		  os.sleep(30)
		  if not turtle.dig() then return false end
		end
		if compareOnDig and ((compareResult == false and compareType == "same") or (compareResult == true and compareType == "different")) then inventoryArray = sortInventory(inventoryArray, "drop")
		elseif compareOnDig then inventoryArray = sortInventory(inventoryArray, "keep") end
	  end
	  if not zeroCheck then
		if not turtle.forward() then
   print("failed to move forward, starting gravel check")
		  if not gravelCheck("forward") then
			os.sleep(30)
			if not turtle.forward() then return false end
		  end
		end
	  end
	end
  else
	while turtle.detect() do
	  if compareOnDig then compareResult = compare("forward", one, two, three, four, five, six, seven, eight, nine) end
	  turtle.dig()
	  if compareOnDig and ((compareResult == false and compareType == "same") or (compareResult == true and compareType == "different")) then inventoryArray = sortInventory(inventoryArray, "drop")
	  elseif compareOnDig then inventoryArray = sortInventory(inventoryArray, "keep") end
	  turtle.forward()
	end
  end
  if compareOnDig then return inventoryArray else return true end
end

--[[
	turns a turtle to the left, while also returning the new direction it's facing
	@param currentDirection (current direction the turtle is facing, [f under xyz in f3])
--]]
function turnLeft(currentDirection)
  turtle.turnLeft()
  currentDirection = currentDirection - 1
  if currentDirection == -1 then currentDirection = 3 end
  return currentDirection
end

--[[
	turns a turtle to the right, while also returning the new direction it's facing
	@param currentDirection (current direction the turtle is facing, [f under xyz in f3])
--]]
function turnRight(currentDirection)
  turtle.turnRight()
  currentDirection = currentDirection + 1
  if currentDirection == 4 then currentDirection = 0 end
  return currentDirection
end

--[[
	Moves a turtle forward a set amount of blocks, or until unable. Tries to handle any obstructions (i.e. gravel, players, etc..) by pausing 30 seconds and trying again once.
	@param amount (# of blocks, -1 = until unable)
--]]
function moveForward(amount)
  if amount >= 0 then
	for y = 1, amount, 1 do
	  if not turtle.forward() then
		os.sleep(30)
		if not turtle.forward() then return false end
	  end
	end
  else
	while turtle.forward() do end
  end
  return true
end

--[[
	A turtle will return the results of a compare towards a direction(forward, up and down). Returns true or false on the compare, so can use for comparing to or against. Also you have full control over exactly what slots in the inventory the block is compared to.
	@param direction (the direction of the block to compare: forward, up or down)
	@param one-nine (1 = add this slot to the compare, 0 = ignore this slot, i.e. ,1,0,0,1,1,0,0,0,1 will compare against slots 1, 4, 5, and 9)
--]]
function compare(direction, one, two, three, four, five, six, seven, eight, nine)
  local result = false
  if one == 1 then result = compareSlot(1, direction) end
  if not result and two == 1 then result = compareSlot(2, direction) end
  if not result and three == 1 then result = compareSlot(3, direction) end  
  if not result and four == 1 then result = compareSlot(4, direction) end
  if not result and five == 1 then result = compareSlot(5, direction) end
  if not result and six == 1 then result = compareSlot(6, direction) end
  if not result and seven == 1 then result = compareSlot(7, direction) end
  if not result and eight == 1 then result = compareSlot(8, direction) end
  if not result and nine == 1 then result = compareSlot(9, direction) end
  return result
end

--[[
	Sorts a turtle's inventory either keeping new blocks or dropping them based on action parameter.
	@param inventoryArray (a table holding the number of items in each slot for the turtle for the respected slots 1-9 before the new blocks)
	@param action ("keep" - keeps blocks and updates inventoryArray, "drop" - drops blocks and updates inventoryArray if values under 0)
--]]
function sortInventory(inventoryArray, action)
  for slot = 1, 9, 1 do
	local amount = turtle.getItemCount(slot)
	if amount ~= inventoryArray[slot] then
	  if amount > 0 then
		if action == "drop" then
		turtle.select(slot)
		turtle.drop(amount - inventoryArray[slot])
		else inventoryArray[slot] = amount end
	  else inventoryArray[slot] = 0 end
	end
  end
  return inventoryArray
end

That's almost everything from the api gotoPosition references. Left out the up and down versions of dig as there same as the forward with just the up and down substituted in for everything. Also it has always gone in the right y coord so not an issue.

If I forgot anything I will attach the full program code, as well as the api for reference.

The only thing I was thinking was in the X coord while loop within the gotoPosition function that the digForward(1) was not always returning true, when in fact the turtle did move forward. Since the coord is only updated here on a successful return, could screw up the movement. Yet, in every case It could return false, I added a print statement and none were ever activated.

Lastly, I was wondering if server lag can influence on turtle commands where it would perform it, but perhaps perform the action more than once during the "spike". Was thinking maybe if the movement coincides with one of my faster crontab jobs if it was possible. Sort of ruled it out without even testing, as if that was the case, it should be playing havoc on the actually digging the "quarry" dimensions as well. Yet, these have always been perfect and never off by 1 block in any direction.

Any help would be appreciated.

p.s. files attached are the full code for both the program and the api, if you need to see anything else
Lyqyd #2
Posted 10 June 2012 - 06:09 PM

 while currentPos_x ~= destination_x do
        if currentPos_x > destination_x then
          currentDirection = faceDirection(1, currentDirection)
          if digForward(1) then currentPos_x = currentPos_x - 1 end
        else
          currentDirection = faceDirection(3, currentDirection)
          digForward(1)
          --Why is this here?
          if digForward(1) then currentPos_x = currentPos_x + 1 end
        end
  end


What's line 7's deal?
archit #3
Posted 11 June 2012 - 06:18 AM
If meaning the digForward(1) , it's the method to dig forward an x amount, while performing any comparing that is setup and passed as args as well. Look up in the digForward method in the pasted code from the api for the exact code.

If referencing the if digForward(1) then … it's tracking my world coordinate and updating it, upon a successful move forward command.
Lyqyd #4
Posted 11 June 2012 - 06:56 AM
I'm trying to point out that it's the problem. Why is that call, specifically, there? It makes no sense, since its presence is not mirrored elsewhere in the code. You're going to move twice and only count it once.

Edit: Compare that x-direction's code with the other x-direction's code and both of the z-directions' code, line by line. You should see what I mean.
archit #5
Posted 11 June 2012 - 07:24 AM
Thank you so much Lyqyd, my apologies for my first response. When you first replied, I totally skipped right over it as I have done countless times already. I just assumed you were asking why not pointing out it was the problem.

Always seems the most hard to find bugs, are the easiest ones to make :(/>/>

Also a huge thank you for taking the time to go through all this code!