Assignment 5: Animal War - Inheritance and Polymorphism

Contents

News

Submission deadline: 11:59pm, Saturday, Nov. 21, 2015

  1. You may change the takeDamage and die functions to virtual functions to help you implement the bonus part. However, it is not recommended to change those if you are not going to work on the bonus part.
  2. You do not need to handle this case:
    
    Dragon Dead Dead Dead Dead
    Dead Dead Dead Dead Dragon
    
    
    But if you want to handle it nicely, you may make it a draw condition.
  3. All animals once dead (HP drops to or below zero), cannot be healed and become alive again. i.e. A bat with zero HP cannot heal itself, an Army Ant Queen cannot heal dead ants.
  4. Virtual Inheritance may help while implementing Phoenix and Cerberus.
  5. You may add any data members/functions to help but you SHOULD NOT alter any existing data members/functions in the skeleton code, unless otherwise specified.
  6. Special moves always happen after normal attacks. If there are more than 1 special move triggered, the triggering order does not matter.
  7. You may want to hand in more files than those stated in Assignment Requirements to help design your inheritance relations. If you have altered Animal.h/ Animal.cpp to include some advanced features, please hand in those as well.
  8. Clarification of Dragon's attack: If the Dragon is positioned at the boundary ,index 0 or 4, then it will only attack 0,1 or 3,4 on the opposite side respectively.
  9. Dragon's defend behaviour is now updated as "Takes only 80% of the damages as flying animals are agile" to avoid confusion.
  10. Army Ant(Queen)'s defend behaviour is updated from "Other alive ants on the battle field" to "Other alive ants of the same team" to avoid confusion
  11. Swimming animals and flying animals are now clearly defined: Only Turtle and Shark are swimming animals. Only Bat, Hawk and Dragon (and Phoenix in the bonus part) are flying animals.
  12. If you are unsure about the details of this assignment, feel free to email me at kwau@cse.ust.hk (David) to ask for the clarifications.

Introduction

In this assignment you will design the game "Animal War" based on your OOP knowledge on inheritance and polymorphism, and simulate the game given an input.

Animal Wars is a turn-based game consisting of 2 players. At the beginning of the game, each of the two players P1 and P2 starts with 5 animals with positions labelled from i = 0 to 4.

Fig 1:


Upon object instantiation, all the position information of the animal, its allies and enemies will be injected into the object for you to implement the more complicated game logics described later. The constructor of the class Animal (the base class of all other animal classes):


Animal::Animal(Game* game, int player, int position) {
	allies = game->animals[player];
	enemies = game->animals[!player];
	pos = position;
	is_dead = false;

}

All animals have the following attributes:

  1. hp: an integer value that determines how many damage points the animal can take before it dies
  2. atk_damage: an integral point of the damage dealt (incurred) on its attacking opponent

Furthermore, all the animals MUST have the following behaviours:

  1. attack: deal (incur) damage to an enemy/enemies on the opposite side, if the damage dealt is larger than the opponent's current HP, the opponent dies.
  2. defend: alter the final damage dealt on oneself, or respond to the attacker according to its defensive skill
  3. takeDamage: Deduct HP according to  a "damage value" defined by the animal's defend behaviour
  4. die, can no longer attack or become a target of the enemies' attacks

If you take a look at the Animal.h file in the provided skeleton code, the declarations of the Animal's behaviours look like this:


	virtual void attack() = 0;
	virtual void defend(Animal* opponent, int damage);

	void takeDamage(int damage);
	void die();

Since different animals should behave differently when attack and defend, you should override these 2 methods in the derived classes to implement the specific behaviour of each animal.

However, the takeDamage and die behaviour should be THE SAME FOR ALL ANIMALS. You may use these 2 methods in your implementation of the attack and defend behaviours of other animals, but you should not override takeDamage and die in the derived classes.


Position Rule:

An animal will attack the enemy of the same position index on the other side, and it will attack whoever else closest to it if the opposite enemy is dead, break ties by choosing an enemy with the smallest position index. The distance between 2 animals is defined as the absolute value of the difference of their position index.

Using the Fig.1 above as an example, Shark of Player 2 (at position 2) should attack:

  1. Bat (at position 2 on the player 1 side, distance = 0), if the Bat is alive;
  2. Hawk (at position 1 on the player 1 side, distance = 1), if the Bat is dead but the Hawk is alive;
  3. Dog (at position 3 on the player 1 side, distance = 1), if both the Bat and the Hawk are dead, and the Dog is alive. 
  4. Dog (at position 0 on the player 1 side, distance = 2),  if the animals above (Bat, Hawk and Dog(at position 3) ) are all dead
  5. Shark (at position 4 on the player 1 side, distance = 2), if other animals are all dead

Unless otherwise stated, the above Position Rule applies to all animals.


Example - Dog:

Dog's attack behaviour:

// Attack according to the Position Rule.
// Note that the enemy's defend method is passively called in the attacker's attack method.
void Dog::attack()
{
	if(!enemies[pos]->isDead())
		enemies[pos]->defend(this, atk_damage);
	else {
		for(int i = 1; i < 5; i++)
		{
			if(pos-i >= 0 && !enemies[pos-i]->isDead())
			{
				enemies[pos-i]->defend(this, atk_damage);
				break;
			}
			else if(pos+i < 5 && !enemies[pos+i]->isDead())
			{
				enemies[pos+i]->defend(this, atk_damage);
				break;
			}
		}
	}
}

Dog's defend behaviour (inherited from the base class Animal):

// Defend the damage from an opponent
void Animal::defend(Animal* opponent, int damage)
{
	takeDamage(damage);
}
Dog's takeDamage behaviour (inherited from the base class Animal):

void Animal::takeDamage(int damage)
{
	hp -= damage;
	if( hp <= 0 )
		die();
}
Dog's die behaviour (inherited from the base class Animal):

void Animal::die()
{
	is_dead = true;
}

When the game starts, P1 and P2 will take turns to attack (Player 1 always starts first in this game). When a player is attacking, the other one will be defending. During a player's attacking turn, all of his animals who are still alive will attack in ascending order of their position index. If the game does not end in a turn, it will proceed to the next turn where the attacking player will become the defending player, and vice versa. The game ends when either one or both sides are all dead.

Input

The input is a single line with 10 integers. The first 5 integers correspond to the animal IDs(listed in the next section) of the 5 animals from position 0 to 4 in Player 1's team. The last 5 integers correspond to the animal IDs of the 5 animals from position 0 to 4 in Player 2's team

For example, the input corresponding to Fig.1 above is: (You should check the animal IDs in the next section)

0 2 3 0 5 1 4 5 1 2

Output

The program should simulate the HP of all animals at the end of the each turn, output "DEAD" if an animal is dead (HP <= 0). When the game ends, it should output the winner as "Player X Wins!", or output "Draw!" if both sides are dead at the end of the game (Please refer to the next section to see how can a "draw" happen).

For example, the expected output corresponding to Fig.1 is:


Turn 1 Player 1 attacks:
Player 1
Dog:30 Hawk:25 Bat:19 Dog:30 Shark:28 
Player 2
Cat:20 Turtle:30 Shark:26 Cat:20 Hawk:21 
Turn 2 Player 2 attacks:
Player 1
Dog:24 Hawk:24 Bat:14 Dog:24 Shark:23 
Player 2
Cat:20 Turtle:29 Shark:25 Cat:20 Hawk:21 
Turn 3 Player 1 attacks:
Player 1
Dog:24 Hawk:24 Bat:13 Dog:24 Shark:21 
Player 2
Cat:15 Turtle:24 Shark:21 Cat:15 Hawk:17 
Turn 4 Player 2 attacks:
Player 1
Dog:18 Hawk:23 Bat:8 Dog:18 Shark:16 
Player 2
Cat:15 Turtle:23 Shark:20 Cat:15 Hawk:17 
Turn 5 Player 1 attacks:
Player 1
Dog:18 Hawk:23 Bat:7 Dog:18 Shark:14 
Player 2
Cat:10 Turtle:18 Shark:16 Cat:10 Hawk:13 
Turn 6 Player 2 attacks:
Player 1
Dog:9 Hawk:22 Bat:2 Dog:9 Shark:9 
Player 2
Cat:10 Turtle:17 Shark:15 Cat:10 Hawk:13 
Turn 7 Player 1 attacks:
Player 1
Dog:9 Hawk:22 Bat:DEAD Dog:9 Shark:7 
Player 2
Cat:5 Turtle:12 Shark:11 Cat:5 Hawk:9 
Turn 8 Player 2 attacks:
Player 1
Dog:DEAD Hawk:17 Bat:DEAD Dog:DEAD Shark:2 
Player 2
Cat:5 Turtle:11 Shark:9 Cat:5 Hawk:9 
Turn 9 Player 1 attacks:
Player 1
Dog:DEAD Hawk:17 Bat:DEAD Dog:DEAD Shark:DEAD 
Player 2
Cat:5 Turtle:6 Shark:9 Cat:5 Hawk:5 
Turn 10 Player 2 attacks:
Player 1
Dog:DEAD Hawk:DEAD Bat:DEAD Dog:DEAD Shark:DEAD 
Player 2
Cat:4 Turtle:5 Shark:7 Cat:5 Hawk:5 
Player 2 Wins!

Details of this output will be explained in the next section.

Animals

Different animals have different HP and attack damage, and they should attack and defend differently according to their nature.

In this assignment, you will need to design the classes and inheritance relations of the animals according to the following information:

ID Name Max HP Damage Attack Defend
0 Dog 30 5 Deals damages normally Takes damages normally
1 Cat 25 6 Cats go crazy while in danger. Deals 1.5 times damages when HP < 13 Takes damages normally
2 Hawk 25 5 Attacks with great accuracy! Hawk's attacks are indefensible1 Takes only 70% of the damages and revenges2 and deals 1 indefensible damage back as hawks are extremely agile
3 Bat 20 4 Drains3 its enemy's HP and heals itself for 1 HP Takes only 80% of the damages as flying animals are agile
4 Turtle 35 2 Deals damages normally With a hard shell, turtle only takes 50% of the damages
5 Shark 30 7 Attacks recklessly, sharks will also hurt themselves by 1 HP in each attack4 Revenges fiercely and deals 2 indefensible damages to whoever attacks it
6 Army Ant 15 1 Deals damages normally Takes damages normally
7 Army Ant(Queen)5 15 0 Queens does not attack, hence will not trigger opponent's defensive skill as well Other alive ants of the same team will revenge and each of them deal 2 indefensible damages to whoever attacks the queen
8 Dragon 40 4 Fire breathes in a cone, dealing damages to the 3 closest positions on the opposite side, regardless the enemies there are dead or alive. (i.e. Position Rule does not apply). If the dragon is positioned at the boundary, index 0 or 4, then it will only attack 0,1 or 3,4 on the opposite side respectively. Takes only 80% of the damages as flying animals are agile

*Notes:

  1. "Indefensible attack/damage" means that the attack/damage will not trigger the defensive skill of the opponent (i.e. Opponents must take 100% of the damage and they cannot revenge). For example in the Fig.1 testcase:
    
    Turn 1 Player 1 attacks: // Player 1's Hawk attacks in this turn, dealing 5 damages to Turtle instead of 2
    Player 1
    Dog:30 Hawk:25 Bat:19 Dog:30 Shark:28 
    Player 2
    Cat:20 Turtle:30 Shark:26 Cat:20 Hawk:21 
    Turn 2 Player 2 attacks: // Player 2's Hawk attacks Shark in this turn, and it is not revenged by the Shark 
    Player 1
    Dog:24 Hawk:24 Bat:14 Dog:24 Shark:23 
    Player 2
    Cat:20 Turtle:29 Shark:25 Cat:20 Hawk:21 
    
  2. Revenges occurs only if the defending animal(who has revenge ability) survives that attack. i.e. You should check whether the defending animal is still alive before revenging.
  3. Bat heals themselves after the enemy's defend behaviour, so the correct sequence will be: Bat attacks->enemy defends and takes damages->enemy revenges(if any)->Bat heals itself. Also note that Bats do not "over heal" themselves, their HP cannot exceed the Max HP after the healing. For example, the Turn 1 and Turn 7 of the Fig.1 testcase:
    
    // Bat attacks Shark-> Shark revenges for 2 damages-> Bat heals itself for 1 HP = 19HP at the end of turn 1
    Turn 1 Player 1 attacks: 
    Player 1
    Dog:30 Hawk:25 Bat:19 Dog:30 Shark:28 
    Player 2
    Cat:20 Turtle:30 Shark:26 Cat:20 Hawk:21 
    
    Turn 6 Player 2 attacks:
    Player 1
    Dog:9 Hawk:22 Bat:2 Dog:9 Shark:9 
    Player 2
    Cat:10 Turtle:17 Shark:15 Cat:10 Hawk:13 
    // Bat starts with 2 HP and attacks Shark-> Shark revenges for 2 damages ->Bat dies, cannot heal itself
    Turn 7 Player 1 attacks: 
    Player 1
    Dog:9 Hawk:22 Bat:DEAD Dog:9 Shark:7 
    Player 2
    Cat:5 Turtle:12 Shark:11 Cat:5 Hawk:9 
    
  4. This is how a "Draw" condition can happen. e.g. The game goes to a state that only 2 animals are standing alive. A shark with HP 1 attacks a cat with HP 1, the shark dies after it kills the cat, no animals alive on both sides after this turn therefore it is a draw. You may also want to take a look at the draw test case (and its expected output) provided in the skeleton code.
  5. It is guaranteed in the input that there will be no more than one Army Ant Queen in each team

To-Do 1:

For each of the animals listed above, complete the corresponding class header and .cpp file. Implement necessary functions as described in the above table. After you have implemented them, remember to include the header files in the Game.cpp and instantiate the animal in the Game::load() function. You may refer to the Dog.h and Dog.cpp files as an example.


Special Moves

To make the game more interesting, several combinations of animals can make some special moves:

  1. With more than 2 (>=3) flying animals (Hawk, Bat and Dragon) alive on the same side, they can harass the opponents and each of them deals 1 indefensible damage to all enemies in their attacking turn
    • Bats also heal themselves for 1 HP during the harass
    • Dragons harass with fire breaths, dealing 2 indefensible damages to all enemies instead
  2. With more than 2 (>=3) swimming animals (Turtle, Shark) alive on the same side, they can summonTsunami and each of them deals 1 indefensible damage to all enemies in their attacking turn
    • Sharks are too reckless in attacking, dealing 2 indefensible damages to all enemies instead but at the cost of hurting themselves for 2 damages
  3. With 5 Army Ants on the same side, they marchAndConquer whatever in front of them, each of them deals 3 indefensible damages to all enemies in their attacking turn
    • The Queen does not attack, but she will heal other ants for 2 HP(excluding herself). This healing also do not "over heal" the ants. i.e. The ants' HP can never exceed the Max HP defined above.

To-Do 2:

Implement these 3 special moves for the corresponding animals. After you finished, simulate the effect of these special moves in the Game::start() function. The special moves should be simulated after the normal attacks in each round. (See the instructions in the skeleton code, which clearly stated where should you put your codes.)

Make sure you have checked that there are enough alive animals for a special move. You may add data members and functions to the Game class to help you complete the required logics.

Assignment Requirements

  1. You must use the skeleton code provided and complete the classes of all the animals mentioned in the above section. The abstract base class "Animal" and the "Dog" class are already completed as examples for you. The zip file includes 2 test cases. 1 normal test case which is the same as the Fig.1 example. Another one is a "Draw" test case, and there is also a corresponding expected output for you to check the correctness of your program. Before you start, you may want to use the test case "0 0 0 0 0 0 0 0 0 0" (10 dogs, 5 on each team) to help you get a basic idea of the game play.
  2. You should design the inheritance relations according to the information given in the above section, as well as the polymorphic behaviours of the animals.
  3. After finishing the animal classes, you should simulate the game in the Game::start() method. In each turn, the program will output the remaining HP of the animals on each side. The game will proceed until either one or both sides are all dead. When the game ends, the program output the winner. These are already done by the skeleton code. Your task is to add the special moves of the animal combinations as described in the above section in the simulation. You may add any necessary data members to help in the Game.h file. Note that we will use our own testing program to grade your program. Therefore, please follow the I/O of the functions because we will use a different program to test your implementation.
  4. We have provided you some input test cases and the expected output for your basic testing only. You may need to come up with your own test cases. Please submit your good test cases if this exposes some of the unique features of your program, or you think they are good to be used to test other programs.
  5. Please submit the following files:
    1. Game.h Game.cpp
    2. Cat.h Cat.cpp
    3. Hawk.h Hawk.cpp
    4. Bat.h Bat.cpp
    5. Turtle.h Turtle.cpp
    6. Shark.h Shark.cpp
    7. ArmyAnt.h ArmyAnt.cpp
    8. ArmyAntQueen.h ArmyAntQueen.cpp
    9. Dragon.h Dragon.cpp
    You may want to hand in more files than those stated above to help design your inheritance relations. If you have altered Animal.h/ Animal.cpp to include some advanced features, please hand in those as well. You may want submit a README file with a few words to justify the design of the classes, the inheritance relations...etc.

Grading Scheme

  1. The correctness of the program will worth 40 points.
  2. The design of the inheritance relations will worth 20 points.
    • Hint: A good design should have high code reusability and is easy to maintain and modify
  3. The design of the polymorphic behaviours will worth 20 points.
    • Hint: A good design should avoid runtime checking of the class objects, but instead exercise polymorphic behaviours by dynamic binding.

Bonus (Maximum 10%)

  1. Implement Phoenix, Cerberus and the special moves as described below, you may define the values of their HP, damage, and the behaviours of attack and defence in your own way, and with the following features:
    • Phoenix revives with full HP upon death, this occurs only once in each game
    • Cerberus can organize a group attack(a special move) with other ally dogs, Cerberus deals 2 while the other dogs deals 1 damage to all enemies
    • With more than 2 (>=3) legendary animals(Dragon, Phoenix and Cerberus) on the same side, they can weather the storm and each of them will deal 3 damages to all enemies
    • All special moves deals indefensible damages
  2. Remember to describe the inheritance relations of them in your README file if you are going to implement this part!
  3. Add other interesting features to the game, it will be graded according to the level of creativity and difficulty. 
  4. Please explain clearly in your README if you have done any of the above.