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

[Lua] [Question] Need help with my quarry program.

Started by Willibilly19, 21 January 2013 - 05:58 AM
Willibilly19 #1
Posted 21 January 2013 - 06:58 AM
Hello everyone. I've recently started coding with this being only my 4th program. I'm starting to get into some of the more advanced stuff (for me anyway:P). I'm just having an issue with my program. What I'm trying to do is make an improved Quarry-esque program. A bunch of people on my server use the excavate program and It wastes fuel, so I took it upon myself to make something better for them because I needed a project for today:) My code is pasted below and here is also a link to my pastebin. http://pastebin.com/u/Willibilly19

What I have done is the turtle clearing a full layer without issues. It also takes care of mobs and gravel/sand. I'm just having issues with the end bit of code, making it go down a layer and start again…and when it's all done, coming back to the surface. I've tried a few things to get it to work, but I just can't figure it out. it never works like it should. Ignore the bit about refueling, I haven't implemented that yet. I added comments to my code to explain each function. Any help would be appreciated.





tArgs = {...}
if #tArgs ~= 1 then
 print("Usage: Quarry <size>")
end

print("To Use: ")
print("Place enderchest in slot 16.")
print("Place fuel in slot 15 or fuel beforehand.")

x = tArgs[1]
depth = 0
k = 0

--functions

function forward() -- Going forward, gravel and mob avoidance.
 while not turtle.forward() do
   turtle.dig()  
   turtle.attack()
 end
end 


function dig()     --To dig a full line.
 turtle.select(1)
 for i = 1,x-1 do
  while not turtle.forward() do
   turtle.dig()  
   turtle.attack()
   chest() 
  end
 end
end

function left()  --Turn left to start a new line. (even lines)
 turtle.turnLeft()
 forward()
 turtle.turnLeft()
end

function right()  --Turn right to start a new line. (odd lines)
 turtle.turnRight()
 forward()
 turtle.turnRight()
end

function spin()  --Spins (just a neater look to my code having a function)
 turtle.turnRight()
 turtle.turnRight()
end

function back()  --To take the turtle back to the starting square of the layer.
 spin()
 for i = 1,x-1 do
  forward()
 end
 turtle.turnRight()
 for i = 1,x-1 do
  forward()
 end
 turtle.turnRight()
end 

function layer()  --Digs one layer of land.
 for i = 1,x do
  dig()
  if i%x == 0 then
   if i%2 == 0 then
    turtle.turnRight()
    for i = 1,x-1 do
     forward()
    end
    turtle.turnRight()
   else
    back()
   end
  elseif i%2 == 1 then
   right()
  else
   left()
  end
 end
end

function chest()  --Empties inventory when full.
 if turtle.getItemCount(14) > 0 then
  turtle.digUp()
  turtle.select(16)
  turtle.placeUp()
  for i = 1,14 do
   turtle.select(i)
   turtle.dropUp()
  end
  turtle.select(16)
  turtle.digUp()
  turtle.select(1)
 end
end


function quarry()  --Needs to move the turtle down to start a new layer and up when done(WIP)
 depth = depth + 1
 if not turtle.down() then
  turtle.digDown()
  turtle.down()
  if not turtle.digDown() then
   for i = 1, depth do
    turtle.up()
    k = k + 1
   end
  end
 end
end


*Edit* Fixed some of the spacing in the code, so it looked better. The indenting messed up while copying.
*Edit* Realized the code I pasted wasn't the most updated. I'm having the same issues, but it's my current code now.
Willibilly19 #2
Posted 21 January 2013 - 08:32 AM
I've tried working on it a bit more. I attempted with adding 1 to depth each time it goes downa layer and subtracting 1 each time it comes up when it's not longer able to move or dig down. I don't know. I'm lost on this piece.
ChunLing #3
Posted 21 January 2013 - 02:34 PM
Um…currently you don't actually call any of these functions.

On function design, it would be nice if you made a hierarchy of functions (and kept them local). You also might want to use three digs/move by digging up and down each time so that you clear more with each motion. I find that when you use an if i%2 == 0 then … else … end works just as well as elseif i%2 == 1 then … end (if you are unsure whether the user will input an integer, then you can math.floor() the input).
Willibilly19 #4
Posted 21 January 2013 - 04:07 PM
I know it doesn't actually call any functions atm. I was testing each function individually, so I ended up deleting the end bit of code. (Should have commented it out now that I think about it.)

As I'm new to any sort of programming, what do you mean a hierarchy of functions?

I like your idea of digging up and down on each move, I'll try to implement that in just a little while.

I think the bit of code I had at the end was


repeat
  layer()
  quarry()
until k > 0 --since I had k = k+1 when it can no longer move down

the problem with that though is the turtle can't dig down on the bottom layer so it skips it and just moves up. The Quarry function and the executing code is what I need to work on, but I just cannot figure it out.
Willibilly19 #5
Posted 21 January 2013 - 04:16 PM
I have a feeling you just meant organizing the functions better, so I did it:P I had been meaning to do so anyway, I was just writing them as I needed them.
Here is a slightly more organized code, and I added in the bit at the end.



tArgs = {...}

if #tArgs ~= 1 then
print("Usage: Quarry <size>")
end

print("To Use: ")
print("Place enderchest in slot 16.")
print("Place fuel in slot 15 or fuel beforehand.")

x = tArgs[1]
depth = 0
k = 0

--movement functions


function forward() -- Going forward, gravel and mob avoidance.
while not turtle.forward() do
	turtle.dig()
	turtle.attack()
end
end


function left()  --Turn left to start a new line. (even lines)
turtle.turnLeft()
forward()
turtle.turnLeft()
end

function right()  --Turn right to start a new line. (odd lines)
turtle.turnRight()
forward()
turtle.turnRight()
end

function spin()  --Spins (just a neater look to my code having a function)
turtle.turnRight()
turtle.turnRight()
end

function back()  --To take the turtle back to the starting square of the layer.
spin()
for i = 1,x-1 do
   forward()
end
turtle.turnRight()
for i = 1,x-1 do
   forward()
end
turtle.turnRight()
end

--Inventory Management

function chest()  --Empties inventory when full.
if turtle.getItemCount(14) > 0 then
   turtle.digUp()
   turtle.select(16)
   turtle.placeUp()
   for i = 1,14 do
	turtle.select(i)
	turtle.dropUp()
   end
   turtle.select(16)
   turtle.digUp()
   turtle.select(1)
end
end

--Digging functions

function dig()	 --To dig a full line.
turtle.select(1)
for i = 1,x-1 do
   while not turtle.forward() do
	turtle.dig()
	turtle.attack()
	chest()
   end
end
end

function layer()  --Digs one layer of land.
for i = 1,x do
   dig()
   if i%x == 0 then
	if i%2 == 0 then
	 turtle.turnRight()
	 for i = 1,x-1 do
	  forward()
	 end
	turtle.turnRight()
	else
	back()
	end
  elseif i%2 == 1 then
   right()
  else
   left()
  end
end
end

function quarry()  --Needs to move the turtle down to start a new layer and up when done(WIP)
depth = depth + 1
if not turtle.down() then
  turtle.digDown()
  turtle.down()
  if not turtle.digDown() then
   for i = 1, depth do
	turtle.up()
	k = k + 1
   end
  end
end
end

--Actual bit of code
repeat
layer()
quarry()
until k > 0	--k stays 0 until it can no longer move down (WIP)


*Edit* fixed the indenting, it doesn't seem to like to keep it for some reason.
ChunLing #6
Posted 21 January 2013 - 10:24 PM
Well, to be perfectly clear, organizing your functions by dependency (which you have), but also being a bit more aggressive about creating layers by using more basic functions to build the more complex functions instead of having larger functions repeating code found in basic functions. Declaring them as local rather than global helps with the first part, since it means you'll throw an attempt to call nil error any time you don't define a function before defining another function that uses it. The second part is just looking to see where you've got code repetition.

If you close the code wizard window and paste directly between the code tags, indentation and stuff seems to go a bit smoother.

So, looking at your quarry function, you move down, digging if necessary, then attempt to move down again, and if that fails you return to the surface, incrementing k along the way. So what exactly do you want to happen instead? Should the turtle do one thing if depth has reached a certain value and another if it hasn't? Or do you want the turtle to come back up if it hits bedrock?
Willibilly19 #7
Posted 21 January 2013 - 10:36 PM
Well currently, when it hits bedrock, it comes back up without digging that layer, which causes loss of resources. I'm trying to make it as efficient as possible and plan on adding in the functionality to digUp and digDown, but I want to get it working before I change it too much. I need to rewrite the quarry() function to get it to dig each layer from the one it's on all the way to bedrock. I've tried a few variances of the code, but I can't get it to work correctly.

I'm probably over complicating things, as I do that a lot, which is why I posted it here to see if someone could give some fresh insight on how to make it work. I know it's probably a large task(for me anyway).


Also, I'm not sure how making the functions local would work. Something like this?



local function dig()
<code>
end

I think I understand how it could be beneficial, basically only allowing that function to be called if all the functions it uses are before it in my code? Ensuring that the code is well organized/has a hierarchy of functions? Seems like it is just something to make reading the code easier. Am I correct?
ChunLing #8
Posted 21 January 2013 - 11:21 PM
Organizing your functions this way is necessary to being able to easily declare/define them local (which works exactly as your sample posits), which is generally good practice for non-api functions. Thinking of them as a hierarchy helps you program with a minimum of repetitive code, which is useful and makes the program behavior easier to track/predict.

If you're going down to bedrock, then you will encounter a lot of gravel, and possibly mobs spawning. So you'll want to have more robust movement functions which can handle various conditions. Here's an excerpt from my turtle api:
dt = {slt = 1}
local mvfncs = {{turtle.forward,turtle.detect,turtle.dig,turtle.attack},
        {turtle.up,turtle.detectUp,turtle.digUp,turtle.attackUp},
        {turtle.down,turtle.detectDown,turtle.digDown,turtle.attackDown},}
function rply(mssgstr) -- e.g. "unbreakable block in path"
    print(mssgstr)
    if dt.rcID then rednet.send(dt.rcID,mssgstr) end
end
local function mvdgK(drctn) -- i.e.(1 = forward, 2 = up, 3 = down)
    local itr8 = 0
    while not mvfncs[drctn][1]() do
        if mvfncs[drctn][2]() then
            if not mvfncs[drctn][3]() then rply("unbreakable block in path") return false end
        elseif turtle.getFuelLevel() == 0 then rply("Out of fuel" ) return false
        else mvfncs[drctn][4]() end
        if itr8 > 64 then rply("persistent impediment") return false end
        itr8 = itr8+1
    end
    return true
end
--snip
tnl = function() turtle.digUp() turtle.digDown() return mvdgK(1) end
dfd = function() return mvdgK(1) end
dup = function() return mvdgK(2) end
ddn = function() return mvdgK(3) end
So, what I'm doing here is reusing the same basic code for three kinds of movement (and for three block tunnelling). The movement function, with the ability to respond to various types of impediments, is large enough to make that a significant savings in code length. I also have the advantage of knowing that the behavior of the final functions is consistent no matter which I'm using. Because this is an API, I make the final functions available globally, but that doesn't really change the order in which I've defined them.

If you use this kind of pattern to create your movemement functions (probably not the exact same code, since you want to have internal control, and these are clearly designed for remote control), then you can easily make it so that your function ends when, say, the general movement function sets a variable ("bedrock = true" rather than "rply("unbreakable block in path")").
Willibilly19 #9
Posted 21 January 2013 - 11:38 PM
Thanks a lot for your reply. I think I might place this code on hold for a while and try to work on a couple API's myself. I think that would be very beneficial to my learning :)/>
I really like how your code looks, and judging just by that, I have a lot to learn(I knew this already…and even though I understand what your code does, I'm not sure I could implement it all.)
ChunLing #10
Posted 22 January 2013 - 08:03 AM
I was just noticing that this is an older version of the API I use…interesting. Anyway, you don't need to go to this level of organization right away, it's mainly for illustrating how arranging functions in a hierarchy lets you create more reusable, consistent code that is optimized for the particular tasks you want.