It’s time to put your new programming knowledge to the test in the world of Minecraft. We’ll program our first turtle to chop down all the wood blocks of a tree. With the help of these turtles, your wood supply problems will be over!
Chopping trees by hand in Minecraft has many problems. It’s slow, it wears out your tools, and you need to reach the topmost wood block to completely chop down a tree. In comparison, turtles can harvest a wood block in one chop, their tools don’t wear out, and they can hover as high as you need them to, as shown in Figure 6-1.
Figure 6-1: Four turtles chopping a tall jungle tree
Before we can write our tree-chopping program, you need to learn some additional turtle functions and you need to think about how the program will work.
To chop down trees, you need to equip the turtle with a brand-new diamond tool. You can equip turtles with diamond pickaxes, shovels, axes, hoes, or swords, but an iron tool or a used diamond tool won’t work. Fortunately, a tool’s durability will never decrease once a turtle is equipped with it.
To equip a turtle with a tool, place the tool in the turtle’s currently selected inventory slot, or current slot. This is the inventory slot with the thick border around it. Craft a diamond pickaxe and place it in the turtle’s current slot. Run the Lua shell by entering the following:
> lua
Interactive Lua prompt.
Call exit() to exit.
Then, equip your turtle with the selected item by running this command:
lua> turtle.equipLeft()
Turtles can equip up to two tools: one on their left side and the other on their right. If you want to unequip a turtle, just call the turtle.equipLeft() or turtle.equipRight() function with nothing in the currently selected slot. The turtle will remove the tool and put it in its inventory.
Turtles can equip any diamond tool, but the diamond pickaxe is the most versatile. The diamond shovel can mine dirt blocks and the diamond axe can mine wood blocks, but neither can mine stone or ore blocks. The diamond pickaxe can mine all types of blocks, so we’ll use it for all the turtles in this book. With the pickaxe equipped, the turtle can call the turtle.dig() function, which I’ll explain in the next section, to mine blocks or chop wood.
Before we write code, let’s thoroughly think through what the lumberjack turtle needs to do. By planning ahead of time, you’ll spot mistakes in your program early instead of discovering them only after you’ve written it. As the old carpenter saying goes, “measure twice; cut once.” We will be planning the turtle’s tree-chopping algorithm. An algorithm is a series of steps for a computer to follow to solve a problem.
To chop down a tree, we’ll start the turtle at the base, dig, move forward, dig above the turtle, move up, and then repeat the last two steps for the whole tree. When the turtle is done, it will move back to the ground so it can be picked up. Figures 6-2 to 6-6 show this entire process.
Figure 6-2: The turtle starts at the bottom of the tree, facing the bottom wood block.
Figure 6-3: The turtle chops the bottom wood block, and then moves forward so it is under the tree.
Figure 6-4: The turtle chops upward, and then moves up one space.
Figure 6-5: The turtle keeps chopping up until there are no more wood blocks above it.
Figure 6-6: The turtle moves back down to the ground so the player can pick it up. The leaves will decompose.
We’ll need to use the turtle.forward() and turtle.up() functions to move the turtle. We’ll also use the turtle.dig() function, which makes the turtle dig (that is, mine) the block in front of it, as well as the turtle.digUp() function, which digs the block above the turtle.
Trees in Minecraft come in all sorts of heights, so the last thing you want to do is write a program that hardcodes the height of the tree the turtle can cut down. Hardcoding means to write a program with a limited, fixed solution. Hardcoded programs can’t handle different situations without the programmer rewriting the code. So you don’t want to write code like this:
turtle.digUp()
turtle.up()
turtle.digUp()
turtle.up()
turtle.digUp()
turtle.up()
turtle.digUp()
Although this program might be easy to understand, the turtle can only chop down trees that are exactly four blocks tall. If you want the turtle to chop down a different-sized tree, you’ll have to rewrite the code, which is not ideal.
Instead, let’s design an algorithm for chopping down trees of any size. For example, we can use these steps for the tree-chopping algorithm:
Start on the ground at the base of the tree, facing the tree.
Chop the bottom wood block in front of the turtle.
Move underneath the tree.
Chop wood blocks above the turtle, and move up after each chop until there is no more wood above.
Move down until the turtle is back on the ground.
Stop.
This algorithm allows the turtle to chop down trees of any height. Now it’ll be easy to harvest wood! You’ll implement this algorithm in the choptree program.
Run the text editor by entering edit choptree at the command shell. In the text editor, enter the following lines of code. Remember not to type the line numbers because they’re only used for reference.
choptree
1. --[[Tree Chopping program by Al Sweigart
2. Chops down the tree in front of turtle.]]
3.
4. if not turtle.detect() then
5. error('Could not find tree!')
6. end
7.
8. print('Chopping tree...')
9.
10. if not turtle.dig() then -- chop base of tree
11. error('Turtle needs a digging tool!')
12. end
13.
14. turtle.forward() -- move under tree
15. while turtle.compareUp() do
16. -- keep chopping until no more wood
17. turtle.digUp()
18. turtle.up()
19. end
20.
21. -- move back down to ground
22. while not turtle.detectDown() do
23. turtle.down()
24. end
25.
26. print('Done chopping tree.')
After you’ve entered all of these instructions, save the choptree program.
Use a pickaxe to mine the turtle and put it in your inventory. Find a tree in the Minecraft world, and place the turtle so it’s facing the bottommost wood block of the tree, as in Figure 6-7.
Figure 6-7: Place the turtle facing the bottommost wood block of a tree.
Right-click the turtle to open its GUI and make sure that the turtle has fuel and that its current slot is empty so the wood blocks it chops can go there. Then run the choptree program and watch it harvest all the wood from the tree. When the turtle is done harvesting the wood, it will come back to the ground, where you can mine it back into your inventory.
If you get errors when running this program, carefully compare your code to the code in this book to find any typos. If you still cannot fix your program, delete the file by running delete choptree and then download it by running pastebin get 8NgPXXxN choptree.
Let’s review the source code for the choptree program line by line. The turtle first needs to check whether a tree is in front of it.
choptree
1. --[[Tree Chopping program by Al Sweigart
2. Chops down the tree in front of turtle.]]
3.
4. if not turtle.detect() then
The turtle.detect() function returns true if something is in front of the turtle and false if there is empty air. The function also returns false if water or lava is in front of the turtle because the turtle can move through these kinds of blocks.
Just like there are turtle.digUp() and turtle.digDown() functions in ComputerCraft, the turtle.detectUp() and turtle.detectDown() functions can detect blocks above and below the turtle, respectively. Although the turtle.detect() function can detect whether a solid block is in front of the turtle, it can’t detect what kind of block it is. The program relies on the user to set up the turtle correctly in front of a tree.
The not in front of turtle.detect() on line 4 is a Boolean operator, which we will learn about next.
The not Boolean operator only operates on one Boolean value and works by evaluating an expression to the opposite value. So not true is false and not false is true. Enter the following into the Lua shell:
lua> not true
false
lua> not false
true
lua> myAge = 8
lua> not (myAge > 5)
false
You can use the not operator on Boolean values like not false or on expressions like not (myAge > 5), which evaluates as follows:
On line 4 of the choptree program, the not operator changes the Boolean value returned by turtle.detect() to its opposite. When there is no block in front of the turtle, turtle.detect() will return false and the not operator will evaluate this as true. The line if not turtle.detect() then can be read as “if the turtle does not detect a block, then run the code.” If any block is detected in front of the turtle, the execution enters the code block following the if statement.
There are two other Boolean operators, and and or. We won’t use them in the choptree program, but let’s take a look at how they work since they will be useful in other programs.
The and Boolean operator compares two Boolean values and evaluates to true if they are both true. If either value is false, the entire expression evaluates to false. Enter the following into the Lua shell:
lua> true and true
true
lua> true and false
false
lua> false and true
false
lua> false and false
false
The order of the values doesn’t affect what the expression evaluates to.
You can also use and with more complicated expressions, such as the following:
lua> 4 < 5 and 5 < 6
true
lua> myName = 'Al'
lua> theirName = 'Alice'
lua> myName == 'Al' and theirName == 'Bob'
false
The expression 4 < 5 and 5 < 6 evaluates like this:
Because both sides of the and operator are true, the expression evaluates to true.
But in myName == 'Al' and theirName == 'Bob', both sides don’t evaluate to true:
The or Boolean operator compares two Boolean values and evaluates to true if either is true. If both values are false, the entire expression evaluates to false. Enter the following into the Lua shell:
lua> true or true
true
lua> true or false
true
lua> false or true
true
lua> false or false
false
Unlike the and operator, only the last expression evaluates to false when using the or operator.
You can also use or with more complicated expressions, like so:
lua> 10 > 5 or 'Hello' == 'Hello'
true
lua> myName = 'Al'
lua> myAge = 8
lua> myName == 'Zophie' or myAge < 10
true
lua> myName == 'Zophie' or myAge ~= 8
false
The expression myName == 'Zophie' or myAge < 10 evaluates like this:
Even though one side of myName == 'Zophie' or myAge < 10 is false, the other side is true, so the entire expression evaluates to true. However, both sides of myName == 'Zophie' or myAge ~= 8 evaluate to false:
This is why myName == 'Zophie' or myAge ~= 8 evaluates to false.
Like the and operator, the or operator will work with expressions that use different data types.
The Boolean operators and, or, and not let you make more sophisticated conditions for your if, elseif, and while statements.
Let’s return to the choptree program. If nothing is in front of the turtle when the choptree program runs—that is, if not turtle.detect() on line 4 is true—the program should terminate with an error message. Normally, programs only terminate when they reach the end of the code. However, you can call the error() function with a string argument to terminate the program early and display an error message. When you call the error() function without passing a string argument, the program will simply stop without displaying an error message.
We want to show an error message if the turtle isn’t facing a block, so we use error() and pass it a string argument on line 5:
choptree
4. if not turtle.detect() then
5. error('Could not find tree!')
6. end
If no block is in front of the turtle, then the program stops and prints choptree:5:Could not find tree! to the turtle’s GUI. The choptree:5 part is added by Lua to say that line 5 of the choptree program had an error. As a result, the program will stop if there isn’t a wood block to chop down in front of the turtle.
If the not turtle.detect() condition on line 4 is false, that is, if the turtle does detect something in front of it, then error() won’t be called. Instead, the choptree program will chop the bottom block of the tree using turtle.dig() and then move the turtle under the tree. The wood block will appear in the current slot (or another slot if there are items already in the current slot). Lines 8 through 14 print a message telling the user the program has started, make the turtle chop, and then move the turtle under the tree.
choptree
8. print('Chopping tree...')
9.
10. if not turtle.dig() then -- chop base of tree
11. error('Turtle needs a digging tool!')
12. end
13.
14. turtle.forward() -- move under tree
Note that the turtle must have a pickaxe or else turtle.dig() won’t work and will return false. If this happens, the turtle won’t be able to chop down the tree. When the turtle.dig() function returns false, it makes the not turtle.dig() condition true, so line 11 will stop the program and display the error message choptree:11:Turtle needs a digging tool!.
In addition to turtle.dig(), the turtle.digUp() and turtle.digDown() functions will chop or mine the block above or below the turtle, respectively.
The turtle.compare() function compares the block that the turtle is facing with the block in the turtle’s current slot. If they’re the same, turtle.compare() returns true. If they’re different, turtle.compare() returns false. The turtle.compareUp() and turtle.compareDown() functions do the same thing, except they compare the block above or below the turtle, respectively.
Because the first part of the program chops the bottommost wood block before moving the turtle under the tree, there should be a wood block loaded in the turtle’s current slot. We need to check whether the block above the turtle is the same type as the block in its current slot, which is why it is important to make sure the current slot is empty before starting the program. We use turtle.compareUp() to do this. The function looks above the turtle instead of in front of it and returns true as long as there is a wood block above the turtle.
choptree
15. while turtle.compareUp() do
16. -- keep chopping until no more wood
17. turtle.digUp()
18. turtle.up()
19. end
The while loop that begins on line 15 uses the return value of turtle.compareUp() for its condition. As long as there is wood above the turtle, the program will keep executing the code in the while loop. Line 17 digs above the turtle and line 18 moves the turtle up. The loop only stops when turtle.compareUp() returns false, which happens when there is no wood above the turtle.
Note that in situations where you might need it, you can use the turtle.compareDown() function to compare the block under the turtle.
The program execution leaves the while loop when no more wood is above the turtle. When the turtle finishes chopping, it should return to the ground.
choptree
21. -- move back down to ground
22. while not turtle.detectDown() do
23. turtle.down()
24. end
25.
26. print('Done chopping tree.')
On line 22, we use a while loop to check not turtle.detectDown(). As long as the turtle doesn’t detect a block under it, the condition will return true and call turtle.down(). When the loop has ended and the turtle is back on the ground, the program prints Done chopping tree. to let the player know that it’s time to mine the turtle and pick it up (along with all the chopped wood).
We can make this program easier to use by running the choptree program as soon as the turtle is placed in front of a tree. Using a special startup program, we can make the program run whenever the turtle is placed and the GUI is first opened. We’ll create the startup program next.
Run the text editor by entering edit startup at the command shell. In the text editor, enter the following line of code:
startup
shell.run('choptree')
The shell.run() function will run the string you pass it as though you typed it at the command prompt. In this case, the turtle runs startup when you first open its GUI, and the startup program runs choptree so you don’t have to type choptree at the command prompt. The shell.run() function returns true if it ran the program and returns false if it couldn’t find the program or if the program stopped because error() was called.
The lumberjack turtle we programmed will speed up the rate that you can harvest wood. If you build multiple lumberjack turtles and load the choptree and startup programs on them, you can have many turtles chopping at once. Set one turtle at a tree, and then while it’s mining wood blocks, set another turtle at another tree, and so on. You’ll have a huge wood supply in no time!
You can then use the wood that these turtles chop to fuel your turtles. Be sure to craft four planks from each wood block first because wood and planks both provide 15 fuel units.
As big of a help as this lumberjack turtle can be, it still takes a lot of manual work to set it up at the base of each tree. In the next few chapters, you’ll learn how to reuse your code and how to make a tree farm by programming turtles to automatically grow and harvest trees.