Introduction: Summer Camp Class on Python Coding With Minecraft

Last summer, I taught a five-day 2.5-hours-per-day summer camp mini-course on Python programming with Minecraft for gifted kids as part of Baylor's University for Young People. Most of the kids were a part of Project Promise, a gifted program for low-income kids. This instructable gives a successful curriculum (used for a total of three mini-course runs: two middle-school and one high-school) you can use to introduce students to Python and basic programming concepts, based fairly closely on what I did.

You will need to use:

  • Minecraft licenses for students and instructor
  • Computers with Minecraft, Forge and my RaspberryJamMod
  • Python IDE (I used Visual Studio Community Edition with PTVS)
  • A projector or other large screen option for showing stuff

I recommend looking at the Whale and O'Hanlon book for ideas (they also have a nice support forum here).

Step 1: Computer Setup

  1. Set up Minecraft 1.9.4, Forge for 1.9.4 and RaspberryJamMod on the instructor's computer. There are detailed instructions on how to do that in this Instructable.
  2. Set all the Minecraft settings you want. Turn sound off, for instance. Make a nice, creative world that shows off the capabilities of Minecraft+python+RaspberryJamMod. For instance, I had a world with a big Deep Space Nine station which one can make with /py render ds9.
  3. Log out of your Minecraft account, and copy everything in your .minecraft (on Windows: %appdata%\.minecraft) directory (including the mcpipy directory for RaspberryJamMod) to a thumb drive.
  4. Install Minecraft on each student computer using the official installer.
  5. Overwrite the .minecraft directory on each student computer with the one on your thumb drive. This will install Forge and the mod.
  6. Install your preferred Python IDE on each computer, and point it to the .minecraft/mcpipy directory. If using Visual Studio + PTVS (which is what I used), load in the mcpipy.sln file.

Note 1: Last summer, I used Minecraft 1.8, but I recommend 1.9.4 right now. I just made a version of RaspberryJamMod for 1.10 but it'll be a week or two before it's mature enough for production use.

Note 2: Throughout, I will assume Python 2.7, as that's what the books on Minecraft python programming use, and as it's what I normally use.

Step 2: Day One: Part One: Impress Them

If your students are like some of mine, they will have already seen some very impressive things in Minecraft done with command-blocks, and you'll need to work to impress them with the usefulness of Python code.

Show them some cool things, especially ones that are hard to do with command-blocks. You can make something yourself, or use the demo scripts that come with Raspberry Jam Mod, which you can launch with /py scriptname from within Minecraft. Some nice options (note: the first three need an active Internet connection).

  • /py render yt1300 : draws a Star Wars YT-1300 freighter, like the Millennium Falcon
  • /py render 1701d : draws a Star Trek Enterprise
  • /py chess d : Minecraft plays chess against itself
  • /py bridge : a bridge extends wherever you go, letting you walk on air and water, and then erasing behind itself
  • /py digitalclock
  • Make a simple vehicle on the ground manually using a couple of blocks, and then turn it into a moving vehicle with /py vehicle . Move/jump/fly the player to move the vehicle. Or load one that's included with RJM: /py vehicle l TIE_Fighter

To stop a running script, just run another script, or /py without a script. (Make that clear to the students.)

In the interests of truth in advertising, tell the students that except for the bridge, these examples go beyond the skills in the course.

After impressing them, you need to pay some attention to see if there are kids who haven't used Minecraft before. If there are, make sure they learn how to create a superflat creative world, exploring a world, build simple stuff, etc. One way to do that is to have more experienced kids teach them this. And to keep the other kids busy, put a list on the board of fun scripts to try (/py donut, /py spacefill, /py borromean, /py mengersponge etc.).

Step 3: Day One: Part Two: Ground Rules

I strongly recommend these rules to minimize distraction:

  • Use nothing on the computer except Minecraft (though you might let them access this list of block ids).
  • No LANs or access to other servers (except when specifically permitted on the last two days).
  • Creative only.
  • Stick to the overworld (RaspberryJamMod only has experimental support for other worlds).
  • No sound.
  • Pay attention when the teacher is speaking.

Distraction will be your biggest enemy in this class. Students will get lost playing in Minecraft instead of coding. It's a challenge for the teacher to have a balance of letting them have fun--ideally fun where a bit of Python code is a part of the fun--and ensuring they stay on task. I did it both ways. Fun is important, as you want them to have pleasant memories of the class, and hence of coding.

By the way, if you do allow LAN sessions, you will need to tell them the distinction between /py and /lpy for running scripts:

  • /py runs a script that is located on the server computer, namely whichever computer hosts the LAN session
  • /lpy runs a script that is located on the physical computer the student is using. (The "l" is for "local".)

So if Alice hosts a LAN session and Bob connects to it, Bob can run Alice's scripts with /py and can run his own scripts with /lpy.

Step 4: Day One: Part Three: Turtle

Now show them how to create a very simple python script using the mcturtle.py module that comes with RaspberryJamMod. To create a new script in Visual Studio, make sure that the mcpipy project is highlighted in the solution pane on the right (loaded from mcpipy.sln), and then use Project | Add New Item. Then type in a script like this, call it turtle1.py say, showing it on a big screen, explaining it line-by-line:

from mcturtle import *

steve = Turtle()
steve.go(10)
steve.yaw(90)
steve.go(10)

For the yaw part, you can put up a diagram like the one here (drawn on the whiteboard by my daughter, who was among the students).

Save, flip to Minecraft, using a new superflat creative world, and run /py turtle1 in Minecraft. You'll notice that you'll move along with the turtle step-by-step. I like to talk of .go() and .yaw() as sending messages to the turtle (which here is named steve).

Then tell the kids to start with this script and make it into square. Go around helping them. Some will have typos.

One issue that's likely to come up is that many people's squares will look ugly and unaligned. That's because the turtle starts going in exactly the direction Steve is facing in Minecraft at the beginning of the script, and that might not be aligned with the grid. You can tell them to fix this by adding steve.gridalign() right after they've created steve.

This may be a good time to talk about other useful mcturtle commands, like penblock(blockname) which changes the block that the turtle draws with (default is GOLD_BLOCK; if they are using an IDE with a good auto-complete like Visual Studio, they will easily be able to pull up a lot of block names; otherwise, give them an abridged list from here), penwidth(n) which lets you have nice, thick lines, pitch(angle) and roll(angle). There is also penup() and pendown().

Challenge them to make some other things with the turtle. Once they start making complex things, suggest that they also initialize with:

steve.turtle(None)
steve.pendelay(0)

This makes the player not trail along with the turtle and makes the turtle move at maximum speed.

The basic turtle commands are listed here. You might include a handout with them.

Step 5: Day One: Part Four: Loops

The obvious square script will look like something this:

from mcturtle import *

steve = Turtle()
steve.go(10)
steve.yaw(90)
steve.go(10)
steve.yaw(90)
steve.go(10)
steve.yaw(90)
steve.go(10)

Now is a good time to talk about how computers make repetitive things easier. You can simplify to:

from mcturtle import *

steve = Turtle()
for i in range(4):
  steve.go(10)
  steve.yaw(90)

This isn't much of a savings for squares. But with other geometric figures, like a pentagon, with more sides, and the savings will be bigger. Make sure everyone can do this. There may be some error messages due to bad punctuation, capitalization, etc. as kids struggle.

If you can get the kids to figure out together how to change the code to do a pentagon, that's great. Otherwise, you will want to guide them through it. The pentagon will involve a loop of 5 pairs of go() and yaw() calls. At the end of the pentagon, the turtle will face the same way as the beginning. So it'll have to turn through 360 degrees, and 360/5 = 72. So, you yaw by 72.

Set them loose making geometric figures. You can challenge them to make a star if they can. (A nice five-pointed one uses yaw(144).) You can also challenge them to draw an upright star, or to draw the outline of a cube.

As the kids draw things with thick turtle lines, the player will sometimes be trapped inside a drawing. You can tell them about the Minecraft teleport command or, even more simply, to run /py top which calls a script to put you on the very top of whatever construction you're inside. (Running /py stops any running script. If you want to do this while another script is running, use /apy top.)

You might not cover all or much of the loop material on day one, if preliminaries (signing on to computers, etc.) take too long. If so, you'll need to shift the material to the next day.

Step 6: Day Two: Part One: More Turtle and Loops

Talk about how to draw a "circle", simply by drawing a figure with lots of sides, say 36 or more. This lets you do cool stuff, like this lava-filled donut:

from mcturtle import *

steve = Turtle()
steve.turtle(None)
steve.pendelay(0)

steve.penwidth(16)
steve.penblock(GLASS)
for i in range(36):
  steve.go(5)
  steve.yaw(360./36)

steve.penwidth(13)
steve.penblock(LAVA)
for i in range(36):
  steve.go(5)
  steve.yaw(360./36)

At this point, tell them about the loop variable. For instance, if you take the code for drawing a circle, and change yaw(360./36) to yaw(360./36+i), the circle will loop in on itself making a spiral. You can also make it clear how the loop variable works by putting a print(i) inside the loop or steve.mc.postToChat(i).

By the way, if someone asks how to draw a sphere, it's super-simple. This draws a sphere of radius 50:

from mcturtle import *
steve = Turtle()
steve.penwidth(50)
steve.go(0)

Step 7: Day Two: Part Two: Working With Coordinates

Explain the Minecraft coordinate system using a diagram like this.

Note: The coordinates in Python code aren't exactly the same as the ones that Minecraft uses (which you can see if you press F3). They are relative to the spawn area.

Now it's time to draw blocks using coordinates. This uses the Minecraft PI API more directly, without the turtle module as a helper. Some simple code for the kids to do:

from mc import *
mc = Minecraft()
mc.setBlock(0,0,0,GOLD_BLOCK)
mc.setBlock(0,1,0,GOLD_BLOCK)

You can then combine this with loops and loop variables:

from mc import *
mc = Minecraft()
for i in range(100):
  mc.setBlock(i,i,0,DIAMOND_BLOCK)

Make sure the kids all understand what's going on, or they will be stuck for the rest of the course.

Step 8: Day Two: Part Three: Randomness

I tell the kids that games normally need randomness. Here's a script they will really enjoy modifying and playing with the output of that uses randomness:

from mc import *
from random import *

mc = Minecraft()

for i in range(200):
  mc.setBlock(randint(-10,10), randint(0,20), randint(-10,10), randint(0,255), randint(0,15))

This draws random blocks in a 20x20 cube. Here, randint(0,255) picks a random block ID and randint(0,15) a random meta value for it. Have the kids experiment with the numbers. They will love to see the wide variety of blocks.

Step 9: Day Three: Part One: Magic Bridge

The magic bridge is a great idea from the Whale and O'Hanlon book. It makes a bridge that extends under the player, letting the player walk on water and in the air, and you can show the kids how a program grows from a simple to more complex form.

Here's the simplest version:

from mc import *
from time import *

mc = Minecraft()

while True:
  position = mc.player.getTilePos()
  mc.setBlock(position.x, position.y-1, position.z, STAINED_GLASS_BLUE)
  sleep(0.2)

Explain all the steps carefully to the kids, focusing on the infinite game loop (while True), and how mc.player.getTilePos() checks the player's current position, divided into x, y and z coordinates. Tell them that the sleep(0.2) is to ensure that Minecraft isn't overwhelmed with doing lots of setBlocks, so that there is a 0.2 second wait. Recall that you can stop a script with /py by itself.

Have all the kids make a working bridge, and then talk with them about its deficiencies. For instance, the bridge damages the ground you're walking in. You you should revise it so it's only drawn in the air. This lets you introduce the if statement:

from mc import *
from time import *

mc = Minecraft()

while True:
  position = mc.player.getTilePos()
  belowBlock = mc.getBlock(position.x, position.y-1, position.z)
  if belowBlock == AIR.id:
    mc.setBlock(position.x, position.y-1, position.z, STAINED_GLASS_BLUE)
  sleep(0.2)

Explain the difference between the assignment = and the comparison ==. It's important that you have AIR.id rather than just AIR in the code. That's because AIR is a Block but getBlock() in the Minecraft Python PI API returns not a block but a block ID number, and AIR.id is that block ID number (zero, actually).

Of course, this isn't perfect, either, because it won't draw bridges above water. To fix that, you get introduce or and change the if line to:

  if belowBlock == AIR.id or belowBlock == WATER_FLOWING.id or belowBlock == WATER_STATIONARY.id:

If you want, kids can even add magma.

There is one final bit of magic, and that's the most magical of all. The bridge could erase itself behind the player. To that end, you would need to introduce lists. Whether you want to do this depends on the level of your students. if you do want to do it, then store past player positions in a list called saved.

from mc import *
from time import *

mc = Minecraft()

saved = []

while True:
  position = mc.player.getTilePos()
  belowBlock = mc.getBlock(position.x, position.y-1, position.z)
  if belowBlock == AIR.id or belowBlock == WATER_FLOW.id or belowBlock == WATER_STATIONARY.id:
    mc.setBlock(position.x, position.y-1, position.z, STAINED_GLASS_BLUE)
    saved.append(position)
    if len(saved) > 10:
      firstPosition = saved.pop(0)
      mc.setBlock(firstPosition.x, firstPosition.y-1, firstPosition.z, AIR)
  sleep(0.2) 

As you add the code, explain it. You're starting an empty list with saved = []. Then you are appending position to the end of the list, and if the list has more than 10 items in it, you're popping out the first item and drawing air below it (you're saving player, not bridge, positions).

There still are imperfections. For instance, if the bridge is drawn on water, it will be restored with air. Fixing that might be a challenge for the cleverer students.

Step 10: Days Four and Five: Part One: You Make a Game

Days four and five of the camp are devoted to the kids making a simple game themselves in groups of two or three. First, you make a simple game.

Here's one where you have to jump onto ten gold blocks as fast as possible.

from mc import *
from random import *
from time import *

mc = Minecraft()

mc.setBlocks(-15,0,-15,15,0,15,AIR)

blockCount = 0
while blockCount < 10:
  x = randint(-15,15)
  z = randint(-15,15)
  if mc.getBlock(x,0,z) != GOLD_BLOCK.id:
    mc.setBlock(x,0,z,GOLD_BLOCK)
    blockCount = blockCount + 1

startTime = time()

while blockCount > 0:
  position = mc.player.getTilePos()
  if mc.getBlock(position.x, position.y-1, position.z) == GOLD_BLOCK.id:
    mc.setBlock(position.x, position.y-1, position.z, AIR)
    blockCount = blockCount - 1
    mc.postToChat("Yay, found one!")
  sleep(0.2)

mc.postToChat("You found them all in "+str(time()-startTime)+" seconds!")

The first while loop goes on until ten blocks are hidden. The if checks to make sure that there is no gold block already where you're placing one (make sure to explain the != part). You can also set a time limit, and if time()-startTime exceeds that limit in the loop, you mc.postToChat("Out of time") and break and make sure that you post the victory message only if blockCount <= 0.

The second while loop goes on until all blocks are found.

If you want a fancy giant display of how many blocks are left, add:

from text import drawText
from fonts import FONTS

and then put before the second while loop, as well as inside the if, this:

drawText(mc, FONTS['tallfont'], Vec3(0,0,16), Vec3(-1,0,0), Vec3(0,1,0), str(blockCount)+"  ", SEA_LANTERN, AIR)

Another fairly simple game to show off is chase.py, included in the RaspberryJamMod distribution, where you're chased by a line of gold blocks. A good setting to play that in is inside a menger sponge (/py mengersponge).

Step 11: Days Four and Five: the Kids Make a Game

Start by having each group plan their game, and then sell you on the concept. Offer them advice. Sometimes you'll need to simplify it, sometimes you'll need to teach the group some additional concepts or commands. (For commands, this instructable may be helpful.) If anybody is really, really stuck, have them start with your simple game and suggest enhancements (time limits, dangerous areas where you die, harder climbs).

You can allow LAN use to help students work as a group. For instance, one person could be writing code, and the others could be drawing the board. I recommend that the computer where the code is written be the host of the LAN session.

Making multiplayer games is likely to be difficult in the time available, so I don't recommend that, unless you've got exceptionally brilliant kids.

Once the kids make their games on Day Five, have them circulate and try other people's games.

Step 12: Day Five: Optional: Subroutines

With my group of high-schoolers, I also gave them a demo of how subroutines work. I did it by showing how to draw a simple branching tree with the turtle. For instance:

from mcturtle import *

steve = Turtle()
steve.turtle(None)
steve.pendelay(0)

def branches():
  steve.pitch(-15)
  steve.go(10)
  steve.back(10)
  steve.pitch(30)
  steve.go(10)
  steve.back(10)
  steve.pitch(-15)

steve.pitch(90) 
steve.go(10)
steve.pitch(-30)
branches()
steve.pitch(60)
branches()
steve.pitch(-30)
steve.roll(90)
steve.pitch(-30)
branches()
steve.pitch(60)
branches()
steve.pitch(-30)

It'll be a lot nicer if you make it recursive and fractal, but that's probably too much for a five-day class. But you can show off fancytree.py and lsystem.py for inspiration.

DIY Summer Camp Challenge

Participated in the
DIY Summer Camp Challenge