In Chapter 6, we programmed a turtle to chop down a tree, but the player still has to manually place the turtle in front of a tree before the program can run. Placing a turtle in front of each tree you want to chop down isn’t much more efficient than harvesting a tree yourself. We can remove this manual step and fully automate the lumber-milling process by also programming the turtle to plant and grow saplings. As a result, the turtle can plant a sapling, harvest it when it becomes a tree, then plant a new sapling, and repeat the process without any human intervention! To do this, we’ll write a program called farmtrees. You can set up multiple turtles to grow trees, as shown in Figure 8-1.
Figure 8-1: An automated tree farm tended by turtles, with each turtle running the farmtrees program
We’ll reuse code we’ve already written in the hare module (Chapter 7) and choptree program (Chapter 6) to harvest the wood, so there’s no need to rewrite all that code!
Instead of moving the turtle to each tree, we’ll set up the turtle to stay in one place. The turtle will plant and grow saplings using bone meal to speed up the sapling’s growth. Then, once the sapling has grown into a tree, the turtle will harvest it and place the harvested wood into a chest behind the turtle.
Here are the steps of the tree-farming program in detail:
Check to make sure the hare module and choptree program exist.
Select tree saplings in the turtle’s inventory. Quit the program if it doesn’t have any.
Plant the sapling.
Repeatedly use bone meal on the planted sapling until it grows.
Run the choptree program.
Place the harvested wood in a chest behind the turtle.
Repeat the entire process.
The turtle will repeat the process until it runs out of tree saplings or bone meal. Now that we know what the code should do, let’s write the program.
Run the text editor by entering edit farmtrees 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.
farmtrees
1. --[[Tree Farming program by Al Sweigart
2. Plants tree then cuts it down.]]
3.
4. os.loadAPI('hare') -- load the hare module
5.
6. local blockExists, item
7. local logCount = 0
8.
9. -- check if choptree program exists
10. if not fs.exists('choptree') then
11. error('You must install choptree program first.')
12. end
13.
14. while true do
15. -- check inventory for saplings
16. if not hare.selectItem('minecraft:sapling') then
17. error('Out of saplings.')
18. end
19.
20. print('Planting...')
21. turtle.place() -- plant sapling
22.
23. -- loop until a tree has grown
24. while true do
25. blockExists, item = turtle.inspect()
26. if blockExists and item['name'] == 'minecraft:sapling' then
27. -- "dye" is the name ID for bone meal
28. if not hare.selectItem('minecraft:dye') then
29. error('Out of bone meal.')
30. end
31.
32. print('Using bone meal...')
33. turtle.place() -- use bone meal
34. else
35. break -- tree has grown
36. end
37. end
38.
39. hare.selectEmptySlot()
40. shell.run('choptree') -- run choptree
41.
42. -- move to and face chest
43. turtle.back()
44. turtle.turnLeft()
45. turtle.turnLeft()
46.
47. -- put logs into chest
48. while hare.selectItem('minecraft:log') do
49. logCount = logCount + turtle.getItemCount()
50. print('Total logs: ' .. logCount)
51. turtle.drop()
52. end
53.
54. -- face planting spot
55. turtle.turnLeft()
56. turtle.turnLeft()
57. end
After you’ve entered all of the code, press the CTRL key, make sure [Save] is selected, and press ENTER. Then quit the editor by pressing CTRL, selecting [Exit], and then pressing ENTER.
Before you run the farmtrees program, you need do some setup. First, ensure that a chest is directly behind the turtle and that saplings and bone meal are in the turtle’s inventory, as shown in Figure 8-2.
Figure 8-2: Place a chest behind the turtle and put saplings and bone meal in the turtle’s inventory.
You can craft bone meal from the bones dropped when you defeat skeletons. Use the recipe shown in Figure 8-3 to craft bone meal.
Figure 8-3: Crafting three bone meal from one bone
Second, make sure you’ve left one inventory slot empty to store the wood that the turtle will harvest.
When you’re finished with all the preparations for the program, run farmtrees. You should see the turtle plant a tree sapling and then chop down the sapling once it grows into a tree. Next, the turtle will return to the ground and face the chest to drop off the wood it collected. Then the turtle will turn around to face its original direction and repeat the process.
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 farmtrees and then download it by running pastebin get v5h8AgGs farmtrees.
Although Minecraft has many different types of trees, each with their own kind of sapling, certain trees are better to use in farmtrees than others because the turtle will harvest one column of a tree, moving straight up. If a tree branches out, the turtle will stop harvesting very quickly because it won’t follow the tree’s curve. Therefore, the best trees to use have tall, narrow trunks like the oak, spruce, birch, and jungle trees shown in Figure 8-4. Acacia trees branch out too much to be useful, and dark oak trees require planting saplings in a 2 × 2 area, which means they take up a lot of room.
Figure 8-4: From left to right: oak, spruce, birch, and jungle trees
When we call hare.selectItem() on line 16, all the saplings will have the name 'minecraft:sapling', so when you put saplings into the turtle’s inventory for it to farm, be sure they are oak, spruce, birch, or jungle saplings.
For the farmtrees program, you don’t need to supervise the turtle while it’s harvesting trees, but you shouldn’t wander too far from the turtle because of how the Minecraft world works. Minecraft’s world is effectively infinite because it generates parts of the world as you move into areas. However, because it would take too much of the computer’s memory to load the entire world all the time, Minecraft loads only the areas near the player. In Minecraft, the map is divided into 16-block by 16-block areas called chunks that load from the bottom to the top of the game world. As the player moves toward other chunks, the chunks are loaded into the computer’s memory from the hard drive and the chunks farthest from the player are unloaded.
Chunks are important to turtle programming because turtles will shut down if the chunk they’re in unloads itself. For example, on my computer, turtles shut down if I’m about 400 to 450 blocks away from them. Also, if your Render Distance option (found under Options ▸ Video Settings) is set to a lower number, the turtles will unload much sooner. If you set up several tree-farming turtles and move somewhere far away to mine, they might stop working. It’s best to keep turtles nearby while their programs are running and to fit as many as you can into a small area.
Now that you know all the details on how to use the farmtrees program, let’s look at each part of its code.
After the comments that describe the program in lines 1 and 2, line 4 loads the hare module that you created in Chapter 7.
farmtrees
1. --[[Tree Farming program by Al Sweigart
2. Plants tree then cuts it down.]]
3.
4. os.loadAPI('hare') -- load the hare module
5.
6. local blockExists, item
7. local logCount = 0
To allow the program to call the hare.selectEmptySlot() and hare.selectItem() functions, which were explained in Chapter 7, your program must first call the os.loadAPI() function and pass the string 'hare' to load the hare module.
Lines 6 and 7 declare variables that the program will use to make them easy to find. The blockExists and item variables store values later in the program when the turtle checks whether the sapling it planted has grown into a tree. The logCount variable keeps track of how many wooden log blocks the turtle has harvested, which is 0 when the program runs for the first time.
Before the program starts farming trees, it checks that the choptree program exists on the turtle. Otherwise, you’ll get an error when the turtle tries to run the farmtrees program.
farmtrees
9. -- check if choptree program exists
10. if not fs.exists('choptree') then
11. error('You must install choptree program first.')
12. end
You can check for the existence of the choptree program using the fs.exists() function, which takes a filename and returns true if a file with that name exists and false if it does not. If the choptree program doesn’t exist, line 11 terminates the program and displays the error message You must install choptree program first.
Line 14 begins the program’s while loop, which plants saplings and harvests wood. Every time the program finishes harvesting the wood from the tree it planted, it loops back to line 14 to repeat the process. Because the while loop’s condition is always true, it is an infinite loop that doesn’t stop until the program terminates with an error() call or break statement (which I explain in “Breaking Out of Loops with break Statements” on page 94).
Inside the while loop, the program first checks the turtle’s inventory for saplings.
farmtrees
14. while true do
15. -- check inventory for saplings
16. if not hare.selectItem('minecraft:sapling') then
17. error('Out of saplings.')
18. end
Line 16 uses the hare module’s selectItem() function to select an inventory slot that contains a tree sapling. If no saplings are in the turtle’s inventory, this function returns false. In that case, line 17 terminates the program by calling error() and displaying the error message Out of saplings.
If the execution passes the sapling check, line 20 displays a status update that the turtle is about to plant a sapling. Line 21 calls the turtle.place() function to do the planting.
farmtrees
20. print('Planting...')
21. turtle.place() -- plant sapling
The turtle.place() function places the block in the current slot in front of the turtle. This function works for saplings as well as planks, stone bricks, or any other block that the player can place in the world. Recall that line 16 selected the inventory slot with saplings, so the turtle.place() function places a sapling. Figure 8-5 shows the sapling after it has been planted in front of the turtle.
Figure 8-5: A sapling planted by the turtle
NOTE
In situations where you might need them, you can also use the turtle.placeUp() and turtle.placeDown() functions to place blocks above and below the turtle. These functions return true if the placement is successful. If a block is already there or something else prevents the placement of the block, these functions return false.
After planting the sapling, the execution enters another while loop that is inside the while loop on line 14. This inner while loop begins on line 24. Inside this loop, the program inspects the block in front of the turtle using the turtle.inspect() function, which is similar to turtle.detect() except turtle.detect() only returns true or false if a block is present, whereas turtle.inspect() returns a table value with details about what kind of block is in front of the turtle.
farmtrees
23. -- loop until a tree has grown
24. while true do
25. blockExists, item = turtle.inspect()
The turtle.inspect() function returns two values, which are stored in the blockExists and item variables that were declared at the start of the program. The first returned value (stored in blockExists) is a Boolean true if a block is in front of the turtle or false if no block is in front of the turtle. The second returned value (stored in item) is a table value with information about the block. If no block is in front of the turtle, this second returned value will be nil.
You can find the name of any item by running turtle.inspect() in the Lua shell while the block is in front of the turtle. For example, if a sapling is in front of a turtle and you run the command, you would see this:
lua> turtle.inspect()
true
{
state = {
type = "oak",
stage = 0,
},
name = "minecraft:sapling",
metadata = 0,
}
The if statement on line 26 checks that a block in front of the turtle exists and that it is a sapling. If it is, then lines 28 to 33 will repeatedly attempt to use bone meal on the sapling to speed its growth into a tree.
farmtrees
26. if blockExists and item['name'] == 'minecraft:sapling' then
27. -- "dye" is the name ID for bone meal
28. if not hare.selectItem('minecraft:dye') then
29. error('Out of bone meal.')
30. end
Line 28 checks the turtle’s inventory for bone meal. The name of bone meal items in Minecraft is 'minecraft:dye'. Similar to how the different tree saplings have the same 'minecraft:sapling' name, bone meal shares the name ID 'minecraft:dye' with other types of items.
If no bone meal is in the turtle’s inventory, then hare.selectItem('minecraft:dye') returns false and line 29 terminates the program with the error message Out of bone meal.
Otherwise, the execution continues to line 32, where the program prints a message to tell the user what the turtle is doing and then uses the bone meal on the sapling by placing it in front of the turtle.
farmtrees
32. print('Using bone meal...')
33. turtle.place() -- use bone meal
The execution skips the else statement on line 34 because the condition wasn’t false, and there are no further lines in the while loop. After using the bone meal, the execution loops back to line 24 where it repeats the check for a sapling in front of the turtle.
If the condition on line 26 is false, then there is no sapling detected in front of the turtle, and the execution moves to the block after the else statement on line 34. The sapling will be gone because it has grown into a tree and a wood block is now in front of the turtle. When line 35 runs, the break statement causes the execution to exit the while loop that started on line 24.
farmtrees
34. else
35. break -- tree has grown
36. end
37. end
The break statement consists of just the break keyword. A break statement causes the execution to immediately exit a loop and move past it without rechecking the while loop’s condition. The break statement on line 35 causes the execution to move to the first line outside the loop, which is line 39.
Line 36 ends the else statement’s code block, and line 37 ends the while statement’s code block.
The shell.run() function lets your program execute commands the same way you do at the command shell. The farmtrees program will use this function to run the choptree program.
farmtrees
39. hare.selectEmptySlot()
40. shell.run('choptree') -- run choptree
Line 39 calls the hare module’s selectEmptySlot() function to ensure that the wood blocks the turtle mines will go into an empty inventory slot. (Otherwise, the choptree program won’t work.) Then, line 40 runs the choptree program by calling shell.run() and passing the string 'choptree'.
The string passed to shell.run() is the same text you would enter into the command shell. Calling shell.run('choptree') in a program does the same thing as running the choptree program in the command shell.
This is how your program can run other programs. When the choptree program terminates, the execution will continue on from line 40.
At the end of the choptree program, the turtle will have descended to the ground where the sapling was originally planted. It then moves back one space to return to its original position and turns left twice to face the chest, ready to drop the wood.
farmtrees
42. -- move to and face chest
43. turtle.back()
44. turtle.turnLeft()
45. turtle.turnLeft()
The turtle.drop() function makes the turtle drop all the items in the current inventory slot into the chest that it’s facing (or on the ground if no chest has been added). If you pass a number to the turtle.drop() function, you can drop a certain number of items in the current slot instead of all of them. For example, the following Lua shell example will drop only one item:
lua> turtle.drop(1)
NOTE
In situations where you might need them, you can also use the turtle.dropUp() and turtle.dropDown() functions to drop items above and below the turtle instead of in front of it.
The while loop continues to select wood blocks as long as they exist in the turtle’s inventory. Inside the loop, the code keeps count of the number of logs as they’re dropped into the chest.
farmtrees
47. -- put logs into chest
48. while hare.selectItem('minecraft:log') do
49. logCount = logCount + turtle.getItemCount()
50. print('Total logs: ' .. logCount)
51. turtle.drop()
52. end
The hare.selectItem() function call on line 48 returns true as long as it can find an item with the name ID 'minecraft:log', meaning that the while loop will keep looping as long as wood blocks are in the turtle’s inventory. The turtle.getItemCount() call returns the number of logs in the current slot. This count is added to the number in logCount on line 49 to keep track of the total number of wood blocks the turtle places in the chest, and line 50 displays that total number. These logs are then dropped from the turtle’s inventory into the chest in front of the turtle using the turtle.drop() function call on line 51.
Lines 55 and 56 make the turtle turn left twice to return to its original position, facing the spot where it planted the sapling. Line 57 marks the end of the while loop that started on line 14, so the execution jumps back to line 14, ready to plant another sapling.
farmtrees
54. -- face planting spot
55. turtle.turnLeft()
56. turtle.turnLeft()
57. end
Recall that the while loop on line 14 is an infinite loop. The farmtrees program will terminate only if the error() calls on lines 17 or 29 are executed, and that happens if the turtle runs out of either saplings or bone meal, respectively. The player can also terminate the program by holding down CTRL-T. The player can refill the turtle’s inventory even while the program is running. As long as the player keeps the turtle stocked with saplings and bone meal, the program will continue to run forever.
As you increase your programming skills, you might think of ideas to improve your programs after they’re already written. You can rewrite your programs as much as you like. For example, you might have noticed that the turtles will go through your supply of bone meal faster than you can slay skeletons. Robots don’t get bored, so you can reprogram your patient turtle to wait for the tree to grow naturally instead of using bone meal.
Currently, the turtles are programmed to quit if no bone meal is in their inventory. To reprogram them to wait for the sapling to grow into a tree when they run out of bone meal, change line 29 from error('Out of bone meal.') to this:
farmtrees
29. os.sleep(10)
The os.sleep() function pauses the program for the number of seconds you pass it. The revised version of line 29 has the turtle sleep for 10 seconds before continuing with the rest of the program. This pause makes the turtle check every 10 seconds to see whether the sapling has grown into a tree.
Another benefit of using os.sleep() instead of just constantly looping is that when os.sleep() is called, Minecraft can stop running the turtle’s code and then resume running the code at the end of the pause. Pausing program execution can prevent lag, especially if several turtles are running programs.
The true power of the farmtrees program is that the program can scale as you add more turtles. If you add 10 turtles, wood production will increase accordingly. This wood is not only useful as building material—it can also be burned in a furnace to turn it into charcoal. Charcoal can be used like coal to fuel turtles, which means these turtles won’t need humans to find fuel for them. Better hope they don’t rebel!
In this chapter, you learned about the different types of trees in Minecraft. You learned about chunks and how turtles will only continue to run as long as they exist in a loaded chunk in the Minecraft world.
You also learned some additional turtle functions. The fs.exists() function will check if a program exists on the turtle. In farmtrees, the turtle.place() function placed saplings on the ground, but you can also use it to place any kind of block in front of the turtle. The turtle.inspect() function lets the turtle see what block is in front of it. The turtle.drop() function drops items, including into chests. The shell.run() function lets the farmtrees program run other programs, such as the choptree program.
The break statement causes the execution of a program to immediately jump out of a while or for loop. And the os.sleep() function lets you pause your program for a certain number of seconds.
In Chapter 9, we’ll expand our automated production to create cobblestone and stone bricks. This stone brick factory will create all the building blocks we need without ever stepping foot into a mine!