The purpose of this lab is to introduce the concepts of inheritence, header files and the use of vectors.
In general, you should use the standard C++ iostream using cin for input and cout for output in your programs, unless otherwise stated.
Unlike lab 1, this lab should not be submitted to CourseMarker. Instead
your tutors will look at your work and grade you during the lab session itself. You should submit a word document with a 1 page write-up detailing your idea. In addition, copy paste ONLY your source code containing your AI to the document and submit this file to IVLE workbin.
If you have any questions, you may post your queries in the IVLE forum.
Remember to put "Ilab2" somewhere in the subject line of your forum
message.
The deadline for completing the lab
is 16 February.
While the length of this writeup can be quite intimidating, the actual length of your code may only be 70 lines (depending on how intelligent your AI is). You can skip some of the overview writeup if you are familiar with the game. The article is written with the assumption that the reader has not played the game before.
The concept of the Pokémon universe, in both the video games and the general fictional world of Pokémon, stems from the hobby of insect collecting, a popular pastime which Pokémon executive director Satoshi Tajiri-Oniwa enjoyed as a child.[8] Players of the games are designated as Pokémon Trainers, and the two general goals (in most Pokémon games) for such Trainers are: to complete the Pokédex by collecting all of the available Pokémon species found in the fictional region where that game takes place; and to train a team of powerful Pokémon from those they have caught to compete against teams owned by other Trainers, and eventually become the strongest Trainer, the Pokémon Master. These themes of collecting, training, and battling are present in almost every version of the Pokémon franchise, including the video games, the anime and manga series, and the Pokémon Trading Card Game. (wikipedia)
In this individual assignment, your task is to improve the game AI by implementing a simple Artificial Intelligence that can defeat the (provided) Stupid AI. Your AI should not accept any input from the user - but make smart decisions depending on the state of the game. You should download the fully completed game here.
You are highly encouraged to ask for ideas / clarify any doubts you have on the forum. You may post code that provide hints on how to start (e.g. iterating through all the player's Pokemons) but you may not post an obvious solution to the problem.
The gameplay itself of the actual game is very similar to this text-based game we are writing (All Pokemon statistics, damage formula are taken from the Pokemon official database). For simplicity (and fairness), we ignore the concept where a Pokemon can "level up" and improve its attributes. All our Pokemon start at level 50 and both players start with exactly the same pokemons with same attributes. Students who are familiar with the game play, or can learn by understanding code should jump to the section "Artificial Intelligence" below.
Beginning of the gameThe genre of the game is a turned based "Role Playing Game". Each player starts with the same set of pre-determined pokemon. The game is a strategy game which pits the player's Pokemon against the opponent's Pokemon. The battle starts with each player choosing a Pokemon at the same time (with each being unaware of each other's selection until starting). The battle then proceeds with several rounds, with each player taking a turn until all their Pokemon's have been defeated. (No Pokemons are ever harmed - they only become unconscious when they they are defeated). Once a player has all their Pokemons defeated, he/she lose the game.
Turn based combat
In every turn, both the players(or AI in our case) would select an action/move without knowing in advance what move the other would make. The moves a player may select is dependent on the "chosen" pokemon (which the player may select at the beginning of the battle). In general, a player may use any moves available to the chosen pokemon as long as the moves have not been exhausted yet. In addition, a player may change to a different pokemon that is still conscious.
In general, the attack moves are executed in order of the Pokemon's speed statistic. However when defending, the defending pokemon will go first and when changing, the changing player will go last. Note that to prevent stalemate situations from happening (where both players keep changing their pokemons), each player is allowed to change their Pokemon THREE times. You do not have to keep track of this - this move becomes unavailable once the player has exceeded the number of times he may change a pokemon
Once a Pokemon has been knocked unconscious, the next round will begin with the first available pokemon. This will resume until all a player's pokemon have been defeated.
Pokemon typesIn our game, each Pokemon MUST be one of three different types - GRASS, FIRE, WATER. The type of a Pokemon would influence the moves it can make (e.g. WATER pokemon gets WATER type moves - we will discuss move types in the next section). In addition, a Pokemon type affects its weakness to certain move types - since the move type of a Pokemon is dependent on its type, we can determine when a Pokemon is weak to another Pokemon by directly looking at both their type.
It therefore makes sense to select a correct Pokemon to counter an opponent's Pokemon.
Pokemon MovesAs mentioned earlier, each Pokemon has an array of moves it can make. The moves available to a Pokemon is determined by the Pokemon type. In our game, each of our Pokemon has four possible moves - a physical move (no damage bonus regardless of defending pokemon type), two elemental moves corresponding to the Pokemon type (Water Pokemon gets two Water type abilities) and a defense type move. As mentioned earlier, if an elemental move is made against a defending pokemon which is weak against that element, it will be more effective and deal twice damage (E.g. Charmander uses EMBER on Bulbasaur. It is super effective!). Defending doubles the Pokemon's defense for that round.
Every move is limited by the number of times it can be used per battle. In general, the more powerful a move is, the less times it can be used. In this aspect, our game differ from the real Pokemon game as we reduce the number of available moves. Every move also has a power rating that affects how powerful an attack will be.
Pokemon statistics and moves
![]() | ![]() | ![]() | |
| Name | Bulbasaur | Charmander | Squirtle |
| Type | Grass | Fire | Water |
| HP | 128 | 123 | 127 |
| Attack | 79 | 82 | 78 |
| Defense | 79 | 73 | 95 |
| Speed | 75 | 94 | 73 |
| Move 1 | Tackle (NON) | Scratch (NON) | Tackle (NON) |
| Move 2 | Vinewhip (GRASS) | Ember (FIRE) | Bubble (WATER) |
| Move 3 | Razorleaf (GRASS) | Flamethrower (FIRE) | Watergun (WATER) |
| Move 4 | Defend | Defend | Defend |
| Description | For some time after its birth, it grows by gaining nourishment from the seed on its back. | The fire on the tip of its tail is a measure of its life. If healthy, its tail burn intensely. | It shelters itself in its shell, then strikes back with sprouts of water at every opportunity. |
We represent a Pokemon by using a class called Pokemon (surprise, surprise). We only list the functions which are useful to you:
| Function | Return type | Description |
|---|---|---|
| getAttack() | int | Gets the attack stat of the Pokemon |
| getDefense() | int | Gets the defense stat of the Pokemon |
| getHp() | int | Gets the hp of the Pokemon |
| getSpeed() | int | Gets the speed stat of the Pokemon |
| getType() | int | Gets the type of the Pokemon. Possible types are Pokemon::FIRE, Pokemon::WATER, Pokemon::GRASS |
| isWeak(Pokemon) | bool | Returns true if current Pokemon is weak against the target Pokemon type |
| isWeak(Move) | bool | Returns true if current Pokemon is weak against the target Move type |
| isAlive() | bool | Returns true if current Pokemon is conscious (i.e. hp > 0) |
We represent the actions a player can make using this class. The actions a player can make includes the options to change pokemon, as well as the abilities of the selected pokemon. We only list the functions which are useful to you:
| Function | Return type | Description |
|---|---|---|
| getPower() | int | Gets the power stat of the ability |
| getNumLeft() | int | Gets the num of remaining times this ability can be used |
| getElement() | enum Element | Gets the Element of this move. Possible values are Move::NON, Move::Change, Move::FIRE, Move::Water, Move::GRASS |
| getIndex() | int | Note: Only used if the element of this move is CHANGE. This returns the index position of the player's pokemon to change to. |
| use() | void | Decreases the number of times this ability can be used by 1. |
We represent each player by using this class. This class stores a list of the player's pokemon as well as their names. We only list the functions which are useful to you:
| Function | Return type | Description |
|---|---|---|
| getPokemon(int) | Pokemon& | Returns a reference to a Pokemon at specified index. |
| countLivePokemons() | int | Gets the total number of conscious pokemons. |
| getMoves() | vector<Move> | Gets a vector of possible moves a player may make (including changing Pokemon, and the Pokemon's ability) for this turn |
Students who are familiar with the game may skip most of the above section. Your main task starts from this point. The game works by using a pair of AI to determine the logic each player would make.
Our AI implementation MUST inherit from the class AIBase which contains the following pure virtual functions:
string getName()
{
return "Max The Pokemon Slayer";
}
int chooseInitialPokemon(Player you)
{
int num = rand() % you.countLivePokemons();
return num;
}
If you like to choose the Pokemon with the strongest attack, you may do something like this:
int chooseInitialPokemon(Player you)
{
int best = 0, maxAtk = 0;
for(int i = 0; i < you.getNumPokemons(); i++)
{
if(you.getPokemon(i).getAttack() > maxAtk)
{
maxAtk = you.getPokemon(i).getAttack();
best = i;
}
}
return best;
}
Move makeMove(Player you, Player opponent)
{
return you.getActivePokemon().getMove(0);
}
A simple way of defeating the StupidAI is to simply use the strongest move available. However, if you wish to have
any chance of defeating a "smarter" AI (such as your friend's) you should consider something more complicated.The student is provided with TWO AI implementations - AIStupid and AIPlayer. Your task is to write an AI<YOURNAME> (YOURNAME is replaced by yourname) that is smart enough to defeat AIStupid. AIStupid is a rather stupid AI that does not know how to change Pokemon and uses the worst ability each turn (so practically any other AI would be able to defeat it). AIPlayer is not a true AI - instead this AI lists available options the player can make and allows a human to decide a move to make. You should make a single modification to Main.cpp to use your AI as follows:
int main()
{
srand(time(NULL));
Player p1("Player 1"), p2("Player 2");
initPlayers(p1, p2);
AIBase *p1AI = new AIPlayer; // <---- Change this to the AI class you wrote
AIBase *p2AI = new AIStupid;
.... //remaining code not shown
Max would like to point out that the parameters to each of the above function is a copy of the actual object. Any attempt to "cheat" by modifying the Player's attributes (e.g. adding more pokemons) would not work, since they are only modifying the local copy!
makeMove method in you AI always returns a valid move. If your makeMove method did not return a Move, then the program will fail with an erroryou.getMoves() - you should then choose a correct move from this listyou.getActivePokemon(). You can get the opponent's active Pokemon by calling the same method on the opponent object.isWeak method.It's not so much fun to defeat the StupidAI. On the week of 12th Feburary 2012 during your scheduled lab session bring a thumb drive containing only your AI implementation (or upload somewhere accessible). You will pit YOUR AI against your friend's AI. Each pair will get ONLY one round. The loser is eliminated and the winner will continue to battle the other winners. There can only be one champion!
Prizes
There's not much fun without prizes! For each group:
First Prize: 1 BONUS POINT to your CA mark (in addition to the 1 mark for this lab) + $20 COOP Voucher
2nd - 5th? Prize: 1 BONUS POINT to your CA mark. The number of students receiving this prize is uncertain - all students who have progressed to round 3 automatically qualifies for this prize.
All students participating will automatically receive 1 mark credit for this lab (if they have coded a reasonably decent AI)