$29
1 Overview
In this project, you will be building a simple text based Pokemon battle simulation. You will have 2 players pick a team of Pokemon from a list to battle them against each other, and one player will win. You will also implement support for saving the game and resuming later (like when mom tells you to pause your online games).
2 Background Info
2.1 The Pokemon Struct
The Pokemon struct is defined as follows in pokemon.h:
typedef struct {
int id;
char name[20];
unsigned int stats;
type_t type;
} pokemon_t;
Each Pokemon has four stats, which are all packed into a single unsigned int value. The stats are Health (bits 31-21) Attack (bits 20-14), Defense (bits 13-7), Accuracy (bits 6-0). We will write a way to handle this later.
There is also an enum defined for types in pokemon.h
typedef enum {
FIRE,
GRASS,
WATER
} type_t;
2.2 Game State Struct
We will allow players to give their names and select their Pokemon, we need to store this information as a battle plays out so that we can save the game state later. This struct is defined as follows in game.h:
typedef struct {
char p1_name[10];
char p2_name[10];
pokemon_t p1_pokemon[3];
pokemon_t p2_pokemon[3];
int turn;
int player_turn;
int game_over;
int winner;
} gamestate_t;
3
2.3 Flowchart of the Game
Don’t worry about understanding this entirely right now. Just look it over and get a feel for the way our Pokemon game is going to work.
3 Instructions
3.1 Packing and Unpacking Pokemon Stats
The first thing you will want to do is fill in the macros to pack and unpack the stats for a given Pokemon. As mentioned above, all Pokemon stats are packed into a single integer to save space. We will write some macros to easily get and set a given stat. In the provided pokemon.h, there are eight macros that you need to define, for each stat, there will be two macros:
#define UNPACK_STAT(stats) // Gets stat shifted to right most position #define PACK_STAT(stats, stat) // Sets stat
Ex:
#define UNPACK_HEALTH(stats)
#define PACK_HEALTH(stats, new_health)
There will also be a macro to create a stats value from the four stats passed in:
#define PACK_ALL_STATS(health, attack, defense, accuracy)
UNPACK_STAT should return the portion of the stat block for a specific stat, and PACK_STAT will take the stats value passed in and overwrite the correct set of bits so that the returned value represents the new stat. Stats will never be negative. You should use shifting and bitwise operations to pack and unpack values from the stats variable.
Your work for these macros can be tested via the autograder. See the autograder section for more details.
4
3.2 Reading The List of Pokemon
The next thing you need to get working is reading in the list of Pokemon from the CSV. This will be done in the function read_csv in pokemon.c.
You will be given the list of possible Pokemon as a CSV file called pokemon.csv. You are to read this file in and turn each entry into a Pokemon struct. The function will take in the name of a CSV file and an array to fill. The array should be populated with every Pokemon in the CSV, in order. More details will be given in a comment above the function.
The format of the CSV will be:
id,name,type,health,attack,defense,accuracy
Hint: Some useful C library functions to explore: fopen, fscanf, fclose, strtok, strcpy, strtoi.
Once again, you can test your work for this portion of the assignment with the autograder.
3.3 Sorting the List of Pokemon
Oh no! The list of Pokemon you just read in through read_csv is out of order! The next thing to complete is sorting the list of Pokemon. We need to sort the array of Pokemon by id so later we are able to select a Pokemon by indexing into the array by its id. You can sort the array using any method and you are guaranteed no duplicates. This will be done in the function sort_pokemon which takes two parameters, the length of the array and the array to be sorted.
Note: The sort should be done in-place
You can test this function via the autograder as well!
3.4 Implementing Attacks
Now that we have our sorted Pokemon, or our pokedex. We need to write a function to decide the outcome of an attack. The attack function in pokemon.c will take in 2 pointers to Pokemon. This is a simulation of the first Pokemon attacking the second Pokemon.
The implementation of attack is as follows:
Generate a random number between 1 and 100, and compare it to the attacker’s accuracy. If the number is below the accuracy, the attack hits, continue. Otherwise, they missed, exit with return value 0. Hint: Use rand() from the C library to generate this random number, and use a modulus and addition to make it in the range you want. Do not seed rand or it will break the autograder.
Lower the second Pokemon’s health by pokemon1's attack - pokemon2's defense. The minimum attack damage for our game is 5, so if this calculation results in a damage less than 5, deal 5 damage instead.
Here, you should also consider Pokemon types.
– If a grass type Pokemon attacks a water type Pokemon, it should do double the attack.
– If a grass type Pokemon attacks a fire type Pokemon, it should do half the attack (integer division, e.g. round down).
– If a water type Pokemon attacks a fire type Pokemon, it should do double the attack.
– If a water type Pokemon attacks a grass type Pokemon, it should do half the attack.
– If a fire type Pokemon attacks a grass type Pokemon, it should do double the attack.
– If a fire type Pokemon attacks a water type Pokemon, it should do half the attack.
5
– Otherwise do normal damage.
– Note: Double and halve the attack before calculating damage.
Exit with return value 0 if the defender survived, with return value 1 if the defender did not.
Note: Since the arguments are pointers to Pokemon, you should be directly modifying the defender’s Pokemon as a result of the attack.
See this flowchart for another explanation of the function:
Once again, this function can be tested individually via the autograder!
3.5 Save and Load State
Before we are ready to implement the main logic of our Pokemon game, we need to write some helper functions to save and load game state.
6
3.5.1 Save State
Fill in the save_state function in game.c. This function should save the state of the game as a text file (<p1_name_<p2_name.save) in the following format:
Player1.name
Player1.pokemon1.id
Player1.pokemon1.health
Player1.pokemon2.id
Player1.pokemon2.health
Player1.pokemon3.id
Player1.pokemon3.health
Player2.name
Player2.pokemon1.id
Player2.pokemon1.health
Player2.pokemon2.id
Player2.pokemon2.health
Player2.pokemon3.id
Player2.pokemon3.health
Current_Turn (0 or 1, for players 1 and 2 respectively)
This function can be tested individually via the autograder as well!
3.5.2 Load State
Now that we have the ability to save the state, what good would that be without the ability to load a state from a given file. You should implement load_state in game.c, which should update the gamestate_t struct to the state specified by the file. There are two parameters to this function, the file name, and the game state struct to be updated. This function will essentially have the opposite logic of save_state—plus it may need to look up some additional details about each Pokemon in the pokedex!
This function is also individually autograded.
3.6 Main Function
Now that we have the ability to read in Pokemon, sort them, and calculate the result of an attack, we are ready to implement the main logic of our game! You should implement my_main in game.c. This should go through the state of the game, via the flowchart above. Function my_main works just like a main function, and has 2 parameters, argc the number of command line arguments + 1, and argv, a char pointer array of all the strings passed as command line arguments. This will emulate a C main function, but for grading purposes, will only fake being one.
A game should play out like this:
Read the CSV file specified by argv[1]
If argv[2] exists, load state from the save file specified by argv[2] and continue game
Player one enters a name (string)
Player two enters a name (string)
Player one enters their first Pokemon by id (integer)
Player two enters their first Pokemon by id (integer)
7
Player one enters their second Pokemon by id (integer)
Player two enters their second Pokemon by id (integer)
Player one enters their third Pokemon by id (integer)
Player two enters their third Pokemon by id (integer)
Begin battle loop
– Current player chooses attack (input: 1) or save (input: 2) (integer)
– If attack
Get attacking player’s first Pokemon with remaining health
Get defending player’s first Pokemon with remaining health
Call attack with attacking and defending Pokemon
If all three of the defending player’s Pokemon are now out of health, the attacking player won! You should print out some notification of the victory, indicate who won, and then exit.
Otherwise, go to next player’s turn
– If save, call save_state with current state and exit the game
3.6.1 Requirements
– The order in which you expect parameters should be exactly as listed above.
– You should descriptively explain what is happening throughout the game by printing messages. You have the freedom to write your messages in your own way but make sure that your main function informs players what is going on.
– As with output messages, prompts for input are not graded to match our examples. However, they should be descriptive so a TA can understand what is going on.
– All input will be valid, meaning that it will be the expected type. However, if you ever receive an input outside of the allowed range, you should re-prompt before continuing.
Examples:
After an successful attack:
"Player1's PokeName1 (Fire) attacked Player2's PokeName2 (Water) and did 20 damage!"
After a Pokemon is defeated:
"Player2's PokeName2 (Water) defeated Player1's PokeName1 (Fire)!"
"Remaining Pokemon: Player1 (1), Player2 (2)"
This is the only function in the entire project that is not autograded for correctness. This function will be graded while a TA plays your game in demos!
4 Notes
4.1 General Notes
You are allowed to define any helper functions you want!
We have provided some includes, but if you feel the need to include some other standard libraries, feel free.
You are allowed to modify suites.c. This includes adding your own test cases, printing things, or adding assertions. This does not change the autograder on Gradescope.
8
5 Autograder
5.1 Autograder
Since we no longer need a GUI, instead of running ./cs2110docker.sh, try running ./cs2110docker.sh -it to enter the Docker terminal within your normal terminal! You can then type exit to return to your host terminal.
You can then run the autograder by running the command make tests. Be sure to do this inside a Docker terminal and not on your host machine!
All of these commands should be run inside a Docker terminal.
Manually compile your code by running make pokemon inside your Docker terminal, in the same di-rectory as your .c files and Makefile.
Manually execute your code by running ./pokemon. Make sure you have previously compiled your code with make pokemon and are in the same directory as pokemon.
You can run a single test case by running the command make tests && ./tests test_name where test_name is the name of the test you want to run.
You can run GDB by executing the command make run-gdb which will launch your program in GDB.
To run your my_test function, you should execute make debug and then ./pokemon
6 Deliverables
Turn in the files game.h, game.c, pokemon.h, and pokemon.c to Gradescope by the due date. Do not submit any other files.
Note: Please do not wait until the last minute to run/test your project, history has proved that last minute turn-ins will result in long queue times for grading on Gradescope. You have been warned.
7 Rules and Regulations
7.1 General Rules
Although you may ask TAs for clarification, you are ultimately responsible for what you submit. This means that (in the case of demos) you should come prepared to explain to the TA how any piece of code you submitted works, even if you copied it from the book or read about it on the internet.
Please read the assignment in its entirety before asking questions.
Please start assignments early, and ask for help early. Do not email us the night the assignment is due with questions.
If you find any problems with the assignment it would be greatly appreciated if you reported them to the author (which can be found at the top of the assignment). Announcements will be posted if the assignment changes.
9
7.2 Submission Conventions
When preparing your submission you must submit the files individually to Gradescope.
Do not submit links to files. The autograder does not understand it, and we will not manually grade assignments submitted this way as it is easy to change the files after the submission period ends.
7.3 Submission Guidelines
You are responsible for turning in assignments on time. This includes allowing for unforeseen cir-cumstances. If you have an emergency let us know IN ADVANCE of the due time supplying documentation (i.e. note from the dean, doctor’s note, etc). Extensions will only be granted to those who contact us in advance of the deadline and no extensions will be made after the due date.
You are also responsible for ensuring that what you turned in is what you meant to turn in. After submitting you should be sure to download your submission into a brand new folder and test if it works. No excuses if you submit the wrong files, what you turn in is what we grade. In addition, your assignment must be turned in via Canvas/Gradescope. Under no circumstances whatsoever we will accept any email submission of an assignment. Note: if you were granted an extension you will still turn in the assignment over Canvas/Gradescope.
Projects turned in late receive zero credit. You alone are responsible for submitting your project before the assignment is due; neither Canvas/Gradescope, nor your flaky internet are to blame if you are unable to submit because you banked on your computer working up until 11:54PM. The penalty for submitting after the assignment is due is non-negotiable.
7.4 Syllabus Excerpt on Academic Misconduct
Academic misconduct is taken very seriously in this class.
Students are expected to have read and agreed to the Georgia Tech Honor Code, see http://osi.gatech.edu/content/honor-code.
Suspected plagiarism will be reported to the Division of Student Life office. It will be prosecuted to the full extent of Institute policies.
A student must submit an assignment or project as his/her own work (this is what is expected of the students).
Using code from GitHub, via Googling, from Stack Overflow, etc., is plagiarism and is not permitted. Do not publish your assignments on public repositories (i.e., accessible to other students). This is also a punishable offense.
Although discussion among the students through piazza and other means are encouraged, the sharing of work is plagiarism. If you are not sure about it, please ask a TA or stop by the instructor’s office during the office hours.
TAs and Instructor determine whether the project is plagiarized. Trust us, it is really easy to determine this....
7.5 Is collaboration allowed?
Collaboration is allowed on a high level, meaning that you may discuss design points and concepts relevant to the homework with your peers, share algorithms and pseudo-code, as well as help each other debug code. What you should not be doing, however, is pair programming where you collaborate with each other on a
10
single instance of the code. Furthermore, sending an electronic copy of your homework to another student for them to look at and figure out what is wrong with their code is not an acceptable way to help them, because it is frequently the case that the recipient will simply modify the code and submit it as their own. Consider instead using a screen-sharing collaboration app, such as http://webex.gatech.edu, to help someone with debugging if you’re not in the same room.
11