8RUNNING AN AUTOMATED TREE FARM

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.

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!

DESIGNING A TREE-FARMING PROGRAM

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.

WRITING THE FARMTREES 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.

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.

RUNNING THE FARMTREES PROGRAM

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.

TREE TYPES IN MINECRAFT

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.

CHUNK LOADING IN MINECRAFT

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.

LOADING MODULES WITH THE OS.LOADAPI() FUNCTION

After the comments that describe the program in lines 1 and 2, line 4 loads the hare module that you created in Chapter 7.

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.

CHECKING FOR FILES WITH THE FS.EXISTS() FUNCTION

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 exists10. if not fs.exists('choptree') then11. 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.

SELECTING SAPLINGS IN THE TURTLE’S INVENTORY

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 do15. -- check inventory for saplings16. if not hare.selectItem('minecraft:sapling') then17. 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.

PLANTING A TREE

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 theturtle.placeUp()andturtle.placeDown()functions to place blocks above and below the turtle. These functions returntrueif the placement is successful. If a block is already there or something else prevents the placement of the block, these functions returnfalse.

INSPECTING BLOCKS AND WAITING FOR THE TREE TO GROW

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.

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:

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' then27. -- "dye" is the name ID for bone meal28. if not hare.selectItem('minecraft:dye') then29. 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.

BREAKING OUT OF LOOPS WITH BREAK STATEMENTS

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. else35. break -- tree has grown36. end37. 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.

RUNNING OTHER PROGRAMS WITH THE SHELL.RUN() FUNCTION

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.

HANDLING ITEMS WITH THE TURTLE’S DROP FUNCTIONS

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.

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 theturtle.dropUp()andturtle.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.

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.

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.

REWRITING YOUR CODE FOR WHEN YOU HAVE NO BONE MEAL

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.

BONUS ACTIVITY: LONE TURTLE FARMER

You don’t need one turtle per tree for your tree farm. You can set up several tree plots in a line, and then program one turtle to check on each tree every few minutes. Write a program that makes a turtle run the farmtrees program for several plots as in Figure 8-6.

You’ll need to modify the farmtrees program so that it only checks whether each tree has grown from a sapling once before moving on to the next plot, instead of checking one tree forever in a loop. This way, you can reuse the code in farmtrees but can create much larger farms.

Figure 8-6: A turtle tending a sapling in one of three plots

WHAT YOU LEARNED

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!