Have you ever wanted to play a Pokemon game in your terminal? In this workshop, we'll learn about file and exception handling, random sampling, and code organization!
Setting up
You can install Python locally on your computer or use repl.it, a free, online IDE, to write the code for this project. Start a new Python file here.
Once you have your Python file open, let's import three libraries!
import random as rand
import time
import sys
-
random
will allow us to sample random Pokemon names, tell us whether we caught a Pokemon or not, and give us randomized time between Pokemon appearances! -
time
will help us delay the program between Pokemon spawns. -
sys
will help us exit the program before all of the code executes.
Next, we need a list of all of the available Pokemon! Luckily, a GitHub user by the name of @cervoise has a list of 721 Pokemon names. You can download the .txt
file here. In repl.it, you can copy and paste the contents into a new file.
We can open a file with the open()
function. The first required argument is the file name, I have the .txt
file stored with the name allpokemon.txt
in the same directory as the Python file. The second required argument refers to the permissions that we open it with. Since we only need to scrape its contents, we can use the permision "r", signifying "read".
Calling readlines()
on a file object splits content on different lines as list elements.
file = open('allpokemon.txt', 'r')
all_pokemon = file.readlines()
Now, we'll create an owned Pokemon list which keeps track of the Pokemon we caught.
owned_pokemon = []
Pokemon Catching
Let's start having pokemon appear! We can force the user to enter a valid response by asking them again (possibly forever) whenever they don't give us the input we're expecting. Since we want a Pokemon to spawn when the loop starts, we can have the program print this information.
while True:
print('\nA pokemon has appeared!\n')
So, what Pokemon actually spawned? We can randomly choose a Pokemon by sampling our list of Pokemon with random.choice()
. Once we select the appearing Pokemon, we should also strip()
the name. This is because readlines()
retains escape characters, so it would leave a newline after its name, which we don't want. To provide emphasis, we can also convert its entire name to uppercase with .upper()
(optional).
Finally, we can tell the user which Pokemon has appeared before them.
current_pokemon = rand.choice(all_pokemon).strip().upper()
# \n is an escape character which moves on to the next line. This helps the output stay organized.
# Again, whether you want to include this is entirely up to you!
print("It's a", current_pokemon + '!\n\n')
Intuitively, the user might want to catch this Pokemon. So, we can set up another while True:
loop to take care of that. We'll collect user input with input()
. We'll also give the user three pokeballs to throw and a 33% chance to catch it.
Notice that we make the input lowercase to avoid case-sensitivity.
catches_left = 3
while True:
catch_state = input('Would you like to catch it? (y/n)')
if catch_state.lower() == 'y' or catch_state.lower() == 'yes':
pass
elif catch_state.lower() == 'n' or catch_state.lower() == 'no':
pass
else:
print('\nValid input is y, yes, n, or no')
Let's write some logic.
- If we don't have any more catches, we can break.
- We'll use
random.randint()
to get a random number. If it's less than or equal to 33 (33% chance), we can add it to our owned pokemon and break. If we can't catch it, we can subtract one from our catches. - If the user doesn't want to catch it, we can break.
while True:
print('\nA pokemon has appeared!\n')
current_pokemon = rand.choice(all_pokemon).strip().upper()
# \n is an escape character which moves on to the next line. I feel like this helps the output stay organized.
# Again, whether you want to include this is entirely up to you!
print("It's a", current_pokemon + '!\n\n')
catches_left = 3
while True:
catch_state = input('Would you like to catch it? (y/n)')
if catch_state.lower() == 'y' or catch_state.lower() == 'yes':
# no more catches left:
if catches_left <= 0:
print('You weren\'t able to catch the pokemon. ')
break
else:
catch = rand.randint(1, 100)
if catch <= 33:
owned_pokemon.append(current_pokemon)
if owned_pokemon not in owned_pokemon:
print('\n\nYou got a new Pokemon!\n\nAdding it to the pokedex...')
break
else:
catches_left -= 1
print('\nIt jumped out, try again!')
elif catch_state.lower() == 'n' or catch_state.lower() == 'no':
print('Bye', current_pokemon + '!')
break
else:
print('\nValid input is y, yes, n, or no')
Lastly, we should give some options to the user (you can always add your own!).
- View owned Pokemon
- View Pokedex (unique Pokemon)
- Save file
- Exit
- Quit Program
We can print out these options first,
print('\n\nWould you like to see owned pokemon or your pokedex?\n')
print('O = Owned Pokemon')
print('P = Pokedex')
print('U = Update both to a file!')
print('N = Exit')
print('S = Exit Program\n')
and pull out our trusty while loop for inputs. (sys.exit()
exits the program)
while True:
choice = input('Pick your choice!')
if choice.lower() == 'o':
pass
if choice.lower() == 'p':
pass
if choice.lower() == 'u':
pass
if choice.lower() == 'n':
break
if choice.lower() == 's':
sys.exit()
If the user wants to see their owned pokemon, we can print out the owned_pokemon
list:
if choice.lower() == 'o':
print(owned_pokemon)
If the user wants to view their Pokedex (unique pokemon), we can plug the owned_pokemon
into a set (which doesn't allow duplicate values.
if choice.lower() == 'p':
print(set(owned_pokemon))
Save File Functionality
If the user wants to write to a save file, we can create the new files owned_pokemon.txt
and pokedex.txt
and write the contents from our created list to it. We'll use the set again for the Pokedex. We can create a new file by using the permission "w"; this creates a new file if it doesn't exist already. If it does, it wipes it's contents.
Remember to close the file to save it!
if choice.lower() == 'u':
print('Working on it!')
# create file
owned_pokemon_file = open('owned_pokemon.txt', 'w')
# for every caught pokemon
for i in owned_pokemon:
# write it to a file and split pokemon with new lines
owned_pokemon_file.write(i + '\n')
# close to save
owned_pokemon_file.close()
# same for pokedex
pokedex_file = open('pokedex.txt', 'w')
for i in set(owned_pokemon):
pokedex_file.write(i + '\n')
pokedex_file.close()
print('\nDone! View them in your explorer tab.')
At this point, we just have to set up a random wait period to spawn a new Pokemon. We can use the function time.sleep()
, with rand.randint()
to delay the program for a varying amount of time.
print('\n\nWait for a new pokemon...')
time.sleep(rand.randint(5, 10))
Lastly, we can implement save file functionality. Let's prompt the user for a save file before they start the game using a while loop.
If they don't, then we can start them off with an empty inventory and break.
If they do, we can ask them for owned_pokemon.txt
, the file that we wrote in the "Save File" part of the program. We'll open the file with "r" (read) permissions, and read every item to our list (stripping it to remove escape characters). Once we finish, we can close the file and break. To avoid any exceptions, we can wrap the file opening with a try: except:
to catch any errors. If the file doesn't exist, we encounter a FileNotFoundError
, and we can tell the user to try again.
while True:
oldsave = input('Do you have a save file? (y/n)')
if oldsave.lower().strip() == 'n':
print('\nWelcome!')
break
elif oldsave.lower().strip() == 'y':
print('\nWelcome back! Add your save file path below! (owned pokemon)')
own_file = input()
try:
own_file_start = open(own_file, 'r')
owned_pokemon = [pokemon.strip() for pokemon in own_file_start.readlines()]
own_file_start.close()
print('\nAll set!')
break
# file doesn't exist
except FileNotFoundError:
print('We had a problem processing your files, try again or start new!')
Done! Let's try running our program. Here's what happens when I run without a save file. I encountered a Toxicroak, and caught it on my second try.
When I backed it up to a file, the Pokemon was transferred successfully!
You can view the source code on GitHub!
Ways that you can hack this workshop are:
- Encrypt the saved file
- Different Pokeballs
- Shop
Happy Hacking!