9
HITTING THINGS WITH LISTS AND DICTIONARIES

image

We use lists, such as shopping lists or lists of instructions, to remember a group of items or to work through steps in a certain order. Lists in Python are very similar: they’re used to store a collection of data within a sequence. A list can store several types of data, including strings, numbers, Booleans, and even other lists.

Normally, variables can hold only one value. Lists are useful because they allow you to store several values in a single variable, such as the numbers from 1 to 100 or your friends’ first names. In other programming languages, lists are sometimes called arrays.

You can use lists of block IDs, coordinates, or a variety of other things to gain lots of power over your Minecraft world. Because lists can store several kinds of values in a single variable, they give you flexibility that a regular variable can’t offer.

In this chapter, you’ll learn how to use lists with the Minecraft Python API to create a mini-game for recording height, make a progress bar, and write a program that randomly slides the player around the game.

USING LISTS

Making a list with Python is straightforward. To define a list, use square brackets around any number of values—or no values at all, which is called an empty list. Each item in a list needs to be separated by a comma.

For example, a list of ingredients for noodle soup might look like this:

>>> noodleSoup = ["water", "soy sauce", "spring onions", "noodles", "beef"]

The noodleSoup list contains several items and all of them are strings.

You can create an empty list like this:

>>> emptyList = []

Use an empty list when you want to add values later in your program.

You can store any data type in your list and even mix different data types. For example, you could have a list that contains integers and strings:

>>> wackyList = ["cardigan", 33, "goofballs"]

Sometimes your lists will be very long, making them difficult for humans to read. But you can format long lists across several lines in Python so programmers can read them easily. Using several lines for items has no effect on how the Python code runs. For example, the following format for soup ingredients works the same as the earlier noodleSoup list:

>>> noodleSoup = ["water",
        "soy sauce",
        "spring onions"
        "noodles",
        "beef"]

Next, we’ll look at how you can access and change items in a list.

ACCESSING A LIST ITEM

To access a value in a list, reference the item’s position in the list, which is known as its index. Using the noodle soup example, you can access the first item in the list like this:

>>> print(noodleSoup[0])
water

It’s important to note that the first index in a list is 0. The second item is index 1, the third is index 2, and so on. The reason for this is that computers count from zero when using lists.

Counting from zero might seem silly, but there’s a good reason for it. Early computers were very slow and had a very little memory. It was faster and more efficient to start counting indexes from zero. Even though computers are much faster these days, they still count from zero.

It’s also important to note that if you try to access a list index that is greater than the number of items in the list, you’ll get an error message. The following line tries to print the item in index position 5:

>>> print(noodleSoup[5])

Here’s part of the error message:

IndexError: list index out of range

The IndexError tells me that there is no data in the index I want to access. Index position 5 in the list has no data because it’s outside the length of the list. Python can’t return a value that doesn’t exist!

CHANGING A LIST ITEM

Just like you can change the value of variables, you can change individual items in lists as well. This is because lists are mutable, which means they can be changed. To change an item in a list, you use the item’s index position and set its value the same way you would set the value of a variable (by using an equal sign).

Let’s change the beef item in the noodle soup to chicken. Beef is the fifth item in the list, so it has an index of 4 (remember, you count from zero in lists). We can easily change item 4 to chicken, like so:

>>> noodleSoup[4] = "chicken"

Now let’s do something cool with lists in Minecraft.

MISSION #47: HIGH AND LOW

When I’m exploring the Minecraft world, it’s interesting to look back over my journey. From the highest mountains to the lowest caves, exploration is one of my favorite activities in the game. Sometimes when I’m playing with friends, we race each other to see who can get to the highest or lowest point in the game the fastest. So no one cheats, I wrote a program that stores the lowest and highest y-coordinates the player reaches within 60 seconds.

When I run the program, it tells me the highest and lowest places in the game that I traveled to during one minute. Listing 9-1 contains the code I’ve started for you. Copy it into a new file and save it as highAndLow.py in a new folder called lists.

highAndLow.py

   from mcpi.minecraft import Minecraft
   mc = Minecraft.create()

   import time

heights = [100, 0]
   count = 0

   while count < 60:
       pos = mc.player.getTilePos()

       if pos.y < heights[0]:
        # Set the lowest height to the y variable
       elif pos.y > heights[1]:
        # Set the highest height to the y variable

       count += 1
       time.sleep(1)

mc.postToChat("Lowest: ")   # Output lowest height
mc.postToChat("Highest: ")  # Output highest height

Listing 9-1: The start of the code to get the lowest and highest positions the player visits

The program will store the lowest and highest y-coordinates you’ve traveled to in a list called heights . The first item in the list (index position 0) stores the lowest coordinate and the second (index position 1) stores the highest. We need to start with a high “lowest” value and a low “highest” value so that the first time we run the program, the player’s position will be the new lowest or highest value and will be displayed in the chat. Here I’ve used a default lowest value of 100 and a default highest value of 0.

The while loop runs once per second for 60 seconds to constantly update the values in heights. The if statement checks whether the player’s current height is lower than the lowest value stored in the list . Then the elif statement checks whether the current height is greater than the highest position stored in the list .

To complete the code, you need to set the value of the lowest height, height[0], to the value of pos.y at . Remember that you set the values in lists like you would a variable, so the line of code should look like this: height[0] = pos.y. You also need to set the highest height, height[1], to the value of pos.y .

Finally, you need to output the value of the lowest and highest heights in the last two lines of the program. To do this, you’ll need to access the index positions for the lowest and highest heights from the heights list (again, index 0 is the lowest height and index 1 is the highest height).

Run the program and start running around the game. See how high and how low you can get. After 60 seconds, the loop will stop, and the program will display your highest and lowest heights. Run the program several times and see if you can beat your record!

Figure 9-1 shows one of my attempts.

image

Figure 9-1: The lowest y-coordinate I visited was 15 and the highest was 102.

MANIPULATING LISTS

Lists have a set of built-in functions that let you manipulate them. These functions include common operations like adding an item to a list, inserting an item, or deleting an item.

ADDING AN ITEM

You can add an item to the end of a list using the append() function: just include the value of the item you want to append as an argument.

The noodle soup would be better if we added some vegetables. To do this, use the append() function:

>>> noodleSoup.append("vegetables")

Now the noodleSoup list contains a "vegetables" string as the last item in the list.

Appending items is very useful when you start with an empty list. By using the append() function, you can add the first item to an empty list:

>>> food = []
>>> food.append("cake")

INSERTING AN ITEM

It’s also possible to insert an item into the middle of a list. The insert() function places an item between two existing items and changes the index positions for all the items after the newly inserted item.

This function takes two arguments, the index position where you want to insert the item and the value that you want to insert.

For example, here’s our current noodleSoup list:

>>> noodleSoup = ["water", "soy sauce", "spring onions", "noodles", "beef",
"vegetables"]

Let’s add "pepper" to the list in the third index position:

>>> noodleSoup.insert(3, "pepper")

The updated list holds the following values after the insert:

["water", "soy sauce", "spring onions", "pepper", "noodles", "beef", "vegetables"]

If you try to insert an item at an index position that is greater than the length of the list, the item will be added after the last item. For example, if your list has seven items, but you try to insert at item position 10, the item will just be added to the end of the list.

>>> noodleSoup.insert(10, "salt")

After running this code, the last item in the list will be "salt":

["water", "soy sauce", "spring onions", "pepper", "noodles", "beef",
"vegetables", "salt"]

Notice that salt isn’t in index position 10; instead it is in index position 7.

DELETING AN ITEM

Sometimes you’ll want to get rid of an item in a list. You use the del keyword for this. The keyword goes before the name of the list, with the index position of the item you want to delete in the square brackets.

For example, to delete the "beef" item, which is now in index position 5 in the noodleSoup list, do this:

>>> del noodleSoup[5]

You can also use the del keyword in combination with the index() function if you want to find the index position of a value and then delete it:

>>> beefPosition = noodleSoup.index("beef")
>>> del noodleSoup[beefPosition]

After deleting an item, the index positions in a list will change. This is what the list will look like after we delete "beef" at index position 5:

["water", "soy sauce", "spring onions", "pepper", "noodles", "vegetables", "salt"]

The "vegetables" index position changes from 6 to 5, and the "salt" index position changes from 7 to 6. Note that only indexes after the deleted item will be affected; any indexes before the deleted item will be unchanged. Keep this in mind when deleting items from your lists.

MISSION #48: PROGRESS BAR

Let’s use some of the list functions to create a progress bar in Minecraft. It will look like the one you see onscreen when you’re downloading a file from the Internet or when you’re keeping track of your next level up in a role-playing game.

The program will use the progress bar to count to 10 seconds. When the program starts, the progress bar will be made of glass blocks. For every second that passes, the progress bar will replace a glass block with a lapis lazuli block. Figure 9-2 shows the first five steps in the progress bar.

image

Figure 9-2: The progress bar shows the progress at 50 percent (5 out of 10 blocks are lapis lazuli).

Open IDLE and create a new file. Save it as progressBar.py in the lists folder. An incomplete version of the program is in Listing 9-2. Copy it into your text editor.

progressBar.py

   from mcpi.minecraft import Minecraft
   mc = Minecraft.create()

   import time

   pos = mc.player.getTilePos()
   x = pos.x + 1
   y = pos.y
   z = pos.z

   # Add 10 glass blocks (ID 20) to this empty list
blocks = [ ]
   barBlock = 22  # Lapis lazuli

   count = 0
   while count <= len(blocks):

       mc.setBlock(x, y, z, blocks[0])
       mc.setBlock(x, y + 1, z, blocks[1])
       mc.setBlock(x, y + 2, z, blocks[2])
     # Add setBlock() for the remaining blocks in the list

       count += 1

     # Delete the last block in the list

     # Insert a lapis lazuli block at the first position in the list

       time.sleep(2)

Listing 9-2: Incomplete code to make a progress bar

To complete the program in Listing 9-2, you’ll need to do the following:

  1. Add 10 glass blocks (ID 20) to the empty blocks list at .

  2. Use the setBlock() function to set all 10 blocks from the list in the game world. The first three blocks have been set for you.

  3. Write a statement that deletes the last block in the list (index position 9) . Remember that you use the del keyword to delete an item from a list.

  4. Insert a new lapis lazuli block at the start of the list . Use the insert() function with the barBlock variable to insert a new lapis lazuli block in index position 0.

Comments are included in the code to help you find where you need to do these tasks.

TREATING STRINGS LIKE LISTS

Strings can be treated like lists, because a string is also a sequence of data. You can access individual characters in a string using their index; however, you cannot change the characters in each index position using the append or insert functions because strings are immutable. That means that they cannot be changed.

The following code will print the second letter in the string "Grape":

>>> flavor = "Grape"
>>> print(flavor[1])
r

This shows that you can access parts of a string like you would items in a list. For example, you could access the first letters of someone’s first and last names to print their initials:

>>> firstName = "Lyra"
>>> lastName = "Jones"
>>> initials = firstName[0] + " " + lastName[0]
>>> print(initials)
L J

The new string "L J" that you get by accessing parts of a string using index positions is called a substring. Note that the index for a string also counts from zero!

TUPLES

Tuples are a type of list that is immutable. But like other lists, they’re a sequence of items of any variable type. Tuples use parentheses instead of square brackets, and they use commas to separate items.

For example, say a nation’s only Olympic athlete, from an underfunded training program, records a number of distances for their long jumps in meters:

>>> distance = (5.17, 5.20, 4.56, 53.64, 9.58, 6.41, 2.20)

If the athlete jumped only once, you could also create a tuple with a single value. To write a tuple with a single value, you still have to include a comma:

>>> distance = (5.17,)

When you’re defining a tuple, the parentheses are optional, so you can just define a tuple by placing commas between values, like this:

>>> distance = 5.17, 5.20, 4.56, 53.64, 9.58, 6.41, 2.20

To access values of tuples, use the square bracket notation that you use with regular lists. Let’s assign the value in index 1 of the distance tuple to the variable jump:

>>> jump = distance[1]
>>> print(jump)
5.20

The main difference between lists and tuples is that tuples are immutable: you can’t change their contents. You can’t append items to the end of the tuple, insert items, delete items, or update any values. You use tuples instead of lists when your program doesn’t need to change the values of the items in the tuple.

SETTING VARIABLES WITH TUPLES

A useful feature of tuples is that you can use them to set more than one variable at the same time. This saves space and can keep related variables clustered together.

Normally, you would refer to a tuple like you would a list, by using a single variable name:

measurements = 6, 30

However, let’s say we want to store the values in two variables instead of one. The syntax to do so isn’t complex. You separate the variable names with commas, then use an equal sign, and then write the tuples on the other side of the equal sign. Each tuple value will be assigned to the variable in the corresponding position. Let’s take a look.

In this example, two variables, width and height, are set to the values 6 and 30, respectively:

width, height = 6, 30

Now we have two variables. One is called width and has a value of 6, and the other is called height and has a value of 30. And we did it by using just a single line of code!

MISSION #49: SLIDING

Setting variables with tuples is a quick and easy way to save space in your programs. It’s also useful for setting related variables together in one place in your program. For example, throughout the book you’ve used code like this for setting the values of the x, y, and z variables:

x = 10
y = 11
z = 12

Instead, you can use a tuple to set all of these values in one line:

x, y, z = 10, 11, 12

Next, you’ll put your new code-writing abilities to use! Your mission is to create a program that moves the player randomly around the game world in small steps, making it look like you’re skating on ice. I’ve started the program for you in Listing 9-3; some bits are missing and you need to complete them.

sliding.py

   from mcpi.minecraft import Minecraft
   mc = Minecraft.create()

   import random
   import time

# Get the player's position

# Set the x, y, and z variables on the same line using a tuple

   while True:
     x += random.uniform(-0.2, 0.2)
       # Change the z variable by a random float
     z +=
       y = mc.getHeight(x, z)

       mc.player.setPos(x, y, z)
       time.sleep(0.1)

Listing 9-3: The start of the code to make the player slide around the map

Copy Listing 9-3 into a new file and save it as sliding.py in your lists folder. To finish the program, you need to get the player’s starting position and set the values of the x, y, and z variables . Use a tuple to set these values. This program also uses the uniform() function , which is like the randint() function (see “Playing with Random Numbers” on page 62) but returns a random float value instead of an integer value. Use the uniform() function to change the value of the z variable in the loop . This has already been done for the x variable .

Figure 9-3 shows my player sliding slowly around my game.

image

Figure 9-3: Slowly sliding backwards around my garden

RETURNING A TUPLE

Some of Python’s built-in functions return a tuple. When you define your own functions, they can return the result as a tuple as well. To do that, you put a tuple after the return keyword. For example, let’s create a function to convert a date into a tuple. We give the date as a string argument, and the function will return the year, the month, and the day in a tuple. Here’s the code:

def getDateTuple(dateString):
    year = int(dateString[0:4])
    month = int(dateString[5:7])
    day = int(dateString[8:10])
    return year, month, day

When we call the function and give it a date as a string, it returns a tuple containing the year, month, and day in that order:

>>> getDateTuple("1997-09-27")
(1997, 9, 27)

When we call the function, we can store the returned tuple however we want. This code stores each value in a separate variable:

year, month, day = getDateTuple("1997-09-27")

Now we can quickly convert date strings to individual variables. In my work as a software developer, I use code that’s very similar to this all the time.

OTHER USEFUL FEATURES OF LISTS

You can do many other tasks with lists. This section explains how to find the length of a list, how to randomly choose an item from a list, and how to use an if statement to check whether a value is in a list.

LIST LENGTH

The len() function is a quick way to find the length of any list in Python. The function returns the number of items in a list when a list is used as an argument. Let’s see it in action:

>>> noodleSoup = ["water", "soy sauce", "spring onions", "noodles", "beef",
"vegetables"]
>>> print(len(noodleSoup))
6

Although Python starts counting indexes at zero, it counts how many items are in a list in regular counting numbers. The highest index in this list is 5, but Python knows there are 6 total items!

MISSION #50: BLOCK HITS

The Minecraft Python API has a handy function that returns a list of locations you’ve hit with your sword. You can use the items in the list to get the coordinates of blocks you’ve hit. You’ll see how useful this is in programs later in this chapter and later in the book.

You can also make a short and fun game that counts the number of blocks you can hit in a minute. In this mission, you’ll do just that. It’s quite a fun game: play against a friend and try to beat each other’s scores! You can also expand it, for example, by keeping a high score.

Figure 9-4 shows the program in action.

image

Figure 9-4: In 60 seconds I hit 197 blocks.

Not much code is required to make this game. Here’s a summary of the code structure:

  1. Connect to the Minecraft game.

  2. Wait 60 seconds.

  3. Get the list of block hits.

  4. Display the length of the block hits list to chat.

The following code shows the only part you haven’t seen so far, which is the code that gets the list of block hits from the game:

blockHits = mc.events.pollBlockHits()

This code uses the pollBlockHits() function to return a list of block hits and stores that list in a variable named blockHits. The blockHits variable will act like any other kind of list, so you can access data from index positions and get the length of the list.

When you play this game, you’ll have to right-click blocks to keep count of them. The reason is that the pollBlockHits() function records all the blocks you right-click with a sword. On the PC version of Minecraft, right-clicking with your sword looks more like you’re defending yourself than hitting something, but it still records which blocks you’ve clicked. Figure 9-5 shows what this looks like. Make sure you only right-click with your sword: left clicks with your sword won’t be recorded, and neither will right-clicking with something else in your hand! But you can use any type of sword, including iron, gold, and diamond.

image

Figure 9-5: When I right-click, the player holds the sword like this.

When you print the output of the list, it should look similar to this, although the values will change each time depending on where you hit:

[BlockEvent(BlockEvent.HIT, 76, -2, 144, 1, 452),
BlockEvent(BlockEvent.HIT, 79, -2, 145, 1, 452),
BlockEvent(BlockEvent.HIT, 80, -3, 147, 1, 452),
BlockEvent(BlockEvent.HIT, 76, -3, 149, 1, 452)]

This list output stores the details of four block hits. Each item contains the hit’s coordinates. You’ll learn how to access these coordinates in Mission #55 (page 196).

To help you get started with the program, I’ve written the basic structure in Listing 9-4.

swordHits.py

   # Connect to the Minecraft game
   from mcpi.minecraft import Minecraft
   mc = Minecraft.create()

   import time

   # Wait 60 seconds
   time.sleep(60)

   # Get the list of block hits
blockHits =

   # Display the length of the block hits list to chat
blockHitsLength =
   mc.postToChat("Your score is " + str(blockHitsLength))

Listing 9-4: Beginnings of the sword hits game

To complete this program, open IDLE, create a new file, and copy Listing 9-4 into it. Save this file as swordHits.py in the lists folder. Set the blockHits variable using the pollBlockHits() function and set the blockHitsLength variable by getting the length of the blockHits variable .

RANDOMLY CHOOSING AN ITEM

By now you might have realized that I really like using randomly generated things in my programs. Randomness makes a program behave somewhat unpredictably every time you run it.

When you’re using lists, you’ll want to access random items from the list from time to time. For example, you might want to choose a block at random from a list of blocks.

The choice() function in the random module is the go-to function for choosing a list item at random. The function takes one argument, the list that you want to use, and returns a random item from within the list.

In Listing 9-5, the colors list contains the names of several colors. It chooses one at random using the choice() function and then prints it:

import random
colors = ["red", "green", "blue", "yellow", "orange", "purple"]
print(random.choice(colors))

Listing 9-5: Printing a random color from a list of colors

When you run the code, the program will output an item from the list at random.

MISSION #51: RANDOM BLOCK

In Minecraft, selecting a random block ID from a range of numbers can cause problems in the program because some block IDs don’t have corresponding blocks. One solution is to use a list of valid blocks to select from at random. Lists allow you to create a limited number of items and then select one at random using the choice() function.

Your mission is to create a list of block IDs, select a random block from that list, and then set the block to the player’s position. You can use Listing 9-5 as a starting point.

First, create a list of block IDs. Second, use the random.choice() function to select a block from the list. Third, use the setBlock() function to place the random block in the Minecraft game.

Save the program as randomBlock.py in the lists folder.

Include as many blocks as you want in your list. For my list I chose five blocks, including melon, diamond, and gold. You can see the result of running the program in Figure 9-6.

image

Figure 9-6: The program randomly selected a gold block.

COPYING A LIST

Copying lists is quite tricky in most programming languages. List variables do not actually contain values; instead, they contain a reference to an address in your computer’s memory that has further references to the values contained in the list. Although your computer takes care of this capability behind the scenes, it’s worthwhile to understand how it works because it will make you a smarter programmer! You can view the memory address of a list using the id() function:

>>> cake = ["Eggs",
            "Butter",
            "Sugar",
            "Milk",
            "Flour"]
>>> print(id(cake))

For example, the output of this code on my computer was 3067456428. The value 3067456428 is the memory location where cake is stored. When you run this code on your computer, you’ll probably get a different number because it’s stored in a different place in your computer’s memory.

You don’t need to understand this behavior fully, but you do need to know that it has consequences when you want to copy a list into another variable. Instead of the values in the list being copied as you would expect, the memory location of the list is copied into the new variable. This means that when you change a value in either list, it will affect the other.

For example, the following program creates a list called cake and then sets the value of chocolateCake to be the same as cake. An item, "Chocolate", is then added to the chocolateCake list:

>>> cake = ["Eggs",
            "Butter",
            "Sugar",
            "Milk",
            "Flour"]

>>> # Store the list in a second variable
>>> chocolateCake = cake
>>> chocolateCake.append("Chocolate")

Unfortunately, "Chocolate" is also added to the cake list, even though you didn’t want it to be. You can see this mistake when the lists are printed:

>>> print(cake)
['Eggs', 'Butter', 'Sugar', 'Milk', 'Flour', 'Chocolate']
>>> print(chocolateCake)
['Eggs', 'Butter', 'Sugar', 'Milk', 'Flour', 'Chocolate']

This problem happens because the variables store the memory location of the list, not the items in the list.

A simple way to overcome this problem is to use a list slice. When you slice food with a knife, you are cutting it into different parts. A list slice in Python is similar. When you slice a list, you take a piece of the list. You can use a list slice to take only certain items in a list, but in this case, you’ll be using a list slice to copy every item in a list. To copy the cake list into the chocolateCake variable, use this code:

>>> chocolateCake = cake[:]

The chocolateCake variable will now contain the values of the cake list but with a different memory address.

The code for the cake ingredients can be corrected using the list slice:

   >>> cake = ["Eggs",
               "Butter",
               "Sugar",
               "Milk",
               "Flour"]

   >>> # Store the list in a second variable
>>> chocolateCake = cake[:]
   >>> chocolateCake.append("Chocolate")

You can see that the items in cake have been copied to chocolateCake using [:] at .

Here’s the output:

>>> print(cake)
['Eggs', 'Butter', 'Sugar', 'Milk', 'Flour']
>>> print(chocolateCake)
['Eggs', 'Butter', 'Sugar', 'Milk', 'Flour', 'Chocolate']

Notice that the values in both lists are now different—only chocolateCake contains the "Chocolate" value.

ITEMS AND IF STATEMENTS

To find out whether a value is in a list, you can use the in operator. The in operator goes between a value and the list you want to check. If the value is in the list, the expression will evaluate to True; if the value is not in the list, the expression will evaluate to False.

The following example checks whether the value "Eggs" is in the cake list:

>>> cake = ["Eggs", "Butter", "Sugar", "Milk", "Flour"]
>>> print("Eggs" in cake)

The value True will be printed, because "Eggs" is in the list.

You can of course use the in operator as part of an if statement condition. The following code extends and adapts this example to use an if statement instead of printing the Boolean value. It checks whether "Ham" is in the cake list and prints different messages depending on whether it is or isn’t in the list:

>>> cake = ["Eggs", "Butter", "Sugar", "Milk", "Flour"]
>>> if "Ham" in cake:
>>>     print("That cake sounds disgusting.")
>>> else:
>>>     print("Good. Ham in a cake is a terrible mistake.")

You can combine the not operator with the in operator to produce the opposite effect. Instead of returning True when an item is in a list, the code will return False and vice versa. Here’s how that looks (note that the bodies of the if and else statements have also been swapped):

>>> cake = ["Eggs", "Butter", "Sugar", "Milk", "Flour"]
>>> if "Ham" not in cake:
>>>     print("Good. Ham in a cake is a terrible mistake.")
>>> else:
>>>     print("That cake sounds disgusting")

You can use either technique in your programs. Just choose the one that you think makes the most sense!

MISSION #52: NIGHT VISION SWORD

Do you forget to bring enough torches with you when you’re exploring caves in Minecraft? I do that all the time. Sometimes I forget to bring any torches, and I’m too far into the cave to go back. So I fumble around in the dark, not really sure if I’m finding anything useful. But with your Python knowledge, you can make a program to help you find diamonds with your sword.

Let’s write a basic program that uses the pollBlockHits() function to check whether any of the blocks you’ve hit are diamond ore. This is useful for exploring caves with no light or playing a game of “find the diamond ore” in the dark. The code is in Listing 9-6. Copy it into a new file and save it as nightVisionSword.py in the lists folder.

nightVisionSword.py

   from mcpi.minecraft import Minecraft
   mc = Minecraft.create()

   import time

   blocks = []

   while True:
       hits = mc.events.pollBlockHits()
       if len(hits) > 0:
           hit = hits[0]
         hitX, hitY, hitZ = hit.pos.x, hit.pos.y, hit.pos.z
           block = mc.getBlock(hitX, hitY, hitZ)
           blocks.append(block)

     # Add the if statement here

       time.sleep(0.2)

Listing 9-6: This program will help you find diamond ore in the dark.

Notice how hit.pos.x, hit.pos.y, and hit.pos.z are used . Each hit stores the coordinates of the block that was clicked using a tuple. You can access these coordinates using dot notation. In this example, the variable name hit is used to name the list that contains each block hit, so I access the coordinates using hit.pos.x, hit.pos.y, and hit.pos.z.

The code is nearly complete. The only remaining task is to check whether you’ve found some diamond. Add an if statement to check whether diamond ore (block ID 56) is in the blocks list and post a message to chat saying "You found some diamond ore!" if it is. Add a break statement inside the if statement as well so the loop stops repeating when you find the ore.

Figure 9-7 shows the program in action.

image

Figure 9-7: It’s dark, but I found some diamond ore. Yay!

If you’re not as forgetful as I am and remember to bring torches with you into caves, you can still use this code—as a game. Make an underground room with no light and put a single diamond ore somewhere on the wall. Run the program and see how long it takes you to find the diamond ore in the dark. Remember to right-click with a sword! That’s the only way the pollBlockHits() function can record which blocks you’re hitting.

DICTIONARIES

Dictionaries are a type of list that uses a different approach. Instead of using an index to identify items, dictionaries identify items using a set of keys defined by the programmer.

For example, this raceTimes dictionary stores the names of people who ran in a race and their race times:

raceTimes = {'Katy': 26,
             'Alex': 30,
             'Richard': 19}

The key uniquely identifies each value in the dictionary. In this example, the key is the name of the person. The 'Katy' key has an associated value of 26.

Like lists, dictionaries are mutable; their content can be changed.

DEFINING A DICTIONARY

To define a dictionary, use a pair of curly brackets around a set of key-value pairs. For example, you can use a dictionary to describe a person. You can use keys like 'name' and 'favoriteAnimal' to store information about the person, like so:

person = {'name': 'David',
        'age': 42,
        'favoriteAnimal': 'Snake',
        'favoritePlace': 'Inside a cardboard box'}

In this example, every key is a string. Each key is paired with a value using a colon. For example, 'age' is a key and 42 is its corresponding value. Items in the dictionary are then separated by commas.

You may have noticed that using dictionaries makes it easy for a programmer to understand what each item in the list represents; for example, it’s easy to understand that the 'name' key stores a name, not a number or some other random information.

You can also use integers and floats as dictionary keys. Using floats or integers in dictionaries is very useful when the keys you want to match with values don’t follow a strict sequence.

The following example creates a dictionary of train times. The train time (which is a float) is stored as the key, and the destination of the train is stored as the value:

trainTimes = {1.00: 'Castle Town',
             2.30: 'Sheep Farm',
             3.15: 'Lake City',
             3.45: 'Castle Town',
             3.55: 'Storage Land'
             }

Because dictionaries can store two pieces of data that go together as a pair, they’re ideal for a situation like this. If I used a list of train destinations instead of a dictionary, I wouldn’t be able to match up the times to the destinations. I would only be able to use the list’s index positions, which would be 0, 1, 2, 3, 4, and so on, instead of the times.

ACCESSING ITEMS IN DICTIONARIES

To access the value of an item in a dictionary, you use square brackets and a key instead of an index. The key is usually a string or an integer. When you’re creating a dictionary that uses strings as keys, make sure you put them in quotation marks.

For example, to access the value of the 'name' key in the person dictionary created earlier, you would use this syntax:

person = {'name': 'David',
        'age': 42,
        'favoriteAnimal': 'Snake',
        'favoritePlace': 'Inside a cardboard box'}

agentName = person['name']

The agentName variable will contain the value 'David' because it accesses the value of the 'name' key. In the same way, if you wanted to access the age of the agent, you would use the 'age' key:

agentAge = person['age']

This would store the value 42 in the agentAge variable.

In the trainTimes example, you can access the values in the dictionary (the destinations) using their key values (the train times), which are floats:

trainTimes = {1.00: 'Castle Town',
             2.30: 'Sheep Farm',
             3.15: 'Lake City',
             3.45: 'Castle Town',
             3.55: 'Storage Land'
             }

myTrain = trainTimes[3.15]

Accessing the 3.15 key in the trainTimes dictionary sets the myTrain variable to 'Lake City'.

MISSION #53: SIGHTSEEING GUIDE

When you’re using dictionaries, you can store any data type as the value, even lists and tuples. For example, you could store a tuple containing values for x, y, and z. Here’s an example of code that does just that:

places = {'Living room': (76, 1, -61), 'Bedroom': (61, 9, -61)}

The places dictionary stores two items. The dictionary key is the name of a location in my Minecraft game (such as my living room or bedroom), and the value is a tuple of the coordinates. If I wanted to access the coordinates of my living room, I would use the following code:

location = places['Living room']
x, y, z = location[0], location[1], location[2]

Your mission is to create a program that uses a dictionary to store the locations of different places in your Minecraft game so you can teleport to them by name. Include as many locations in the dictionary as you want. To teleport to those locations, you need to access the tuple of coordinates stored in the dictionary and then set x, y, and z to the values stored in the tuple. Comments in the code show where to do this.

Copy Listing 9-7 into the IDLE text editor and save it in the lists folder as sightseeingGuide.py.

sightseeingGuide.py

   from mcpi.minecraft import Minecraft
   mc = Minecraft.create()

   # Add locations to the dictionary
   places = {}

   choice = ""
   while choice != "exit":
     choice = input("Enter a location ('exit' to close): ")
     if choice in places:
          # Store the dictionary item's value using its key (choice)
          location =
          # Store the values stored in the tuple in the x, y, and z variables
          x, y, z =
          mc.player.setTilePos(x, y, z)

Listing 9-7: Some neat code to teleport to different locations

I’ve included a statement that asks you to enter the name of the location you want to go to. This input is stored in the choice variable . The program then uses an if statement to check whether the value of choice is in the dictionary . The last line uses the x, y, and z variables to teleport the player to the position stored in the dictionary.

When the program runs, enter the name of the location that you want to go to. Figure 9-8 shows my version of the program teleporting me to different places in my game.

image

Figure 9-8: I teleported to my living room (top) and my bedroom (bottom).

CHANGING OR ADDING AN ITEM IN A DICTIONARY

It doesn’t take much work to change the value of an item in a dictionary. You use square brackets with a key to access the item and set it as you would a normal variable (with an equal sign). You can also add a new item using this approach.

Let’s change the value of the age item in the person dictionary from 42 to 43:

person['age'] = 43

Let’s also add a new item called location with the value 'USS Discovery':

person['location'] = 'USS Discovery'

After running this code, the dictionary will have a new key called location that has the value of 'USS Discovery'.

DELETING ITEMS IN DICTIONARIES

Sometimes you’ll want to delete an item in a dictionary. As with a list, you use the del keyword to do this. For example, to delete the favoriteAnimal item in the person dictionary, you would do this:

del person['favoriteAnimal']

As you can see, it works just like deleting items from a list.

MISSION #54: BLOCK HITS SCORE

In Mission #50 (page 180), you wrote a program that counts the number of times the player hits a block with their sword in 60 seconds. As fun as the program is, it would be even cooler if you could record the scores of everyone who played.

To add a scoreboard to the game, you’ll use a dictionary. The dictionary will store the player’s name and their score, which can then be displayed alongside everyone else’s scores.

To get started, open swordHits.py and save it as swordHitsScore.py in the lists folder. Update the code to match Listing 9-8, where I’ve made some changes to the program so it repeats, asks the player for their name, and then prints all the scores. (I’ve also included the solutions to the missing code from swordHits.py.) The older sections are grayed out. (Remember to indent everything inside the loop.)

swordHitsScore.py

   # Connect to the Minecraft game
   from mcpi.minecraft import Minecraft
   mc = Minecraft.create()

   import time

   name = ""
   scoreboard = {}

   while True:
       # Get the player's name
       name = input("What is your name? ")
       # Break loop if name is exit
       if name == "exit":
           break
       mc.postToChat("Go!")

       # Wait 60 seconds
       time.sleep(60)

       # Get the list of block hits
       blockHits = mc.events.pollBlockHits()

       # Display the length of the block hits list to chat
       blockHitsLength = len(blockHits)
       mc.postToChat("Your score is " + str(blockHitsLength))

     # Add the player to the scoreboard

       # Display the scoreboard
       print(scoreboard)

Listing 9-8: When the code is complete, it will add a scoreboard to the block hits game.

To finish the program, you need to store the name and score of every player who plays the game. Do this by adding a new dictionary item using the pieces of data in the code at . The dictionary is called scoreboard, and the name of the player is stored in the name variable.

Figure 9-9 shows the output of my scoreboard.

image

Figure 9-9: My friends and I played a game, and Jim is the winner with 274 block hits.

NOTE

You might have noticed that when the scoreboard dictionary is printed, it isn’t easy to read. You’ll learn how to fix this in Mission #59 (page 205).

WHAT YOU LEARNED

Excellent job! In this chapter you learned about lists, tuples, and dictionaries. You saw that they can store several data values in a single variable. They are a very useful way to structure and store data in your programs.

In the missions, you created several fun programs that use lists, dictionaries, and tuples. With lists, you created a progress bar using lapis lazuli and glass. Using tuples, you learned a quicker way to set the x, y, and z variables. And dictionaries allowed you to store the coordinates of things you’ve built and then teleport to them by entering their names.

In Chapter 10, you’ll further develop your knowledge of lists by learning about for loops. You’ll create some very cool programs, including one that you can use to duplicate items you’ve built.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.212.99