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.10 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 24.
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 py3.10
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:
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
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/py3.10/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