The goal of this assignment is to work with scripts and packages in Python.
You will be doing your work in Python for this assignment. You may choose to work on this assignment on a hosted environment (e.g. tiger) or on your own local installation of Jupyter and Python. You should use Python 3.8 or higher for your work. To use tiger, use the credentials you received. If you work remotely, make sure to download the .py files to turn in. If you choose to work locally, Anaconda is the easiest way to install and manage Python. If you work locally, you may launch Jupyter Lab either from the Navigator application or via the command-line as jupyter-lab
.
In this assignment, we will again be working with data from Pokémon compiled from online sources. As with Assignment 3, we will be using the Complete Pokemon Dataset collected by Mario Tormo Romero from online sources. Rather than using this dataset directly, I have created a subset of this data, which can be read into a list of dictionaries. That data is located here; it is updated from Assignment 3 with the addition of sp_attack
and sp_defense
so download the new one. Once loaded, the data is a list of dictionaries where each dictionary has 12 key-value pairs. Those keys and a brief description are:
name
: the namegeneration
: the generation (1-8)species
: the species (e.g. Lizard Pokémon)primary_type
: the primary type (e.g. Grass, Fire)hp
: base hit pointsheight_m
: height in metersweight_kg
: weight in kilogramsspeed
: base speedattack
: base attackdefense
: base defensesp_attack
: special attacksp_defense
: special defenseYou will be writing Python modules, putting them in a package, and writing a script to help analyze this data. You may use other core Python modules (e.g. collections) in this assignment.
The assignment is due at 11:59pm on Friday, March 5.
You should submit the completed Python files required for this assignment on Blackboard. Zip the files together; the filename of the zipfile should be a5.zip
. You can create an archive on tiger (assuming at a directory above the package) using the following code:
import shutil
'a5', 'zip', '.', 'pokemon_analysis') shutil.make_archive(
Then, download the a5.zip to turn in via Blackboard.
Please make sure to follow instructions to receive full credit. To test your code, you may use the %run
magic command in the notebook. For example,
%run pokemon.py
%run -m pokemon_analysis
You may also use the Terminal in Jupyter on tiger, but you should activate the correct environment by first running:
$ conda activate py38
Since we are using Python files (.py) files for this assignment, add the identifying information to the beginning of your __main__.py
script and the __init__.py
file of your package. Minimally, you should have a line for your name and a line for your Z-ID. If you wish to add other information (the assignment name, a description of the assignment), you may do so after these two lines.
Create three new Python modules, one for reading the dataset, one for analyzing generations, and one for comparing two Pokémon characters. Put the three modules (data.py
, generation.py
, and compare.py
) into a package named pokemon_analysis
.
Create a data.py
module that has a get_data
method that reads and parses the pokemon.json datafile, and stores it in a module variable. Assume that the data file resides in the same directory as data.py
. You can then get its absolute path via the __file__
variable of the module via:
import os
= os.path.join(os.path.dirname(__file__),'pokemon.json') fname
Use the json module to load the data from the file. Your get_data
method should only read the file from disk once, otherwise returning the pre-loaded data.
%autoreload
to automatically reload modules as you edit them. Do note, however, that this will mask the effects of trying to not keep reloading the data! You can also use importlib.reload
to do this manually.Create a generation.py
module that has two methods that both take one parameter, the generation number. Use the get_data
method from the data module to obtain the data. The first method, generation_types
, should return a dictionary of the form {<primary_type>: <count>}
with the counts of primary types for the given generation. The second method, generation_ranges
, should return a dictionary of the form {<measure>: (<min_value>,<max_value)}
with the minimum and maximum values for hp
, attack
, and defense
, among all pokemon in that generation.
collections.Counter
for generation_types
.collections.defaultdict
to help with generation_ranges
.Create a compare.py
module calculates comparative information between two Pokemon. Again, use the get_data
method from the data module to obtain the data. Given two names as parameters, the attack_diff
, defense_diff
, and hp_diff
methods should return the difference as a float between the two pokemons in the representative values (the first minus the second). Do this remembering the DRY principle! Finally, the combat_power_diff
method will comapre the combat power of two pokemons, again returning the difference as a float. The combat power can be computed via information here as (note: there was a typo, now fixed, in the formula until 2021-02-28):
Attack = 2 * round(attack^0.5 * sp_attack^0.5 + speed^0.5)
Defense = 2 * round(defense^0.5 * sp_defense^0.5 + speed^0.5)
Stamina = 2 * hp
MaxCP = (Attack + 15) * (Defense + 15)^0.5 * (Stamina + 15)^0.5 * 0.7903001^2 / 10
attack_diff
, defense_diff
, and hp_diff
, can all use.Make sure all three analysis modules live in a single pokemon_analysis
package. Add an __init__.py
file for completeness. It may contain documentation and the pass keyword.
Add a __main__.py
file that allows the package to embed a top-level script. That script should process two subcommands; the first is “generation” and the second is “compare”. The first subcommand takes a generation number as an argument and prints the result from the generation_range
(fixed typo, 2021-03-02) method, and the second subcommand takes the names of two Pokémon as arguments and prints the result from the combat_power_diff
method. You can test your script via the IPython magic command %run -m pokemon_analysis ...
or via the shell command !/opt/conda/envs/py38/bin/python -m pokemon_analysis ...
(you will need to adjust the path if not using tiger). Note that for %run
, you will need to make sure the package also has an __init__.py
file (a good habit anyway). Make sure to print a usage method if the user misses or provides incorrect arguments. Some sample output:
%run -m pokemon_analysis
Usage: python -m pokemon_analysis [generation <num> | compare <name1> <name2>]
%run -m pokemon_analysis generation
Usage: python -m pokemon_analysis [generation <num> | compare <name1> <name2>]
%run -m pokemon_analysis generation 3
Generation 3:
hp: 1.0-170.0
attack: 15.0-180.0
defense: 20.0-230.0
%run -m pokemon_analysis compare Mewtwo Magikarp
Mewtwo has +3882.048635 combat power than Magikarp
%run -m pokemon_analysis compare Mewtwo Slaking
Mewtwo has -227.238909 combat power than Slaking