report

Build A Defuse the Bomb Game Using Python and Raspberry Pi

Not Your Ordinary Hello World Tutorial

I don't know about you, but as I've been teaching myself how to program, I keep coming across the same types of tutorials in every language: 'Hello World' and 'How to Make an Address Book'. While these are both great for learning the fundamentals, I don't enjoy arbitrary projects, even if it is teaching me.

When I got my Raspberry Pi 2 last year, I decided I was going to learn Python with it and I certainly wasn't going to just do 'Hello World' tutorials. The result of my project is a game that takes user input from buttons on my breadboard using the GPIO pins. In this tutorial, we will recreate this game and try to learn what exactly we are doing with each line of code, instead of just copying and pasting and playing a simple game in the end.

The Pi

Let's get started.

I'm doing this all on a Raspberry Pi 2 running Raspbian Jessie. The Pi is connected to my local network via ethernet cable (if you have the WIFI adapter, that'll work just as well) and I am ssh'd into it from my MacBook Pro. You can do this all locally on the Pi if you have it connected to a monitor, keyboard and mouse.

The Breakout Board

Let's get our breakout board all set up. If you don't know, the board goes top to bottom the long way. Each horizontal row is the same connection, so anything next to one another horizontally, will have power at the same time.

I've included an image of my actual breakout board and a digital rendition of the general idea. The digital design was made in Fritzing software. It is not a perfect rendition as it did not offer the option to include the cobbler, but it gets the point across.

The LED's are connected as follows. Red is connected positive to pin 27 and negative to 3V negative through a 220 Ω (Red, Red, Brown, Gold color code) resistor. Be sure you use a resistor or you'll likely blow out your LED. Green is connected positive to pin 22 and negative to 3V negative through a 220 Ω resistor. The top button is connected positive to 17 and negative to ground. The bottom button is connected positive to 18 and negative to ground.

Red wire goes to Red LED and Green Wire goes to Green LED. Black wires are positive to the buttons and White wires are grounds.
Red wire goes to Red LED and Green Wire goes to Green LED. Black wires are positive to the buttons and White wires are grounds.

The Code: Big Picture

Let's start by talking about what our end goal is. When the game is started, it will show a paragraph on the terminal screen telling the story of coming across a time bomb. As the only person around, it falls to the player to decide if they should cut the red wire or the blue wire (in this case the wires are the buttons on the breakout board). When the user pushes a button, it flashes either a red or green light and a congratulations or failure message on the screen.

In order to make this game truly random, we use a random number generator and some basic math in order to determine which button is the correct one and which one will result in the death of many innocent bystanders.

The Code: Imports

OK, let's get to the fun stuff.

First we need to import the frameworks we will use in this game: random, time and gpio.

#Import frameworks
from random import randint
import RPi.GPIO as GPIO
import time

I always include comments to make sure that when I go back later (or if anyone ever sees this), I remember what each block does.

In order to limit the size and computing requirements, we only import the randint portion of the random framework. This isn't that big of a deal in a program as small as this one will be, but a good practice to get into.

To make interaction with the GPIO framework easier, we import it as GPIO. GPIO is now a variable that prevents us from writing RPi.GPIO every time; you could change the variable name to anything you want.

We need to have a few seconds where we delay or wait during this game, so we import time.

The Code: GPIO Setup

Now we have to tell the Pi what pins we will be using for this project. Remember, for this project we are not connecting direct to the components, but are mapping it through a breakout board by a CanaKit 40-pin T-shaped cobbler.

#GPIO Setup
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP) #Top Button
GPIO.setup(18, GPIO.IN,pull_up_down=GPIO.PUD_UP) #Bottom Button
GPIO.setup(27, GPIO.OUT) #Red
GPIO.setup(22, GPIO.OUT) #Green

First off, we disable the GPIO warnings. The code will work without this line, but you'll get a warning every time you run it, so it's best just to ignore it.

Now we have to tell the code that we are mapping it to the breakout board. I'll be honest, I don't fully understand this part, I just no we need to include this line of code to help our numbers line up.

The last 4 lines all do the same thing, they tell the Pi what pins we are using and what time of device is on the other end of the pin's circuit: input or output.

The Code: Game Function

Now we get to create a function. Let's talk about functions for a minute. Functions take a lot of instructions and turn them into a single 'variable' (not the right terminology, but go with me on this) that you can call later. In this case, we tell the program what the game is, but we don't let it run until we are ready for it. This also allows us to stop the game or add extra functionality if we want to later.

As this function is really long, I'm going to break the code segments out into shorter segments. Remember is all part of the game function. I'll include the full function code as well as the full program code later. But I don't want to overwhelm anyone with a bunch of code all at once.

def game():

First we define our function and give it a name. I chose to be really creative here and name it game.

	#Random Number
	x = randint(0,9)
	#Determine if number is even or odd
	y = x%2

Now we choose a number. Because we used randint, the number will be an integer (that means no decimals for those of you who hate math) and in the parenthesis, we pass 0, 9 as the arguments. In this case, that makes the range of integers 0-9. Realistically, we could do (1, 2) and limit the integer to 1 or 2, but we're doing this to increase our learning so let's go with 0-9.

Now we have to get it down to a 50/50 option. I chose to do this by determining if the number was even or odd. To do this we use a function called modulo, represented by %. Again, for you non-math folks, modulo returns the remainder of a division problem so 27 / 5 = 5 remainder 3 and 27 % 5 = 3. This can determine odd or even because we know that if any even number divided by 2 has no remainder, therefore any even number modulo 2 is 0.

In this case x is our random integer, so we'll make y our equation to determine odd or even. So y is x % 2, meaning the only possible results y could yield are 0 or 1. Now we have our 50/50 option.

	#Story
	print "You are casually walking down the street one day when out of nowhere you notice a ticking time bomb, ready to explode. You immediately remember your bomb squad days and rush into action. You have the bomb nearly defused, but you must now choose: red wire or blue wire. You have 10 seconds."
	time.sleep(1)
	print "Choose wisely"

Every good game needs a story. Here we just output the story through plain text to the terminal window. Then we wait 1 second and then tell the user to choose wisely.

	#Button Controls
	while (GPIO.input(17) == True or GPIO.input(18) == True): #Listen for input from buttons
		topButton = GPIO.input(17)
		bottomButton = GPIO.input(18)
		if (topButton == False): #Top Button Pressed
			if (y == 0): #If the number was even and you pushed the top button, you lose
				print("You have failed. Countless people have died due to your incompetence and you have been reduced to nothing but a few subatomic particles that are barely visible to the human eye.")
				GPIO.output(27,GPIO.HIGH)
				time.sleep(.3)
			else: #If the number was odd and you pushed the top button, you win.
				print ("Well done! You have successfully defused the bomb and saved many lives. You are an international hero!")
				GPIO.output(22,GPIO.HIGH)
				time.sleep(.3)

Now the code for the buttons. Keep in mind that when a button is pushed it returns false. When not pushed, it is true. To me it seems a little backwards, but it was designed by someone smarter than me.

This game will run in a while loop that says while one of the buttons are un-pushed, the Pi will continue to wait for input.

To make the code easier, I've declared each GPIO button input as an english named variable so it don't have to remember which number is which. The variables 'topbutton' and 'bottombutton' correspond to their location on the breakout board.

Now we use an if/elif statement. I've broken it out between 2 segments here to make it easier to read. The top button will win if the user pushes it and the random number from earlier is odd. If they push the top button and the number is even, they lose. So we say if the user touches the top button, then we check if y is equal to 0 (random number was even) then it prints out the losing message and turns on the red light. Otherwise (so y is 1 or random number was odd) it displays the winning message and turns on the green light.

This is the first time we've used the GPIO.output feature. In the case of LED's, we either output HIGH for on or LOW for off. Since we set up GPIO as a variable earlier, we can just say GPIO.output(pin number, HIGH or LOW) to turn the light on or off.


The time.sleep(.3) stops the computer from filling your screen with thousands of victory or failure messages. It gives you enough time to get your finger off the button.

		elif (bottomButton == False): #Button Button Pressed
                	if (y == 1): #If the number was odd and you pushed the bottom button, you lose.
                        	print("You have failed. Countless people have died due to your incompetence and you have been reduced to nothing but a few subatomic particles that are barely visible to the human eye.")
				GPIO.output(27,GPIO.HIGH)
				time.sleep(.3)
                	else: #If the number was even and you pushed the bottom button, you win.
                        	print ("Well done! You have successfully defused the bomb and saved many lives. You are an international hero!")
				GPIO.output(22,GPIO.HIGH)
				time.sleep(.3)
		time.sleep(.3) #Leave the light on for .3 second
		GPIO.output(22,GPIO.LOW) #Turn off Green
		GPIO.output(27,GPIO.LOW) #Turn off Red

Now we do the same calculation, except for the bottom button. This section is ignored if the top button is pushed and the previous section is ignored if the bottom button is pressed. That's the beauty of if statements.

Notice we are using an elif statement instead of just and else. Else would accept any input except pushing the top button, so it would run if nothing was pushed. We however want it to only run if we have pushed one button or the other, thus we use elif.

After the calculations to determine if the player won or lost and the .3 second wait time, the Pi will shut off both LED's. There should only be 1 LED on, either red or green depending on if the game is won or lost, but it doesn't hurt to shut off one that is already off, the Pi will make no change. This just guarantees a light isn't left on after the game is done.

	print "Exiting Game"
	return

Remember I said this was a loop that ran as long as at least 1 button was not pushed? Well when you push both buttons, that will exit the loop and end the program. Here we print to the terminal window that the game is closing. The return command actually ends the program.

The Full Game Function

def game():
	#Random Number
	x = randint(0,9)
	#Determine if number is even or odd
	y = x%2

	#Story
	print "You are casually walking down the street one day when out of nowhere you notice a ticking time bomb, ready to explode. You immediately remember your bomb squad days and rush into action. You have the bomb nearly defused, but you must now choose: red wire or blue wire. You have 10 seconds."
	time.sleep(1)
	print "Choose wisely"

	#Button Controls
	while (GPIO.input(17) == True or GPIO.input(18) == True): #Listen for input from buttons
		topButton = GPIO.input(17)
		bottomButton = GPIO.input(18)
		if (topButton == False): #Top Button Pressed
			if (y == 0): #If the number was even and you pushed the top button, you lose
				print("You have failed. Countless people have died due to your incompetence and you have been reduced to nothing but a few subatomic particles that are barely visible to the human eye.")
				GPIO.output(27,GPIO.HIGH)
				time.sleep(.3)
			else: #If the number was odd and you pushed the bottom button, you win.
				print ("Well done! You have successfully defused the bomb and saved many lives. You are an international hero!")
				GPIO.output(22,GPIO.HIGH)
				time.sleep(.3)
		elif (bottomButton == False): #Button Button Pressed
                	if (y == 1): #If the number was odd and you pushed the bottom button, you lose.
                        	print("You have failed. Countless people have died due to your incompetence and you have been reduced to nothing but a few subatomic particles that are barely visible to the human eye.")
				GPIO.output(27,GPIO.HIGH)
				time.sleep(.3)
                	else: #If the number was even and you pushed the bottom button, you win.
                        	print ("Well done! You have successfully defused the bomb and saved many lives. You are an international hero!")
				GPIO.output(22,GPIO.HIGH)
				time.sleep(.3)
		time.sleep(.3) #Leave the light on for .3 second
		GPIO.output(22,GPIO.LOW) #Turn off Green
		GPIO.output(27,GPIO.LOW) #Turn off Red

	print "Exiting Game"
	return

The Code: Call the Function

Now that the function is finally written, we can call it and play the game. There are no arguments needed for this function. We just call it so that the Pi knows it is time to play.

game()

The Whole Code

#Import frameworks
from random import randint
import RPi.GPIO as GPIO
import time

#GPIO Setup
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP) #Top Button
GPIO.setup(18, GPIO.IN,pull_up_down=GPIO.PUD_UP) #Bottom Button
GPIO.setup(27, GPIO.OUT) #Red
GPIO.setup(22, GPIO.OUT) #Green


def game():
	#Random Number
	x = randint(0,9)
	#print(x)
	#Determine if number is even or odd
	y = x%2

	#Story
	print "You are casually walking down the street one day when out of nowhere you notice a ticking time bomb, ready to explode. You immediately remember your bomb squad days and rush into action. You have the bomb nearly defused, but you must now choose: red wire or blue wire. You have 10 seconds."
	time.sleep(1)
	print "Choose wisely"

	#Button Controls
	while (GPIO.input(17) == True or GPIO.input(18) == True): #Listen for input from buttons
		topButton = GPIO.input(17)
		bottomButton = GPIO.input(18)
		if (topButton == False): #Top Button Pressed
			if (y == 0): #If the number was even and you pushed the top button, you lose
				print("You have failed. Countless people have died due to your incompetence and you have been reduced to nothing but a few subatomic particles that are barely visible to the human eye.")
				GPIO.output(27,GPIO.HIGH)
				time.sleep(.3)
			else: #If the number was odd and you pushed the bottom button, you win.
				print ("Well done! You have successfully defused the bomb and saved many lives. You are an international hero!")
				GPIO.output(22,GPIO.HIGH)
				time.sleep(.3)
		elif (bottomButton == False): #Button Button Pressed
                	if (y == 1): #If the number was odd and you pushed the bottom button, you lose.
                        	print("You have failed. Countless people have died due to your incompetence and you have been reduced to nothing but a few subatomic particles that are barely visible to the human eye.")
				GPIO.output(27,GPIO.HIGH)
				time.sleep(.3)
                	else: #If the number was even and you pushed the bottom button, you win.
                        	print ("Well done! You have successfully defused the bomb and saved many lives. You are an international hero!")
				GPIO.output(22,GPIO.HIGH)
				time.sleep(.3)
		time.sleep(.3) #Leave the light on for .3 second
		GPIO.output(22,GPIO.LOW) #Turn off Green
		GPIO.output(27,GPIO.LOW) #Turn off Red

	print "Exiting Game"
	return
game()

Video Demonstration

Below I've included a video that shows both the Terminal screen and the LED's and buttons. There is one extra feature on this that is not covered in our tutorial. There is a blinking light that is a countdown limiting the time that the player has to make a choice. At some point, I may make a tutorial on how to add this feature, but as it is not working perfectly yet, I'm just going to leave that part out for now.

Comments

No comments yet.

    Sign in or sign up and post using a HubPages Network account.

    0 of 8192 characters used
    Post Comment

    No HTML is allowed in comments, but URLs will be hyperlinked. Comments are not for promoting your articles or other sites.


    Click to Rate This Article

    Menu

    Explore