Part 2 is here: Tutorial Part 2
Part 3 is here: Tutorial Part 3
It assumes you are already familiar with the turtle api. You already know how to get the turtle to dig using:
turtle.dig()
If not you will need to read the excellent tutorials on this forum before you continue.So you all know the competition rules: place an empty crafty mining turtle in front of a tree, with no fuel, and get it to reproduce itself.
Easy!
There is just one line of code in the script:
main()
You will find it at the bottom of the script, around line no 11,567. That's it!But surely, I hear you say, the first line of code should be:
turtle.dig()
Using that, you dig the bottom log of the tree, then use
turtle.refuel()
That will eat the log and you are good to go…Well…Yes…and no…. We will get back to turtle.dig() a bit later. Well a lot later. Lets continue:
OK so there are 11566 other lines containing functions, classes and objects, but those are all ignored until they are called. So let's have a look at the function main() which is the last function in the script. The rest are all in alphabetical order so it is easier to find the one you are looking for, with the exception of initialise(), which is the first function, and debug(), which is last but one.
With a large project like this, it is important to organise it properly, otherwise the code gets very messy, things go wrong and are difficult to track. To help with organising I put all my functions first, in alphabetical order, and then use a function called main() which runs everything. This is a method developed before Lua was born, and still works well. As functions need to be declared before they are used, it makes sense to put main() at the bottom of the script. Let's have a look at main(). Hopefully we will find our first line - turtle.dig() within main()
function main()
initialise() -- Setup global variables
--deBug("logFile") -- uncomment for debugging and starting at different stages
getCoords() -- Get input from player
firstTree() -- Harvests first tree, fuels, makes a chest
findCobble() -- Dig down far enough to find cobble
checkGravel() -- If gravel found, test to make sure
confirmCobble() -- Suspected cobble found so confirm, and place furnace
clearBase() -- Clear area around first tree 4X4
--deBug("AllTrees") -- uncomment for debugging and starting at different stages
harvestAllTrees() -- Harvest trees in 32 x 32 area until enough resources found for deep mining
prepareMining() -- Enough resources found to go diamond mining. Prepare mining area.
mineForDiamonds() -- Mining area prepared. Mine 3 layers, then to bedrock until min 6 diamonds found
craftMiningTurtle() -- All resources mined. Build new turtle(s) if minimum 3 diamonds found
end
You will notice there are 11 functions in main(), which do all the work. There are two commented out, which were used during debugging, so the script could be re-started at different stages.So already you can see a structure to the program, it has a function called main(), whose sole purpose is to consecutively call 11 other functions. As you have probably already guessed, each of these 11 calls further functions as and when needed. Disappointingly turtle.dig() does not yet appear!
The first one is initialise(), so lets have a look at that one:
function initialise()
-- create classes/objects
createCoordObject()
createFurnaceObject()
createChestObject()
createSlotObject()
createLogfileObject()
createTreeFarmObject()
createDigObject()
createPlaceStorageObject()
--Edit out other stuff here
end
Still no sign of turtle.dig()!
So let's look at one of the functions in this lot: creatSlotObject()
Wait, I hear you say, objects is getting nerdy. All I want to do is turtle.dig() Right?
Well don't let objects frighten you. You are already using them.
turtle is an object, and .dig() is something that object can do: It is a method of the turtle object
Before discovering Computercraft, I always used to think of an object as a black box filled with gears and levers, with buttons on the outside to make it do things, tools on the opposite side controlled by the buttons. On another side of the box are labels, meters and gauges tell you what is going on inside the box, and a hole in the top you can drop instructions in if you wanted to change what the labels and meters are displaying. It would also be touch-sensitive, and have various gadgets, to see, hear, or otherwise detect what is going on around it. It would be able to respond to events such as phone calls, knocking on the outside of the box etc.
Then along came Computercraft and turtles, and the object appears as a grey box, with tools on its side, can tell you how much fuel it has, responds to right-clicking on it, or redstone signals etc….Uncanny
The buttons are invisible, but you can press them using code: turtle.dig() as an example
The labels and meters are also invisible, but you can read them with code:
turtle.getFuelLevel()
will give you the current fuel level. This is a Property of the turtle object. You can sometimes set the value of a property. eg . turtle.setFuelLevel(10000) would be great, equivalent to dropping a note into the top of the box telling it there is now 10000 fuel ready to use. Unfortunately this has not been put in place….You can of course get round this by being a bit sneaky. There is a back door on the turtle, which you open by right-clicking on it, and a monitor screen and shelf rack appears, consisting of 16 partitions grouped in a 4 x 4 grid. Right-Clicking on the turtle triggers an event, which displays the inventory and screen. So you have already been using methods, properties and events of an object. You are a fully qualified nerd already!
If you stick some wood into one of the shelves in the back of the turtle, you can then set the fuelLevel() property with a bit more code. Let's say you put a log into slot 16 (bottom right shelf)
turtle.select(16) -- a method
turtle.refuel() -- a method
The refuel() method will act internally by getting a small person inside to carry it away, so it disappears from the shelf, put it in the fuel tank, then write on the label on the outside to display the current level….1 log gives 15 units of fuel, so :
print(turtle.getFuelLevel())
will output 15 onto the screen, all this without you knowing what is going on inside the object.Now you are ready to make you own objects. Remember: a black box, tools and buttons(methods), eyes and ears (events), and a noticeboard(properties) For the purposes of this program, you will not need events, only properties and methods. Here we go with a very important one, the slot object:
function createSlotObject()
clsSlot = {}
clsSlot.__index = clsSlot
function clsSlot.new(self) --creates new instance of slot object
local self = setmetatable({}, clsSlot)
self.slotContains = {}
self.slotCount = {}
self.slotStatus = {}
self.index = 1
self.itemTested = {}
self.firstUnknownItem = ""
self.lastUnknownItem = ""
self.freeUnknownItem = "item1"
self.numUnknownItems = 0
-- initialise variables
for i = 1, 16 do
self.slotContains[i] = ""
self.slotCount[i] = 0
self.slotStatus[i] = "empty"
self.itemTested[i] = ""
end
return self
end
Other stuff here edited out
end
We do not need to go into the purpose of the first few lines in this tutorial, just accept it as part of the process of making a "class", which is a blueprint for creating objects. All this self. stuff and metatables makes my head spin.This function is used to create a new object. In nerdspeak we are creating "an instance of the class" Note the dot syntax clsSlot.new() . Any functions within this object to manipulate methods or properties should follow the same pattern. If this was a class to create turtles, it would create a new, empty turtle, with no fuel, which would work independently from any other turtles in the world. This time we are using it to create a slot object. If you look at the line at the end of the createSlotObject() function you will see:
slot = clsSlot.new()
This line is creating an object called slot by invoking the clsSlot.new() function. This is how it works:
Call the function:
clsSlot.new()
create the object:
local self = setmetatable({}, clsSlot)
Set the default properties of the object:
self.slotContains = {}
self.slotCount = {}
self.slotStatus = {}
self.index = 1
self.itemTested = {}
self.firstUnknownItem = ""
self.lastUnknownItem = ""
self.freeUnknownItem = "item1"
self.numUnknownItems = 0
for i = 1, 16 do
self.slotContains[i] = ""
self.slotCount[i] = 0
self.slotStatus[i] = "empty"
self.itemTested[i] = ""
end
Finally, and very important not to forget this line:
return self
This completes the creation of the object. Great, but why? What's the point?Think about what we are trying to do. As the turtle goes on its business, it digs blocks into its 16 slots, but it has no way of identifying what the blocks are. By using an object which keeps track of what is dug, where it is stored, and how much there is at any time, we are in full control of the turtle contents.
Now that was not too difficult was it? All that's left is to write some getters and setters, and a couple of methods while we are at it. To keep it simple we will just write a "getter". We already used one on the turtle:-
turtle.getItemCount()
Now let's write our own
function clsSlot.getSlotContains(self, slotNo)
return self.slotContains[slotNo]
end
This will return the contents of the slot requested as a string e.g. if the turtle had wood in slot 1
print(slot.getSlotContains(self, 1))
> "wood"
Luckily there is a shortcut, to avoid using self all over the place:
print(slot:getSlotContains(1))
> "wood"
Note the colon instead of dotThe other functions createXXXObject() all do similar things, but we will skip over them for the time being.
The remaining code in initialise() just sets up some global variables
-- set global variables. As each item is identified, set objectives["item"] = true
objectives = {}
local items = {}
items = {"wood","wood2","dirt","cobble","stone"}
for key, value in ipairs(items) do
objectives[value] = false
end
The table items = {"wood","wood2","dirt","cobble","stone"} has been edited to just 5 items for clarityWe want to set:
objectives["wood"] = false
objectives["wood2"] = false
objectives["dirt"] = false
objectives["cobble"] = false
objectives["stone"] = false
The loop for key, value in ipairs(items) do is a special type of for loop. It iterates the entire list of values stored in the table "items" which we set to {"wood","wood2","dirt","cobble","stone"}and sets objectives[value] = false, where value starts as "wood" and ends as "stone". It does the same as the 5 lines of code above, but in 3 lines. If we have 50 values stored in items{} it would take 50 lines of code
If we add more text to items{} in edit mode, the for loop creates new objectives[] to suit in run mode.
So that has got initialise() sorted
NOW can we get to turtle.dig()
Patience, please. We are nearly there. The next function in main() is getCoords()
This asks the player for coordinates, and whether a logFile should be produced. Getting the coordinates is very useful in the debugging process as the exact location where something goes wrong can be written to the logFile. Also the y coordinate is essential for the later stages of the program, when deep mining uses the depth of the turtle to excavate areas between 0 and 14 for diamonds.
If tutorials on player input, or writing logFiles are required, let me know with a reply to this post.
Now we can go to the function we have all been waiting for: firstTree()
Function firstTree(). At last we use turtle.dig()
function firstTree()
local quantity = 0
local tempyCoord = 0
local emptySlot = 0
local dugItem = ""
local dugSlot = 0
local success = false
local isJungle = false --check if next to a jungle tree
local isBranched = false
local numLogs = 0
local treeSide = ""
local sTime = os.time()
term.clear()
term.setCursorPos(1,1)
--break lower block of tree
saveToLog("firstTree: Chopping tree base", true)
dig.digNew{self = dig, expectedItem = "wood", callFrom = "firstTree"}
--craft to 4 planks in slot 2
saveToLog("firstTree: Crafting planks for fuel", true)
craft{craftItem = "planks", craftQuantity = 4, sourceItem1 = "wood", destSlot = 2, chest = "doNotUse", doSort = false}
--use all planks as fuel
turtle.select(slot:getItemSlot("planks"))
saveToLog("firstTree: "..turtle.getItemCount(2).." planks used for fuel", true)
turtle.refuel(turtle.getItemCount(2))
slot.update{self = slot, item = "planks", delete = true}
forward(1) --now under tree trunk - on level 0
other stuff here edited out
There it is:The 17th line down:
dig.digNew{self = dig, expectedItem = "wood", callFrom = "firstTree"}
WTF!!!
Where is turtle.dig()???
If anybody wants a continuation let me know by replying below……
Enjoy