The most common blocks you’ll find as you mine are stone. They become cobblestone when mined, but you can turn them back into stone by smelting them in a furnace. Then you can craft this stone into stone bricks for your buildings’ construction materials.
Whew! That’s a lot of work in dangerous, dark mines just to get stone bricks. In this chapter, you’ll learn how to create a cobblestone generator that will give you infinite cobblestone to work with, and then you’ll create a turtle program to automatically mine and smelt that cobblestone into stone. Safe inside your base, you’ll have a production line for an endless amount of stone bricks to build with.
Although you can obtain cobblestone by mining it in Minecraft, you can also create it by mixing a stream of water with a stream of lava, which forms a cobblestone block. You can use this knowledge to build a cobblestone generator that performs the same process to create an unlimited number of cobblestone blocks. Turtles can mine this cobblestone forever because their tools don’t wear out.
To create a cobblestone generator, follow the blueprint in Figure 9-1. A generator has three layers of blocks. You’ll need one type of block to act as an enclosure for holding the water and lava streams. I used glass, but you can use any nonflammable blocks. You’ll need to use three iron ingots to craft a bucket, which you’ll then fill from a lava pool. Although you can find lava pools on the surface, they’re more commonly found deep underground near bedrock. You can draw water from the rivers, ponds, and oceans on the surface.
Figure 9-1: A bird’s-eye view of the blueprints for a cobblestone generator
When placing the lava and water, be sure to place the water first. Otherwise, the water stream will mix directly with the lava block (instead of the lava stream), turning it into obsidian. You don’t need to place the cobblestone block in the blueprint. It will form automatically.
Figure 9-2 shows the completed cobblestone generator.
Figure 9-2: The completed cobblestone generator with a turtle in the empty slot on the top layer
Whenever the cobblestone block in the generator is mined, it opens space for the lava to flow into to create a new cobblestone block. You could mine the cobblestone an infinite number of times, but you would wear out a lot of pickaxes. By placing a turtle in the open spot on the top layer facing the cobblestone block, you can have the turtle mine the cobblestone blocks forever. Because the turtle doesn’t even need to move, it doesn’t use any fuel either!
Even though we now have an infinite supply of cobblestone, we still need to smelt the cobblestone into stone to use it. To do this, we’ll create the cobminer program, which will make a turtle mine the cobblestone from the generator and then deposit the mined cobblestone into furnaces to smelt it into stone.
Before you create the cobminer program, you’ll need to do some setup. First, you need to extend the cobblestone generator by adding five furnaces to the middle layer behind the turtle, as shown in Figure 9-3.
The turtle running the new cobblestone miner program will mine until it has a full stack of 64 cobblestones. Then it will move backward over the furnaces, dropping the cobblestone into them. The furnaces will smelt the cobblestone into stone. If all the furnaces are full, the turtle will wait five minutes before trying to drop cobblestone into them again. This entire process will repeat forever.
Figure 9-3: Five furnaces added to the middle layer of the cobblestone generator (left) and the furnaces in the game (right)
In Chapter 10, we’ll create a brickcrafter program to run a second turtle. The brickcrafter program will pick up the smelted stone from the furnaces and use it to craft stone bricks. The turtle will store these stone brick blocks in a nearby chest for the player.
To write the cobminer program, run edit cobminer from the command shell and enter the following code:
cobminer
1. --[[Stone Brick Factory program by Al Sweigart
2. Mines cobblestone from a generator, turtle 1 of 2]]
3.
4. os.loadAPI('hare') -- load the hare module
5. local numToDrop
6. local NUM_FURNACES = 5
7.
8. print('Starting mining program...')
9. while true do
10. -- mine cobblestone
11. if turtle.detect() then
12. print('Cobblestone detected. Mining...')
13. turtle.dig() -- mine cobblestone
14. else
15. print('No cobblestone. Sleeping...')
16. os.sleep(0.5) -- half-second pause
17. end
18.
19. -- check for a full stack of cobblestone
20. hare.selectItem('minecraft:cobblestone')
21. if turtle.getItemCount() == 64 then
22. -- check turtle's fuel
23. if turtle.getFuelLevel() < (2 * NUM_FURNACES) then
24. error('Turtle needs more fuel!')
25. end
26.
27. -- put cobblestone in furnaces
28. print('Dropping off cobblestone...')
29. for furnacesToFill = NUM_FURNACES, 1, -1 do
30. turtle.back() -- move over furnace
31. numToDrop = math.floor(turtle.getItemCount() / furnacesToFill)
32. turtle.dropDown(numToDrop) -- put cobblestone in furnace
33. end
34.
35. -- move back to cobblestone generator
36. for moves = 1, NUM_FURNACES do
37. turtle.forward()
38. end
39.
40. if turtle.getItemCount() > 0 then
41. print('All furnaces full. Sleeping...')
42. os.sleep(300) -- wait for five minutes
43. end
44. end
45. end
After you’ve entered these instructions, press CTRL, make sure [Save] is selected, and press ENTER. Then quit the editor by pressing CTRL, selecting [Exit], and pressing ENTER. In addition, you’ll need the hare module, which you can download by running pastebin get wwzvaKuW hare.
After you’ve set up the cobblestone generator with five furnaces, position the turtle facing the cobblestone block and run cobminer. The turtle will begin to mine the cobblestone until it has 64 blocks; then it will drop them into the furnaces. Until you write the brickcrafter program in Chapter 10, you’ll have to manually load fuel into the furnaces and remove the smelted stone blocks from them. To create fuel for the furnaces, smelt the wood blocks from the tree-farming turtles in separate furnaces to produce charcoal for fueling the furnaces. Let’s look at each part of the cobminer program.
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 cobminer and then download it by running pastebin get YhvSiw7e cobminer.
The first couple of lines of the program contain the usual comment that describes what the program is.
cobminer
1. --[[Stone Brick Factory program by Al Sweigart
2. Mines cobblestone from a generator, turtle 1 of 2]]
3.
4. os.loadAPI('hare') -- load the hare module
5. local numToDrop
Line 4 loads the hare module so the program can call hare.selectItem(). Line 5 declares a variable called numToDrop, which is used later in the program.
Line 6 declares the NUM_FURNACES variable, which contains an integer that represents the number of furnaces that are placed behind the turtle.
cobminer
6. local NUM_FURNACES = 5
This program has five furnaces, but you can add more furnaces if you like. If you add more furnaces to your cobblestone generator, set the value of NUM_FURNACES to the new number of furnaces.
The NUM_FURNACES variable is uppercase because it’s a constant variable, which means its value never changes while the program is running. Uppercase names for constants are just a convention. Constants are still regular variables. The capitalized name helps remind you that you shouldn’t write code that changes the variable. It might seem odd to have a variable whose value never changes, but using constants will make your code easier to understand and will make future changes convenient.
For example, you need to indicate the number of furnaces in your code, but if you use the number instead of NUM_FURNACES throughout your code and then you later change the number of furnaces, you would have to update your code everywhere that number is used. When you use a constant like NUM_FURNACES, you can update your code by just changing the assignment statement, which in this case is on line 6. Constants make your code clear and easy to modify.
Line 9 begins the program’s main while loop, which contains the code to make the turtle mine cobblestone, move over the furnaces, and drop cobblestone into the furnaces.
cobminer
8. print('Starting mining program...')
9. while true do
10. -- mine cobblestone
11. if turtle.detect() then
12. print('Cobblestone detected. Mining...')
13. turtle.dig() -- mine cobblestone
The first part, mining cobblestone, begins on line 11. The turtle.detect() function returns true if a cobblestone block is in front of the turtle. In that case, the program displays Cobblestone detected. Mining... and the call turtle.dig() on line 13 mines the cobblestone.
However, if there is no cobblestone because it was previously mined (and the new cobblestone block hasn’t formed yet), turtle.detect() returns false. When the if statement’s condition is false, the block of code after the else statement on line 14 runs.
cobminer
14. else
15. print('No cobblestone. Sleeping...')
16. os.sleep(0.5) -- half-second pause
17. end
This code displays No cobblestone. Sleeping... and calls os.sleep(0.5) to pause the program for half a second so a new cobblestone block has enough time to form. This new cobblestone block will be mined when the program loops around again. When the turtle is done mining cobblestone, it needs to smelt the cobblestone in the furnaces.
Furnaces have three slots: a fuel slot where burnable items like coal power the furnace, an input slot for items to be smelted, and an output slot where the smelted items remain until the player takes them. The turtle’s position next to the furnace determines whether the turtle is putting an item into the furnace as fuel, putting an item in as a block to smelt, or removing the final product. If the turtle is on the side of the furnace, it can drop items into and take items from the furnace’s fuel slot. If a turtle is above a furnace, it can drop items into and take items from the furnace’s input slot. If a turtle is below a furnace, it can take smelted items from the furnace’s output slot. Figure 9-4 shows these positions.
Figure 9-4: The turtle’s position indicates which furnace slot it interacts with.
Next, the turtle will drop the cobblestone blocks into the furnaces.
After checking for a cobblestone block to mine, the program then checks whether the turtle has collected 64 cobblestone blocks, which is the maximum an inventory slot can hold. If so, the turtle is ready to drop them into the furnaces behind it after checking that it has enough fuel to travel across the furnaces and back to the cobblestone generator.
cobminer
19. -- check for a full stack of cobblestone
20. hare.selectItem('minecraft:cobblestone')
21. if turtle.getItemCount() == 64 then
22. -- check turtle's fuel
23. if turtle.getFuelLevel() < (2 * NUM_FURNACES) then
24. error('Turtle needs more fuel!')
25. end
The hare.selectItem() function on line 20 finds the inventory slot with cobblestone and selects the slot. Line 21 calls turtle.getItemCount() to check the number of cobblestone blocks in this slot. If the total is 64 cobblestone blocks, the program calls turtle.getFuelLevel() to check the turtle’s fuel level.
Line 23 checks whether the turtle’s fuel level is less than 2 * NUM_FURNACES. The reason is that the turtle needs enough fuel to move over each furnace and then move back across each furnace to return to its starting position, as shown in Figure 9-5.
Figure 9-5: The amount of fuel needed to move over the furnaces and back is twice the number of furnaces.
If the turtle doesn’t have enough fuel, line 24 calls error() and displays Turtle needs more fuel!. Then line 25 terminates the program.
When the turtle has 64 cobblestone blocks and enough fuel to travel across the furnaces and back, the turtle can move backward and drop off the cobblestone, like in Figure 9-6.
Figure 9-6: The turtle drops cobblestone blocks into the furnaces.
The for loop on line 29 is slightly different from for loops we’ve used before. A for loop can count up, as in for i = 1, 10 do, but it can also count in different increments when you include a third number, a step number, to the statement. Instead of adding 1 on each iteration, the for loop will add the number indicated in the step argument. If you use a negative number, as in for i = 10, 1, -1 do, you can make the loop count down.
cobminer
27. -- put cobblestone in furnaces
28. print('Dropping off cobblestone...')
29. for furnacesToFill = NUM_FURNACES, 1, -1 do
30. turtle.back() -- move over furnace
31. numToDrop = math.floor(turtle.getItemCount() / furnacesToFill)
32. turtle.dropDown(numToDrop) -- put cobblestone in furnace
33. end
The for loop on line 29 tells the turtle to move backward NUM_FURNACES (or five) times. However, it begins counting at 5 down to 1 instead of 1 up to 5, so we can use the for loop variable, furnacesToFill, on line 31 to calculate how many cobblestone blocks to drop into each furnace. This calculation uses the math.floor() function. Let’s look at how this function works.
The math.floor() function rounds down the number it’s passed and returns it, whereas the math.ceil() function (“ceil” as in “ceiling”) rounds up the number it’s passed and returns it. Enter the following into the Lua shell to see how these functions work.
lua> math.floor(4.2)
4
lua> math.floor(4.9)
4
lua> math.floor(10.5)
10
lua> math.floor(12.0)
12
lua> math.ceil(4.2)
5
lua> math.ceil(4.9)
5
lua> math.ceil(10.5)
11
➊ lua> math.ceil(12.0)
12
Passing a value to math.floor() results in the number without its decimal point, whereas passing a number to math.ceil() rounds up the number to the next number. When you pass math.ceil() a number with a decimal value of 0, it doesn’t round up but instead rounds to the closest integer, as you can see at ➊. The functions’ rounding helps us evenly distribute the turtle’s cobblestone into the furnaces.
In Minecraft, each furnace’s input slot can hold up to 64 items to smelt. For efficiency, we want all the furnaces smelting at the same time instead of just one. To calculate how many cobblestone blocks to drop into each furnace, we’ll divide the number of cobblestone blocks in the current slot by NUM_FURNACES. Because this division operation might not result in a whole number, such as 64 / 5 = 12.8, we’ll pass this number to math.floor(), which in this case rounds down the number to 12. Then we’ll drop that number of cobblestone blocks into each furnace so all the furnaces can smelt at the same time.
But this calculation has a couple of problems. For example, if you have 64 cobblestone blocks and 5 furnaces, the turtle will drop 12 cobblestone blocks in each furnace and be left with 4 blocks. Turtles can mine cobblestone quicker than furnaces can smelt them, and each furnace can hold 64 items at most in its input slot. For each furnace that is full and can’t accept any more cobblestone, the turtle will be left holding the portion of blocks for that furnace—in this case, 12. To address this issue, we’ll make a different calculation. Let’s look at lines 29 to 33 again:
cobminer
29. for furnacesToFill = NUM_FURNACES, 1, -1 do
30. turtle.back() -- move over furnace
31. numToDrop = math.floor(turtle.getItemCount() / furnacesToFill)
32. turtle.dropDown(numToDrop) -- put cobblestone in furnace
33. end
Using numToDrop, line 31 calculates the number of cobblestone blocks to drop in each furnace with numToDrop = math.floor(turtle.getItemCount() / furnacesToFill). Instead of calculating the number of cobblestone blocks to drop once and storing that number in the numToDrop variable, the value of numToDrop is recalculated each time the turtle moves to a new furnace. Table 9-1 shows how numToDrop is calculated on each iteration of the for loop when all the furnaces are empty.
Table 9-1: numToDrop Values When All Furnaces Are Empty
Iteration |
math.floor(turtle.getItemCount() / furnacesToFill) |
numToDrop |
Number of cobblestone dropped into furnace |
First |
math.floor(64 / 5) |
12 |
12 |
Second |
math.floor(52 / 4) |
13 |
13 |
Third |
math.floor(39 / 3) |
13 |
13 |
Fourth |
math.floor(26 / 2) |
13 |
13 |
Fifth |
math.floor(13 / 1) |
13 |
13 |
|
|
|
Total: 64 |
However, let’s pretend the second furnace is full because the player dropped some of their own mined cobblestone into it. Now no cobblestone can be dropped into the second furnace. But because numToDrop is recalculated on each iteration of the for loop, the code automatically drops more cobblestone into the later furnaces. Table 9-2 shows how numToDrop is calculated on each iteration. Notice that on the second iteration, the number of cobblestone blocks dropped in the furnace is 0 because the second furnace is full.
Table 9-2: numToDrop Values When the Second Furnace Is Full
Iteration |
math.floor(turtle.getItemCount() / furnacesToFill) |
numToDrop |
Number of cobblestone dropped into furnace |
First |
math.floor(64 / 5) |
12 |
12 |
Second |
math.floor(52 / 4) |
13 |
0 |
Third |
math.floor(52 / 3) |
17 |
17 |
Fourth |
math.floor(35 / 2) |
17 |
17 |
Fifth |
math.floor(18 / 1) |
18 |
18 |
|
|
|
Total: 64 |
Lines 29 to 33 show that a bit of clever code can make the furnaces work at maximum efficiency. When the for loop has finished, the turtle will be over the last furnace and will need to move back to the cobblestone block.
Lines 36 to 38 keep moving the turtle forward until it is in front of the cobblestone block.
cobminer
35. -- move back to cobblestone generator
36. for moves = 1, NUM_FURNACES do
37. turtle.forward()
38. end
At this point, the turtle checks the current slot. Remember, the turtle can mine cobblestone quicker than furnaces can smelt them. It won’t be long before all of the furnaces are completely full but the turtle has 64 cobblestone blocks to drop in them. If any cobblestone is still in the turtle’s inventory, then all the furnaces are full and the turtle is unable to put this cobblestone in them.
cobminer
40. if turtle.getItemCount() > 0 then
41. print('All furnaces full. Sleeping...')
42. os.sleep(300) -- wait for 5 minutes
43. end
44. end
45. end
The turtle.getItemCount() returns the number of items in the current slot. If this number is greater than 0 (meaning the turtle still has some cobblestone), line 42 pauses the program for 300 seconds, or five minutes, to give the furnaces more time to smelt the previous cobblestone.
Line 43 ends the if statement block on line 40, line 44 ends the if statement block on line 21, and line 45 ends the while loop on line 9. Finally, the execution loops back to line 9 and the turtle continues mining cobblestone and filling the furnaces until it runs out of fuel.
As with the tree-farming program in Chapter 8, you can scale your cobblestone production by building multiple cobblestone generators. You can also add more furnaces behind the turtle and change the NUM_FURNACES constant. (Five or six furnaces are plenty to smelt cobblestone. Otherwise, your turtle won’t be able to mine fast enough to keep up with the furnaces!)
In this chapter, you learned how to build a cobblestone generator that mixes lava and water streams to produce an endless supply of cobblestone blocks for your turtle to mine, and you used the cobminer program to make the turtle mine these cobblestone blocks and drop them into furnaces behind the turtle. You also learned about constants, which are variables that don’t change their values and which help make your code more readable. In addition, you learned about the step argument in for loops, which lets you create for loops that count down instead of up. Finally, you learned how the math.floor() and math.ceil() functions can round a number down and up, respectively.
In Chapter 10, we’ll use the cobminer program to create a stone brick factory, which is a two-turtle operation. We’ll write a program that will instruct another turtle to take smelted stone blocks out of the furnaces and craft them into stone brick using the brickcrafter program.