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

Requestion design ideas to save x,y and (maybe) z coordinates

Started by Crucidal, 18 August 2014 - 08:20 PM
Crucidal #1
Posted 18 August 2014 - 10:20 PM
Hi,

I would like to start with implementing the a* algorithm by bluntly starting to go up or down to the required z and then running the algorithm.

However, I'm not sure about the way to approach this.
My knowledge about the a* algorithm is basically based on this article: http://www.policyalmanac.org/games/aStarTutorial.htm

I think I need a table called "x" and use integer keys to refer to nested tables "y". something like this
x = { 1{}, 2{}. 3{}}

If an x coordinate is non-existent I would like to generate it:
using something like this


if exampleTable[x] == nill then 

xnumber = myVars.x
ynumber = myVars.y
y = {}
y.[number] = weight --weight refers to the term weight as used in the link
x.[newInteger] = y
else
y = x.[existingInteger][newInteger] = weight
end

I haven't coded it yet ('m the kind that thinks it through first :P/>) but I think I will run into a lot of problems with an implentation like this.

First of: In this example there is no "parenting" so getting/saving a path is difficult.
Second: Functions like table.max are useless if I safe the coordinates as keys… however, I don't know how else to get a proper dimensional array and/or a linked list of coordinates.

Did any of you ever try to tackle this problem?

Kind regards,
Cruci
Bomb Bloke #2
Posted 18 August 2014 - 11:25 PM
So if I've got this straight, you want the turtle to 1) explore the world around it, and 2) pathfinder through the explored world?

This code does exactly that. It ain't exactly A*, and you may find it a bit difficult to read, but it's perhaps worth a skim.

I save nodes like so:

local nodes = {
{node1x, node1y, node1z, linkedNode1, linkedNode2, etc},
{node2x, node2y, node2z, linkedNode1, linkedNode2, etc},
etc}

By getting the length of nodes[someNode] and subtracting three, I know how many nodes link to someNode. I never need to look nodes up by their co-ords: all I need to know is which node the turtle is at, and then I can inspect the attached nodes from there.
Crucidal #3
Posted 20 August 2014 - 06:53 PM
I really really like your code!
Most of it I don't understand yet… but you seem to have knowledge of all the useful "shortcuts" to write something in syntax that is as short as possible… I really like that :-)

What exactly is happening down here? Do you create an array with all these "objects" in it or are all these objects becoming arrays?

local node, direction, curnode, x, y, z, targetX, targetY, targetZ, pathList, gpsAccess, comparing = {}

Could you explain how you use the two-dimensional arrays?
based on the comment I know what the function does, but I cannot find your specification of the array node.
What does 1,2,3 refer to?

-- Returns true if the turtle is at the specified node.
local function atNode(tnode) return (x == node[tnode][1] and y == node[tnode][2] and z == node[tnode][3]) end

So if I've got this straight, you want the turtle to 1) explore the world around it, and 2) pathfinder through the explored world?

This code does exactly that. It ain't exactly A*, and you may find it a bit difficult to read, but it's perhaps worth a skim.

I save nodes like so:

local nodes = {
{node1x, node1y, node1z, linkedNode1, linkedNode2, etc},
{node2x, node2y, node2z, linkedNode1, linkedNode2, etc},
etc}

By getting the length of nodes[someNode] and subtracting three, I know how many nodes link to someNode. I never need to look nodes up by their co-ords: all I need to know is which node the turtle is at, and then I can inspect the attached nodes from there.

based on what you said earlier: saving "linkedNodeX". What kind of objects are they? Also nodes (and thus arrays?)? How did you initialize the whole set of nodes?

Loooots of questions! ^^" I hope you don't mind :-)
Bomb Bloke #4
Posted 21 August 2014 - 01:44 AM
What exactly is happening down here? Do you create an array with all these "objects" in it or are all these objects becoming arrays?

"node" becomes an array. The rest of the variables (direction, curnode, etc) don't get set to anything, the Lua VM just notes them down as variables that're to be treated as local to the script.

If you did this:

local var1, var2 = {}, "cow"

… then var1 would get set to point to a new table, and var2 would get set to the string "cow". If you supply less data than you do variables, the extra variables remain set to nil.

Could you explain how you use the two-dimensional arrays?
based on the comment I know what the function does, but I cannot find your specification of the array node.
What does 1,2,3 refer to?

-- Returns true if the turtle is at the specified node.
local function atNode(tnode) return (x == node[tnode][1] and y == node[tnode][2] and z == node[tnode][3]) end

"node" starts out as an empty table, and gets filled with values as the turtle explores. On boot, it adds a node referring to its starting position (line 337 - and if there's a GPS handy, it'll bug the user for the co-ords it should travel to, and those go in the node table as a second entry on line 317). Every time the turtle finds an intersection it throws that in the table too (around line 226).

Each node is defined according to my previous post (though there's an additional "explore" table assigned to them as well). node[whateverNode][1] is the x co-ord of "whateverNode". node[whateverNode][2] is the y co-ord, and node[whateverNode][3] is z.

Thus if the variables x, y and z (which track the turtle's current position) match the co-ords of a given node, then the turtle must be at that node.

(Note that I treat z as "distance from the bottom of the world", as that's the convention I'm familiar with from most other games, but I only do it internally - MineCraft itself uses y for this value, and so the turtle expects any co-ords it receives (from eg a GPS) to match that convention.)

based on what you said earlier: saving "linkedNodeX". What kind of objects are they? Also nodes (and thus arrays?)? How did you initialize the whole set of nodes?

Well, the linkedNode values attached to each node are simply numbers indicating the index of each node the turtle can travel to from the node it's at.

Here's an example of a manually-built node table I gave to a older turtle that helped manage a base for me:

local node = {{241,422,58,   2,3},       --   1, barrel central.
        {244,422,57,   1,3,4},  --   2, processed resource dropoff.
        {244,419,57,   1,2},    --   3, machine central.
        {242,430,57,   2}}      --   4, chopper programming point.

When the turtle is at node 1 ("barrel central"), it knows that the linked nodes are 2 and 3. Say it runs its pathfinding code with the aim of getting from node 1 to node 4 (the spot for placing new turtles to act as wood choppers - which is a long story in itself). It can't just try to go directly from 1 to 4, because enough blocks are in the way that it'll get stuck on a wall or something.

So instead, it sees that node 1 has clear access to nodes 2 and 3. It checks the position of each of those nodes, and notices that only node 2 is linked to node 4. So now it has a path - it will travel from node 1 to node 2, then from node 2 to node 4.

Node 3 also links to node 2, so in theory the turtle could also go 1 - 3 - 2 - 4. However, it's bright enough to know that 1 - 2 - 4 involves traveling a shorter distance, and so that's what it goes with.

In the case of the pathfinding turtle, whenever a new node is discovered, that node is automatically "linked" to the node that the turtle started exploring from to get to that new node (and the starting node is likewise linked to the new one). If, while exploring, the turtle stumbles across a pre-explored node, then much the same thing happens. This goes on until all the directions the turtle can travel from each node have been crossed off as "explored".

Whenever the turtle hits a dead end, it checks the node list to see which other nodes still have directions available to explore in. The next node to check might be quite far away, requiring a lot of turns to get to - that's when the pathfinding code kicks in, allowing the turtle to navigate through the nodes that've already been explored back to the next one that needs checking.

Bear in mind that nodes don't have to be right next to each other. If the turtle moves into a space and finds that the only directions it can travel are either forward or backward, then it doesn't register that space as a junction but instead keeps going.

It's a little more complex than that (sometimes the turtle doesn't bother to save points as nodes, and sometimes it deletes nodes - this is done to keep the node table free of dead-ends that don't go anywhere), but that's the general gist of it:

while true do
  if not at an unexplored node,
    pathfind to an unexplored node using your A* code.
  end

  explore in one direction from the node you're at.
  (mark that direction as explored for that node.)
  (add the new node you find to the node table, link it to the one you explored from)

  if at the destination,
    finish the script
  end

  prune any dead-end nodes from the table
end

For now, I advise concentrating on building around that loop, leaving the node-pruning thing until very last (assuming you bother with it at all - I didn't bother to do it properly myself). Don't worry too much about what the rest of my script is doing. That way lies madness.
Edited on 21 August 2014 - 12:02 AM
Crucidal #5
Posted 26 August 2014 - 07:42 PM
Spoiler

--[[
	 This API is created to provide Turtles functions to keep
	   track of their relative location while moving around.
	   Basically, after moving or turning I would like to save this information in a file.
		Just in case the server shuts down or the chunk unloads.
]]--
			 --current location--create variables
			 -- used to be "local x = 0" but that did not work either
			 local myVars = {["x"] = 0,["y"] = 0,["z"] = 0,["d"] = 0,["r"]=0}
			 local boundary = {}
local goalVars = {["x"] = 0,["y"] = 0,["z"] = 0,["d"] = 0}
local no = {}
local side = { ["north"] = {["x"] = 0,["y"] = 0, ["z"] = 0},
["east"]  = {["x"] = 0,["y"] = 0, ["z"] = 0},
["south"] = {["x"] = 0,["y"] = 0, ["z"] = 0},
["west"]  = {["x"] = 0,["y"] = 0, ["z"] = 0},
["up"]	= {["x"] = 0,["y"] = 0, ["z"] = 0},
["down"]  = {["x"] = 0,["y"] = 0, ["z"] = 0}
}


--[[
support functions:
getLocation FromFile

]]--

--just useful
function show()
term.clear()
term.setCursorPos(1,1)
print("goal: ")
print("x: " .. goalVars.x .. "  y: " .. goalVars.y .. "  z: " .. goalVars.z "  d: " .. goalVars.d)
print("myVars: ")
print("x: " .. myVars.x .. "  y: " .. myVars.y .. "  z: " .. myVars.z "  d: " .. myVars.d)
end

--getLocation and direction
function getLocation()
--print("getLocation()")
		locationFile = fs.open("location", "r")
		myVars = textutils.unserialise(locationFile.readAll())
		locationFile.close()

end

--setLocation and direction
function setLocation()
--print("setLocation()")
		locationFile = fs.open("location", "w")
		locationFile.write(textutils.serialise(myVars))
		locationFile.close()

end

--getLocation and direction
function getBoundary()
--print("getBoundary")
		boundaryFile = fs.open("boundary", "r")
		boundary = textutils.unserialise(boundaryFile.readAll())
		boundaryFile.close()

end

--setLocation and direction
function SetBoundary()
--print("setBoundary")
		boundaryFile = fs.open("boundary", "w")
		boundaryFile.write(textutils.serialise(boundary))
		boundaryFile.close()

end

--toggleRegistery
function toggleR()
--print("toggleR()")
		 if myVars.r == 0 then
		 myVars.r = 1
		 else
		 myVars.r = 0
		 end
end

--movement functions
function registerMove()
		--print("registerMove()")
d = myVars.d
		if d == 0 then
				myVars.y = myVars.y+1
		elseif d == 1 then
				myVars.x = myVars.x+1
		elseif d == 2 then
				myVars.y = myVars.y-1
		elseif d == 3 then
				myVars.x = myVars.x-1
		end
				if myVars.r == 1 then
getBoundary()
if boundary[x] == nil then
y = {}
end
setBoundary()
				end
end

--moves horizontally and registers moves.
function move(amount)
	   print("move(amount)")
		for x = 0, amount-1, 1 do
		getLocation()
				if turtle.forward() then
						registerMove()
						setLocation()
				end
		end
end

-- moves vertically and registers moves.
function moveV(amount)
	   --print("moveV(amount)"
		if amount == nil then
				amount = 1
				end
		for x = 0, math.abs(amount)-1, 1 do
if amount > 0 then
getLocation()
if turtle.up() then
myVars.z = myVars.z+1
setLocation()
end
elseif amount < 0 then
getLocation()
if turtle.down() then
myVars.z = myVars.z-1
end
end
end

		for x = 0, amount-1, 1 do
		getLocation()
				if turtle.forward() then
						myVars.z = myVars.z+upOrDown
						setLocation()
				end
		end

end

--turns left, saves direction
function left(amount)
	   --print("left(amount)")
		if amount == nil then
				amount = 1
		end

		for x = 0, amount-1, 1 do
				getLocation()
				turtle.turnLeft()
				d = myVars["d"]
						if d > 0 then
								myVars.d = d-1
						else
								myVars.d = 3
						end
				setLocation()
		end
end

--turns right, saves direction
function right(amount)
	   --print("right(amount)")
		if amount == nil then
				amount = 1
		end

		for x = 0, amount-1, 1 do
				getLocation()
				turtle.turnRight()
				d = myVars.d
				if d < 3 then
								myVars.d = d+1
						else
								myVars.d = 0
						end
				setLocation()
		end
end

--initialize variables
function init()
--print("init()")
myVars.x = 0
myVars.y = 0
myVars.z = 0
myVars.d = 0
myVars.r = 0
setLocation()

goalVars = {["x"] = 0,["y"] = 0,["z"] = 0,["d"] = 0}
no = {}
side = {["north"] =  {["x"] = 0,["y"] = 0, ["z"] = 0},
["east"] =  {["x"] = 0,["y"] = 0, ["z"] = 0},
["south"] = {["x"] = 0,["y"] = 0, ["z"] = 0},
["west"] =  {["x"] = 0,["y"] = 0, ["z"] = 0},
["up"] =  {["x"] = 0,["y"] = 0, ["z"] = 0},
["down"] = {["x"] = 0,["y"] = 0, ["z"] = 0}
}

end

-- turns to north (0), east(1), south(2) or west(3)
-- tries to do it efficiently :P/>/>/>/>/>/>/>	  
function turnTo(direction)
--print("turnTo(direction)")
x = myVars.d - direction
if (x == -1 or x == 3) then
		right()
		elseif (x == 1 or x == -3) then
		left()
		elseif math.abs(x) == 2 then
		right(2)
		else
		--do nothing
		end


end

--goes to (0,0) regardless of height or direction	  
function returnEZ()
print("returnEZ()")
getLocation()
if myVars.x > 0 then
						turnTo(3) --west
				move(myVars["x"])
				elseif myVars["x"] < 0 then
				turnTo(1) --east
				move(myVars["x"])
				else
				--do nothing
		end
				if myVars["y"] > 0 then
						turnTo(2) --south
						move(myVars["y"])
						elseif myVars["y"] < 0 then
						turnTo(0) --east
						move(myVars["y"])
						else
						--do nothing
				end
end	

--goes to given coordinates x, y, z without destroying terrain
--returns true if there were no obstacles and destination is reached.
function goToEZ(x,y,z)
print("goToEZ(x,y,z)")
getLocation()
amountX = math.abs(x- myVars.x)
amountY = math.abs(y- myVars.y)
amountZ = math.abs(z- myVars.z)

if myVars.x > x then
				turnTo(3) --west

				elseif myVars["x"] < x then
				turnTo(1) --east
	end
move(amountX)


	if myVars["y"] > y then
turnTo(2) --south
elseif myVars["y"] < y then
		turnTo(0) --east
	end
move(amountY)

if myVars["z"] > z then
moveV(-amountZ)
elseif myVars["z"] < z then
		moveV(amountZ)
	end

return (myVars.x == x and myVars.y == y and myVars.z == z)
end

--returns the weight of a node.
function weight(x,y,z)
print("weight(x,y,z)")
return (
(math.abs(goalVars.x-x)+math.abs(goalVars.y-y)+math.abs(goalVars.z-z))

)
end
--determines coordinates of all sides around the turtle.
function sides()
print("sides()")
--north
side.north.x = myVars.x
side.north.y = myVars.y+1
side.north.z = myVars.z
--east
side.east.x = myVars.x+1
side.east.y = myVars.y
side.east.z = myVars.z
--south
side.south.x = myVars.x
side.south.y = myVars.y-1
side.south.z = myVars.x

--west
side.west.x = myVars.x-1
side.west.y = myVars.y
side.west.z = myVars.x
--up
side.up.x = myVars.x
side.up.y = myVars.y
side.up.z = myVars.z+1
--down
side.down.x = myVars.x
side.down.y = myVars.y
side.down.z = myVars.z-1
end

--returns true if goalVars equal myVars.
function arrived()
print("arrived()")
return (myVars.x == goalVars.x and myVars.y == goalVars.y and myVars.z == goalVars.z)
end

--FIRST ATTEMPT TO PATHFINDING YAY
--will not be able to continue automatically after chunk-unloading/server shutdown
function goTo(x,y,z,d)
print("goTo(x,y,z,d)")
goalVars.x, goalVars.y, goalVars.z, goalVars.d = x, y, z, d
while (not arrived()) do
print("in not-arrived-loop")
--determine side-coordinates
sides()
--determined value with lowest weight
minWeight = weight(side.north.x, side.north.y, side.north.z)
minSide = side.north
-- k = cardinal direction (at least I think so)
-- v = sub-variable of k?
for k, v in pairs(side) do
-- check if min side != in no
check = false
if (weight(v.x, v.y, v.z) <= minWeight) then
for e, t in pairs(no) do
if (v.x == t.x and v.y == t.y and v.z == z) then
check = false
end

if (check) then
minSide = k
end
end
end
end

--goto lowest weight
if (goToEZ(minSide.x, minSide.y, minSide.z)) then
print("go to lowest weight loop (dus we zijn er)")
--good, do this again :P/>/>/>/>/>/>/>
else
print("niet bij lowest weight aangekomen")
table.insert(no, {["x"] = minSide.x, ["y"] = minSide.y, ["z"] = minSide.z})
end
end
turnTo(d)
end





function help()
print("getLocation(), setLocation(), move(amount), moveV(amount), left(amount)")
print("right(amount), init(), turnTo(direction), returnEZ(), goToEZ(x,y)")
end

This is my code so far. I've decided to re-discover the surroundings every time the robot restarts the program because we're still playing early-game in our current world and there are a lot of buildings being raised :-)
Currently when I try to goTo(0,2,0,1) from the starting position (0,0,0,0) it works! :-)
the integers stand for goTo(X,Y,Z,Direction)

However, going to any other direction which is not "North"/0 from my starting point cannot be reached.
I suspect that my usage of the pairs k,v in the table side is faulty. if K would denote the first key and V the second, then calling v.x (to get the x-coordinate of K) doesn't make sense.
I cannot really figure out how to do this though.

Another problem is that I am not able to print my side-table. the following bit of code denotes the lua commands I tried and the results it yields.
Could anyone give me advice please? :-)


lua
os.loadAPI("myAPI")
myAPI.sides()
t = textutils.serialise(side)
print(textutils.unserialise(t)

sides()

1

EDIT: the code in my spoiler is not showing up properly… it sees everything as comments while it works in my own editor. help? :X
FIXED: it doesn't like ' in the comments
Edited on 26 August 2014 - 06:51 PM
Bomb Bloke #6
Posted 27 August 2014 - 03:43 AM
Beats me what's going on with the turtle's inability to travel in any direction but north - there's a bit much code to read through. Try explaining what the turtle does when you try going other ways.

I suspect that my usage of the pairs k,v in the table side is faulty. if K would denote the first key and V the second, then calling v.x (to get the x-coordinate of K) doesn't make sense.

Say you've got this:

side = {["north"] =  {["x"] = 0,["y"] = 0, ["z"] = 0},
["east"] =  {["x"] = 0,["y"] = 0, ["z"] = 0},
["south"] = {["x"] = 0,["y"] = 0, ["z"] = 0},
["west"] =  {["x"] = 0,["y"] = 0, ["z"] = 0},
["up"] =  {["x"] = 0,["y"] = 0, ["z"] = 0},
["down"] = {["x"] = 0,["y"] = 0, ["z"] = 0}}

"side" is a variable which holds a pointer leading to a table. In the table, you've got the keys "north", "south", "east", etc. Each of these hold a pointer to another table.

So, if you do this:

for k, v in pairs(side) do ...

… then when "k" is "north", "v" will be the table attached to "north". When "k" is "south", "v" will be the table attached to "south". Etc. Thus v.x/v.y/v.z is correct.

Line 350 looks a little odd to me though:

if (v.x == t.x and v.y == t.y and v.z == z) then

Why "t.x", "t.y", then just "z"?

Another problem is that I am not able to print my side-table.

One way of many:

for direction,subtable in pairs(side) do
  for coord,value in pairs(subtable) do
    print(direction..": "..coord..": "..value)
  end
end
Crucidal #7
Posted 27 August 2014 - 11:53 AM
… then when "k" is "north", "v" will be the table attached to "north". When "k" is "south", "v" will be the table attached to "south". Etc. Thus v.x/v.y/v.z is correct.

Thank you for the explanation! :-)

Line 350 looks a little odd to me though:

if (v.x == t.x and v.y == t.y and v.z == z) then

Why "t.x", "t.y", then just "z"?

Being sloppy is the answer, it should have been t.z indeed. Using better variable names seems wise as well.


One way of many:

for direction,subtable in pairs(side) do
  for coord,value in pairs(subtable) do
	print(direction..": "..coord..": "..value)
  end
end

thanks, I'll give this a try soon.
Crucidal #8
Posted 30 August 2014 - 11:22 AM
I'm not able to print the information from my table and the error "attempt to call number" does not provide me enough information to solve this:


--[[
This API is created to provide Turtles functions to keep
track of their relative location while moving around.
		Basically, after moving or turning I would like to save this information in a file.
		Just in case the server shuts down or the chunk unloads.
]]--

												--current location
			 local myVars = {["x"] = 0,["y"] = 0,["z"] = 0,["d"] = 0,["r"]=0}
			 local boundary = {}
						 local goalVars = {  ["x"] = 0, ["y"] = 0, ["z"] = 0, ["d"] = 0}
						 local no = {}
						 local side = { ["north"] =	 {["x"] = 0, ["y"] = 0, ["z"] = 0},
										["east"]  =	 {["x"] = 0, ["y"] = 0, ["z"] = 0},
										["south"] =  {["x"] = 0, ["y"] = 0, ["z"] = 0},
										["west"]  =	 {["x"] = 0, ["y"] = 0, ["z"] = 0},
										["up"]	=	 {["x"] = 0, ["y"] = 0, ["z"] = 0},
										["down"]  =	 {["x"] = 0, ["y"] = 0, ["z"] = 0}
												}


--[[
support functions:
getLocation FromFile

]]--

--useful
function show()
term.clear()
term.setCursorPos(1,1)
print("goal: ")

[error on this line: attempt to call number]   print("x: " .. goalVars.x .. "  y: " .. goalVars.y .. "  z: " .. goalVars.z .. "  d: " .. goalVars.d)

print("myVars: ")
print("x: " .. myVars.x .. "  y: " .. myVars.y .. "  z: " .. myVars.z .. "  d: " .. myVars.d)
end

any clue?
Edited on 30 August 2014 - 09:24 AM
Bomb Bloke #9
Posted 30 August 2014 - 11:48 AM
An "attempt to call number" means you're trying to treat a numeric value like a function. You're only attempting one call on that line - of the function "print". In other cases, I'd guess that you accidentally overwrite "print" with a number at some point, but seeing as you successfully called it two lines above the point you marked out, that can't be the case.

Double check that the error is indicating that line in that script file.
Crucidal #10
Posted 30 August 2014 - 12:04 PM
Okay,

I'm getting weird behavior that I have not seen before.

test is a simple program that looks like this


os.loadAPI("maTest")
maTest.init()
maTest.show()

when I call test the excact error is:

"maTest:34: attempt to call number"

however, I changed my code ("maTest") and put some random "enters"/end of lines in the code just to check whether the error is really happeining in this script file like you mentioned.

However, the error doesn't change even when I set the line that was on 34 to 35.

What could be my next step to solve this mystery? :-)
Edited on 30 August 2014 - 10:04 AM
Crucidal #11
Posted 30 August 2014 - 12:14 PM
Solved it!
I simply restarted the turtle and the error was gone. It's really strange but I am glad it works now.
Crucidal #12
Posted 30 August 2014 - 05:56 PM
I'm slowly but surely getting somewhere :-)

For those interested:
Spoiler

--[[
This API is created to provide Turtles functions to keep
track of their relative location while moving around.
Basically, after moving or turning I would like to save this information in a file.
Just in case the server shuts down or the chunk unloads.
]]--

--current location--create variables
local myVars = {["x"] = 0,["y"] = 0,["z"] = 0,["d"] = 0,["r"]=0}
local boundary = {}
local goalVars = {  ["x"] = 0, ["y"] = 0, ["z"] = 0, ["d"] = 0}
local no = {}
local side = { ["north"] = {["x"] = 0, ["y"] = 0, ["z"] = 0},
			   ["east"]  = {["x"] = 0, ["y"] = 0, ["z"] = 0},
			   ["south"] = {["x"] = 0, ["y"] = 0, ["z"] = 0},
			   ["west"]  = {["x"] = 0, ["y"] = 0, ["z"] = 0},
			   ["up"]	= {["x"] = 0, ["y"] = 0, ["z"] = 0},
			   ["down"]  = {["x"] = 0, ["y"] = 0, ["z"] = 0}
			 }


--[[
support functions:
getLocation FromFile
]]--

--useful
function show()
   term.clear()
   term.setCursorPos(1,1)
   print("goal: ")
   print("x: " .. goalVars.x .. "  y: " .. goalVars.y .. "  z: " .. goalVars.z .. "  d: " .. goalVars.d)
   print("myVars: ")
   print("x: " .. myVars.x .. "  y: " .. myVars.y .. "  z: " .. myVars.z .. "  d: " .. myVars.d)
end

--getLocation and direction
function getLocation()
   --print("getLocation()")
   locationFile = fs.open("location", "r")
   myVars = textutils.unserialise(locationFile.readAll())
   locationFile.close()

end

--setLocation and direction
function setLocation()
   --print("setLocation()")
   locationFile = fs.open("location", "w")
   locationFile.write(textutils.serialise(myVars))
   locationFile.close()	
end

--getLocation and direction
function getBoundary()
   --print("getBoundary")
   boundaryFile = fs.open("boundary", "r")
   boundary = textutils.unserialise(boundaryFile.readAll())
   boundaryFile.close()	
end

--setLocation and direction
function SetBoundary()
   --print("setBoundary")
   boundaryFile = fs.open("boundary", "w")
   boundaryFile.write(textutils.serialise(boundary))
   boundaryFile.close()

end

--toggleRegistery
function toggleR()
   --print("toggleR()")
   if myVars.r == 0 then
	  myVars.r = 1
   else
	  myVars.r = 0
   end
end

--movement functions
function registerMove()
   --print("registerMove()")
	  d = myVars.d
   if d == 0 then
	  myVars.y = myVars.y+1
   elseif d == 1 then
	  myVars.x = myVars.x+1
   elseif d == 2 then
	  myVars.y = myVars.y-1
   elseif d == 3 then
	  myVars.x = myVars.x-1
   end

   if myVars.r == 1 then
	  getBoundary()
	  if boundary[x] == nil then
		 y = {}
	  end
	  setBoundary()
   end
end

function move(amount)
   --print("move(amount)")
   for x = 0, amount-1, 1 do
	  getLocation()
	  if turtle.forward() then
		 registerMove()
		 setLocation()
	  end
	end
end

function moveV(amount)
   --print("moveV(amount)"
   if amount == nil then
	  amount = 1
   end

   if amount > 0 then
	  for x=0,math.abs(amount)-1,1 do
		 getLocation()
		 if turtle.up() then
			myVars.z = myVars.z+1
			setLocation()
		 end
	  end
	end

   if amount < 0 then
	  for x=0,math.abs(amount)-1,1 do
		 getLocation()
		 if turtle.up() then
			myVars.z = myVars.z-1
			setLocation()
		 end
	  end
	end	
end

function left(amount)
   --print("left(amount)")
   if amount == nil then
	  amount = 1
   end
   for x = 0, amount-1, 1 do
	  getLocation()
	  turtle.turnLeft()
	  if d > 0 then
		 myVars.d = myVars.d-1
	  else
		 myVars.d = 3
	  end
	  setLocation()
   end
end

function right(amount)
   --print("right(amount)")
   if amount == nil then
	  amount = 1
   end
   for x = 0, amount-1, 1 do
		 getLocation()
		 turtle.turnRight()
	  if d < 3 then
		 myVars.d = myVars.d+1
	  else
		 myVars.d = 0
	  end
		 setLocation()
   end
end

function init()
	--print("init()")
	myVars.x = 0
	myVars.y = 0
	myVars.z = 0
	myVars.d = 0
	myVars.r = 0
	setLocation()
	goalVars = {["x"] = 0,["y"] = 0,["z"] = 0,["d"] = 0}
	no = {[0] = {["x"] = -999,["y"] = -999,["z"] = -999}}
	side = {["north"] ={["x"] = 0,["y"] = 0, ["z"] = 0},
			["east"]  ={["x"] = 0,["y"] = 0, ["z"] = 0},
			["south"] ={["x"] = 0,["y"] = 0, ["z"] = 0},
			["west"]  ={["x"] = 0,["y"] = 0, ["z"] = 0},
			["up"]	={["x"] = 0,["y"] = 0, ["z"] = 0},
			["down"]  ={["x"] = 0,["y"] = 0, ["z"] = 0}
		   }

end

function turnTo(direction)
	--print("turnTo(direction)")
	x = myVars.d - direction
	if (x == -1 or x == 3) then
		right()
	elseif (x == 1 or x == -3) then
		left()
	elseif math.abs(x) == 2 then
		right(2)
	else
		--do nothing
	end


end

function returnEZ()
	--print("returnEZ()")
	getLocation()
	if myVars.x > 0 then
		turnTo(3) --west
		move(myVars["x"])
	elseif myVars["x"] < 0 then
		turnTo(1) --east
		move(myVars["x"])
	else
		--do nothing
	end
	if myVars["y"] > 0 then
		turnTo(2) --south
		move(myVars["y"])
	elseif myVars["y"] < 0 then
		turnTo(0) --east
		move(myVars["y"])
	else
		--do nothing
	end
end	

function goToEZ(x,y,z)
	--print("goToEZ(x,y,z)")
	getLocation()
	amountX = math.abs(x- myVars.x)
	amountY = math.abs(y- myVars.y)
	amountZ = math.abs(z- myVars.z)

	if myVars.x > x then
		turnTo(3) --west
	elseif myVars.x < x then
		turnTo(1) --east	  
	end
	move(amountX)
	if myVars.y > y then
		turnTo(2) --south
	elseif myVars.y < y then
		turnTo(0) --east
	end
	move(amountY)
	if myVars.z > z then
		moveV(-amountZ)
	elseif myVars.z < z then
		moveV(amountZ)
	end
	return (myVars.x == x and myVars.y == y and myVars.z == z)
end

--returns the weight of a
function weight(x,y,z)
	--print("weight(x,y,z)")
	return
	(
	math.abs(goalVars.x-x)+math.abs(goalVars.y-y)+math.abs(goalVars.z-z)
	)
end
--set sides
function sides()
	--print("sides()")
	--north
	side.north.x = myVars.x
	side.north.y = myVars.y+1
	side.north.z = myVars.z
		--east
		side.east.x = myVars.x+1
		side.east.y = myVars.y
		side.east.z = myVars.z
	--south
	side.south.x = myVars.x
	side.south.y = myVars.y-1
	side.south.z = myVars.x
		--west
		side.west.x = myVars.x-1
		side.west.y = myVars.y
		side.west.z = myVars.x
	--up
	side.up.x = myVars.x
	side.up.y = myVars.y
	side.up.z = myVars.z+1
		--down
		side.down.x = myVars.x
		side.down.y = myVars.y
		side.down.z = myVars.z-1

	if (false) then
		for direction, subtable in pairs(side) do
			text = direction .. ":="
			w = weight(subtable.x, subtable.y, subtable.z)
			for coord, value in pairs(subtable) do
				text = text.. " " .. coord .. ": " .. value
			end
			print(text .. " weight = " .. w)
			--wait for user
			event, key = os.pullEvent("char")
		end
	end

end

function arrived()
	--print("arrived()")  
	return  (
		myVars.x == goalVars.x and myVars.y == goalVars.y and myVars.z == goalVars.z
			)
end

--FIRST ATTEMPT TO PATHFINDING YAY
--zonder server-shutdown-mechanisme
function goTo(x,y,z,d)
	--print("goTo(x,y,z,d)")
	goalVars.x, goalVars.y, goalVars.z, goalVars.d = x, y, z, d
	while (not arrived()) do
		--print("in not-arrived-loop")
		--determine side-
		sides()
		--determined value with lowest weight
		minWeight = weight(side.north.x, side.north.y, side.north.z)
		minSide = side.north
		check = true
		for direction, subtable in pairs(side) do
			-- check if min side != in no
			if (weight(subtable.x, subtable.y, subtable.z) < minWeight) then
				print("There is a direction smaller than the minSide")
				event, key = os.pullEvent("char")
				for index, subtable2 in pairs(no) do
					if (subtable2.x == subtable.x and subtable2.y == subtable.y and subtable2.z == subtable.z) then
						print("coordinaten zijn in no terecht gekomen")
						check = false
					end
				end
				print(check)
				if (check == true) then
					minSide = subtable
					minWeight = weight(subtable.x, subtable.y, subtable.z)
					print("check is true and the coordinates of new minSide are: ")
					for coord, value in pairs(minSide) do
						print(coord .. ": ".. value)
					end
				end
			end
		end
		--goto lowest weight
		if (goToEZ(minSide.x, minSide.y, minSide.z)) then
			--print("go to lowest weight loop (dus we zijn er)")
			--good, do this again :P/>/>/>
		else
			--print("niet bij lowest weight aangekomen")
			table.insert(no, {["x"] = minSide.x, ["y"] = minSide.y, ["z"] = minSide.z})
		end
	end
	turnTo(d)
end





function help()
print("getLocation(), setLocation(), move(amount), moveV(amount), left(amount)")
print("right(amount), init(), turnTo(direction), returnEZ(), goToEZ(x,y)")
end

My turtle sucessfully travels from (0,0,0,0) (being x,y,z,direction) to (1,4,0,1). However, when walking in the south direction (when going back to (0,0,0,0) it always goes up after going forward. Also: adding coordinates to the "no" table needs to be refined. (0 = north, 1 = east, 2 = south, 3 = west)

In order to find out exactly what is happening with my program I would like to know if there is a way to use parallel programming in order to get the following functionality.

The turtle runs through the program as usual but when I press P it will Pause,
Next When I press S, it should show it's current location and/or when I press W it should show the weights of coordinates around itself. When P is pressed again, the turtle should continue.

Is this possible with some aid and my level of expertise? =P

EDIT:

from (0,0,0,0) to (-1,-4-0,1) works
from (-1,-4,0,1) to (0,0,0,0) works as well!

from (1,4,0,1) to (0,0,0,0) still doesn't work though… programming can be really confusing! :-)
Edited on 30 August 2014 - 05:17 PM
Bomb Bloke #13
Posted 31 August 2014 - 02:09 AM
I think you'd be better off having the turtle open a text file, and writing that data into it with every movement it makes. Don't just leave the file open - constantly re-open it in append mode, and leave it closed between movements (or else you won't be able to use external text editors to view the file while the script is running).

You could then use something like this to halt the turtle at specific points.
Crucidal #14
Posted 31 August 2014 - 07:14 PM
thank you,
I will take a look at it tomorrow! :-)

Concerning re-opening the file. As far as I know I am already doing this constantly.

navigation issues have been resolved. Movement between point A and B, without obstacles or single blocks in between is now operational.

I'm now working on saving a "path" were the turtle has been already and more importantly: Deciding which movements are allowed based on it's path and the objects surrounding it.
I'm not requesting help for this, it's just info :P/>

programming is fun!