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

Trying to tidy up a remote turtle mining/mapping script, new to lua

Started by skyeyemachine, 25 April 2012 - 04:23 AM
skyeyemachine #1
Posted 25 April 2012 - 06:23 AM
Hello all,

Firstly, I found a program I am really excited about; it allows me to control a turtle remotely and have it map out its path on a 2D map. However, it's coded quite cryptically, and I've also tried to expand its functions a bit. The resulting program runs, but I seem to have botched something, as the turtle behaves erratically. I'm new to lua and programming in general, but I've been careful, and I can't seem to pick out where my error(s) lie.

If anyone cares to take a look, I'd appreciate any help in tracking my bugs.

The original, for the turtle and terminal respectively;

Spoilerprint("ID?")
ID = tonumber(read())

x = 45
y = 45
xOff = 20
yOff = 36
dir = 0
frontx = 0
fronty = 1

function turn(s)
if s == "Right" then
turtle.turnRight()
dir = dir + 1
if dir > 3 then dir = 0 end
end
if s == "Left" then
turtle.turnLeft()
dir = dir - 1
if dir < 0 then dir = 3 end
end
Updatedif()
end

function Updatedif()
if dir == 0 then frontx = 0 fronty = -1 end
if dir == 1 then frontx = 1 fronty = 0 end
if dir == 2 then frontx = 0 fronty = 1 end
if dir == 3 then frontx = -1 fronty = 0 end
end

function Scan()
scannedx = tostring(x + frontx)
if scannedx:len() < 2 then scannedx = table.concat({"0",scannedx},"") end
scannedy = tostring(y + fronty)
if scannedy:len() < 2 then scannedy = table.concat({"0",scannedy},"") end

scan = turtle.detect()
if scan then rednet.send(ID, table.concat({"0",scannedx,scannedy,"0"},"")) end
if not scan then rednet.send(ID, table.concat({"0",scannedx,scannedy,"2"},""))end
end

function FullScan()
for i = 1,4 do
Scan()
turn("Right")
end
end

function SetDir(s)
while dir ~= s do
turn("Right")
end
end

function Dig()
turtle.dig()
os.sleep(0.40)
Scan()
end

function Place()
turtle.place()
Scan()
end

function Forward()
if not turtle.detect() then
if dir == 0 and y > 1 then
turtle.forward()
y = y - 1
if y > 8 and y + 1 > 8 and y < 82 and y + 1 < 82 then
yOff = yOff - 1
end
end
if dir == 1 and x < 90 then
turtle.forward()
x = x + 1
if x < 66 and x - 1 < 66 and x > 24 and x - 1 > 24 then
xOff = xOff + 1
end
end
if dir == 2 and y < 90 then
turtle.forward()
y = y + 1
if y < 82 and y - 1 < 82 and y > 8 and y - 1 > 8 then
yOff = yOff + 1
end
end
if dir == 3 and x > 1 then
turtle.forward()
x = x - 1
if x > 24 and x + 1 > 24 and x < 66 and x + 1 < 66 then
xOff = xOff - 1
end
end
end
local stringmat = {}
stringmat[1] = tostring(xOff)
stringmat[2] = tostring(yOff)
stringmat[3] = tostring(x)
stringmat[4] = tostring(y)
for i = 1,4 do
local stringeval = stringmat
if stringeval:len() == 1 then
stringmat = table.concat({"0",stringeval},"")
end
end
rednet.send(ID, table.concat({"2",stringmat[1],stringmat[2],stringmat[3],stringmat[4]},""))
Scan()
end

function Parse(s)
if s:sub(1,1) == "0" then SetDir(tonumber(s:sub(2,2))) end
if s:sub(1,1) == "2" then Dig() end
if s:sub(1,1) == "3" then FullScan() end
if s:sub(1,1) == "4" then Place() end
if s:sub(1,1) == "1" then Forward() end
end

rednet.open("right")
repeat
local event,p1,p2
event,p1,p2 = os.pullEvent()
if event == "rednet_message" then
Parse(p2)
rednet.send(ID, "1")
end
until event == "key" and p1 == 25
rednet.close("left")


Spoilerprint("ID?")
ID = tonumber(read())

map = {}
for i=1,90 do
map = {}
for j=1,90 do
map[j] = 3
end
end

xOff = 20
yOff = 36
x = 45
prevX = 45
y = 45
prevY = 45
playerChar = 94
Ready = true

function ScreenUpdate(x, y)
term.clear()
for xa = 1,50 do
for ya = 1,18 do
mapXY = map[xa + x][ya + y]
if mapXY == 0 then
term.setCursorPos(xa,ya)
term.write("#")
end
if mapXY == 1 then
term.setCursorPos(xa,ya)
term.write(string.char(playerChar))
end
if mapXY == 2 then
term.setCursorPos(xa,ya)
term.write("-")
end
end
end
for xa = 46,50 do
for ya = 15,18 do
term.setCursorPos(xa,ya)
if Ready == true then
term.write("!")
else
term.write(" ")
end
end
end
end

function matrixUpdate()
map[prevX][prevY] = 2
map[x][y] = 1
prevX = x
prevY = y
end


function parse(s)
if s:sub(1,1) == "0" then
map[tonumber(s:sub(2,3))][tonumber(s:sub(4,5))] = tonumber(s:sub(6,6))
end

if s:sub(1,1) == "1" then
Ready = true
ScreenUpdate(xOff,yOff)
end

if s:sub(1,1) == "2" then
xOff = tonumber(s:sub(2,3))
yOff = tonumber(s:sub(4,5))
x = tonumber(s:sub(6,7))
y = tonumber(s:sub(8,9))
matrixUpdate()
end
end

rednet.open("back")
term.setCursorBlink(false)
matrixUpdate()
ScreenUpdate(0,0)
repeat
local Event, key, key2 = os.pullEvent()
if Event == "rednet_message" then
parse(key2)
end

if Event == "key" and Ready == true then
if key == 17 then
if playerChar == 94 then
rednet.send(ID, "1")
else
rednet.send(ID, "00")
playerChar = 94
end
Ready = false
end
if key == 30 then
if playerChar == 60 then
rednet.send(ID, "1")
else
rednet.send(ID, "03")
playerChar = 60
end
Ready = false
end
if key == 31 then
if playerChar == 118 then
rednet.send(ID, "1")
else
rednet.send(ID, "02")
playerChar = 118
end
Ready = false
end
if key == 32 then
if playerChar == 62 then
rednet.send(ID, "1")
else
rednet.send(ID, "01")
playerChar = 62
end
Ready = false
end
if key == 57 then
rednet.send(ID, "2")
Ready = false
end
if key == 18 then
rednet.send(ID, "3")
Ready = false
end
if key == 16 then
rednet.send(ID, "4")
Ready = false
end
ScreenUpdate(xOff, yOff)
end
until Event == "key" and key == 25
term.clear()
rednet.close("back")



And my versions (mostly an attempt to clarify exactly what's going on), turtle and terminal respectively. I've added three new functions and appended/changed the keymap a little, but beyond that, I've tried to leave everything essentially the same, just easier to read. Note that my variable names may not be entirely appropriate; I'm still figuring this program out:

Spoilerprint("### Connecting to Stonelike. ###")

ID = 0

currentXpos = 45
currentYpos = 45
xOffset = 20
yOffset = 36
directionFacing = 0
frontx = 0
fronty = 1

function Turn(s)
if s == "Right"
then
turtle.turnRight()
directionFacing = directionFacing + 1
if directionFacing > 3
then
directionFacing = 0
end
end

if s == "Left"
then
turtle.turnLeft()
directionFacing = directionFacing - 1
if directionFacing < 0
then
directionFacing = 3
end
end
Updatedif()
end

function Updatedif()
if directionFacing == 0
then
frontx = 0
fronty = -1
end
if directionFacing == 1
then
frontx = 1
fronty = 0
end
if directionFacing == 2
then
frontx = 0
fronty = 1
end
if directionFacing == 3
then
frontx = -1
fronty = 0
end
end

function Scan()
scannedx = tostring(currentXpos + frontx)
if scannedx:len() < 2
then
scannedx = table.concat({"0",scannedx},"")
end
scannedy = tostring(currentYpos + fronty)
if scannedy:len() < 2
then
scannedy = table.concat({"0",scannedy},"")
end
scan = turtle.detect()
if scan
then
rednet.send(ID, table.concat({"0",scannedx,scannedy,"0"},""))
end
if not scan
then rednet.send(ID, table.concat({"0",scannedx,scannedy,"2"},""))
end
end

function FullScan()
for i = 1,4 do
Scan()
Turn("Right")
end
end

function SetDirection(s)
while directionFacing ~= s do
Turn("Right")
end
end

function Dig()
turtle.dig()
os.sleep(0.40)
Scan()
end

function Place()
turtle.place()
Scan()
end

function Forward()
if not turtle.detect()
then
if directionFacing == 0 and currentYpos > 1
then
turtle.forward()
currentYpos = currentYpos - 1
if currentYpos > 8 and currentYpos + 1 > 8 and currentYpos < 82 and currentYpos + 1 < 82
then
yOffset = yOffset - 1
end
end
if directionFacing == 1 and currentXpos < 90
then
turtle.forward()
currentXpos = currentXpos + 1
if currentXpos < 66 and currentXpos - 1 < 66 and currentXpos > 24 and currentXpos - 1 > 24
then
xOffset = xOffset + 1
end
end
if directionFacing == 2 and currentXpos < 90
then
turtle.forward()
currentYpos = currentYpos + 1
if currentYpos < 82 and currentYpos - 1 < 82 and currentYpos > 8 and currentYpos - 1 > 8
then
yOffset = yOffset + 1
end
end
if directionFacing == 3 and currentXpos > 1
then
turtle.forward()
currentXpos = currentXpos - 1
if currentXpos > 24 and currentXpos + 1 > 24 and currentXpos < 66 and currentXpos + 1 < 66
then
xOffset = xOffset - 1
end
end
end
local stringMatrix = {}
stringMatrix[1] = tostring(xOffset)
stringMatrix[2] = tostring(yOffset)
stringMatrix[3] = tostring(currentXpos)
stringMatrix[4] = tostring(currentYpos)
for i = 1,4 do
local stringeval = stringMatrix
if stringeval:len() == 1
then
stringMatrix = table.concat({"0",stringeval},"")
end
end
rednet.send(ID, table.concat({"2",stringMatrix[1],stringMatrix[2],stringMatrix[3],stringMatrix[4]},""))
Scan()
end

function Parse(s)

if s:sub(1,1) == "0"
then
SetDirection(tonumber(s:sub(2,2)))
end

if s:sub(1,1) == "2"
then
Dig()
end

if s:sub(1,1) == "3"
then
FullScan()
end

if s:sub(1,1) == "4"
then
Place()
end

if s:sub(1,1) == "1"
then
Forward()
end

if s:sub(1,1) == "5"
then
Ascend()
end

if s:sub(1,1) == "6"
then
Decend()
end

if s:sub(1,1) == "7"
then
DropInventory()
end

end


function Ascend()
turtle.up()
Scan()
end

function Descend()
turtle.down()
Scan()
end

function DropInventory()
turtle.drop(1)
turtle.drop(2)
turtle.drop(3)
turtle.drop(4)
turtle.drop(5)
turtle.drop(6)
turtle.drop(7)
turtle.drop(8)
turtle.drop(9)
Scan()
end



rednet.open("right")
repeat
local event,p1,p2
event,p1,p2 = os.pullEvent()
if event == "rednet_message"
then
Parse(p2)
rednet.send(ID, "1")
end
until event == "key" and p1 == 25
rednet.close("left")


Spoilerprint("### WifiMiner Exploration Mapper Active ###")
print("NOTE: Wireless module must be on RIGHT SIDE.")
print("REMEMBER: Controls are relative to the terminal map view, NOT the turtle itself.")
print("+++ CONTROLS +++")
print("W - turn/move forward")
print("S - turn/move down")
print("A - turn/move left")
print("D - turn/move right")
print("Spacebar - ascend")
print("Left shift - descend")
print("E - scan around turtle")
print("Q - lay/place block")
print("P - clear inventory")
print("M - mine block")

print("Now, which turtle ID number will you use? Enter a number.")
ID = tonumber(read())

terrainMap = {}
for i=1,90 do
terrainMap = {}
for j=1,90 do
terrainMap[j] = 3
end
end

xOffset = 20
yOffset = 36
currentXpos = 45
previousXpos = 45
currentYpos = 45
previousYpos = 45
turtleMapcursor = 94
turtleReady = true

function ScreenUpdate(currentXpos, currentYpos)
term.clear()
for xAction = 1,50 do
for yAction = 1,18 do
terrainMapXY = terrainMap[xAction + currentXpos][yAction + currentYpos]

if terrainMapXY == 0 then
term.setCursorPos(xAction,yAction)
term.write("#")
end

if terrainMapXY == 1
then
term.setCursorPos(xAction,yAction)
term.write(string.char(turtleMapcursor))
end

if terrainMapXY == 2
then
term.setCursorPos(xAction,yAction)
term.write("-")
end

end

end

for xAction = 46,50 do
for yAction = 15,18 do
term.setCursorPos(xAction,yAction)
if turtleReady == true
then
term.write("!")
else
term.write(" ")
end
end
end
end

function MatrixUpdate()
terrainMap[previousXpos][previousYpos] = 2
terrainMap[currentXpos][currentYpos] = 1
previousXpos = currentXpos
previousYpos = currentYpos
end


function Parse(s)
if s:sub(1,1) == "0"
then
terrainMap[tonumber(s:sub(2,3))][tonumber(s:sub(4,5))] = tonumber(s:sub(6,6))
end

if s:sub(1,1) == "1"
then
turtleReady = true
ScreenUpdate(xOffset,yOffset)
end

if s:sub(1,1) == "2"
then
xOffset = tonumber(s:sub(2,3))
yOffset = tonumber(s:sub(4,5))
currentXpos = tonumber(s:sub(6,7))
currentYpos = tonumber(s:sub(8,9))
MatrixUpdate()
end
end

rednet.open("right")
term.setCursorBlink(false)
MatrixUpdate()
ScreenUpdate(0,0)
repeat
local Event, key, key2 = os.pullEvent()
if Event == "rednet_message" then
Parse(key2)
end

if Event == "key" and turtleReady == true
then

if key == 17 or key == "W"
then
if turtleMapcursor == 94
then
rednet.send(ID, "1")
else
rednet.send(ID, "0")
turtleMapcursor = 94
end
turtleReady = false
end

if key == 30 or key == "A"
then
if turtleMapcursor == 60
then
rednet.send(ID, "1")
else
rednet.send(ID, "3")
turtleMapcursor = 60
end
turtleReady = false
end

if key == 31 or key == "S"
then
if turtleMapcursor == 118
then
rednet.send(ID, "1")
else
rednet.send(ID, "2")
turtleMapcursor = 118
end
turtleReady = false
end

if key == 32 or key == "D"
then
if turtleMapcursor == 62
then
rednet.send(ID, "1")
else
rednet.send(ID, "1")
turtleMapcursor = 62
end
turtleReady = false
end

if key == 50 or key == "M"
then
rednet.send(ID, "2")
turtleReady = false
end

if key == 18 or key == "E"
then
rednet.send(ID, "3")
turtleReady = false
end

if key == 16 or key == "Q"
then
rednet.send(ID, "4")
turtleReady = false
end

if key == 57 or key == "SPACE"
then
rednet.send(ID, "5")
term.clear()
turtleReady = false
end

if key == 42 or key == "LEFTSHIFT"
then
rednet.send(ID, "6")
term.clear()
turtleReady = false
end

if key == 25 or key == "P"
then
rednet.send(ID, "7")
turtleReady = false
end



ScreenUpdate(xOffset, yOffset)
end

until Event == "key" and key == 21
term.clear()
print("### WifiMiner Exploration Mapper Closing ###")
rednet.close("right")



Any suggestions are welcome.
libraryaddict #2
Posted 25 April 2012 - 08:17 AM
You can use spoilers :)/>/>
Spoilers will turn off the headache of spam
skyeyemachine #3
Posted 25 April 2012 - 09:03 AM
Ah, sorry, will do so next time. Can't seem to edit my first post.
skyeyemachine #4
Posted 25 April 2012 - 01:36 PM
Oh, I should mention for anyone who tests; it came with no instructions, so I had to figure it out myself, but the "ID" at the start of each program is the computer ID for the other machine in the pair (so on the computer, you enter the turtle ID, and on the turtle, the computer ID). Maybe that's obvious to more experienced coders, but I wasn't sure what it wanted at first.
skyeyemachine #5
Posted 25 April 2012 - 08:58 PM
Incidentally, since the map it generates is 2D, I added a simple hack for vertical movement; the map is cleared upon an attempt to move upwards or downwards. If anyone has any suggestion for how I might make a multiple-level map, with the display cycling through each layer of terrain as it moves up and down, please let me know, as that would be much more ideal.
OmegaVest #6
Posted 25 April 2012 - 11:29 PM
First: put code tags inside the spoiler, please. +1 for spoiler-tagging, though.
Second, have the maps generate/save on multiple files. Each map would be in a folder ("maps"..turtleNum), within would be a bunch of levels. To call each, know your depth/height, then call like so:
Spoiler

map[height] = file.read("maps"..turtleNum, "y"..height)
--Display code

It's a horrible way to do so, but would probably help in the long run. And, hopefully this will help a bit.