Created
April 21, 2018 14:34
-
-
Save KireinaHoro/d2ea9c501b6d55d1ef06b37887849721 to your computer and use it in GitHub Desktop.
WarCraft assignment final version
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <algorithm> | |
#include <iomanip> | |
#include <iostream> | |
#include <sstream> | |
#include <vector> | |
// useless headers | |
#include <cstring> | |
#define SIDE(x) ((x)->getTerritory() ? "red" : "blue") | |
// current time | |
int T; | |
bool endOfWar = false; | |
// number of cities | |
int N; | |
struct Epoch { | |
unsigned hour; | |
unsigned minute; | |
public: | |
friend void tick(); | |
std::string format() const { | |
std::ostringstream os; | |
os << std::setfill('0') << std::setw(3) << hour << ':' | |
<< std::setw(2) << minute; | |
return os.str(); | |
} | |
bool isEnd() { | |
return 60 * hour + minute > T; | |
} | |
} epoch; | |
class Warrior; | |
class Headquarter; | |
using WarriorPtr = Warrior *; | |
using WarriorCreator = WarriorPtr(*)(int, Headquarter const &); | |
class City { | |
private: | |
City *next; | |
City *previous; | |
enum { | |
RED, | |
BLUE, | |
UNSET, | |
} flag = UNSET; | |
bool redBuffer = false; | |
bool blueBuffer = false; | |
protected: | |
WarriorPtr red = nullptr; | |
WarriorPtr blue = nullptr; | |
WarriorPtr redArrival = nullptr; | |
int id; | |
int strength = 0; | |
public: | |
friend void initCities(); | |
friend void tick(); | |
virtual void event0(); | |
int getID() const { return id; } | |
void event5(); | |
void event10(); | |
virtual void event20(); | |
virtual void event30(); | |
void event35(); | |
void event38(); | |
void event40(); | |
virtual void event40_reward() {} | |
virtual void event50(); | |
void event55_red(); | |
void event55_blue(); | |
City(City *next, City *previous, int id) | |
: next(next), previous(previous), id(id) {} | |
City(int strength, City *next, City *previous, int id) | |
: strength(strength), next(next), previous(previous), id(id) {} | |
virtual ~City(); | |
}; | |
class Headquarter : public City { | |
private: | |
std::string name; | |
int index = 1; | |
std::vector<WarriorCreator> warriorSequence; | |
int currentWarriorIndex = 0; | |
std::vector<WarriorPtr> warriors; | |
public: | |
Headquarter(const std::string &name, int strength, WarriorCreator seq[]); | |
void event0() override; | |
void event20() override {} | |
void event30() override {} | |
void event40_reward() override; | |
void event50() override { | |
std::cout << epoch.format() << ' ' | |
<< strength << " elements in " | |
<< name << " headquarter" << std::endl; | |
} | |
std::string getName() const { return name; } | |
int getStrength() const { return strength; } | |
}; | |
Headquarter *redHead, *blueHead; | |
namespace weapon { | |
class Weapon; | |
using WeaponPtr = Weapon *; | |
using WeaponCreator = WeaponPtr(*)(Warrior *); | |
class Weapon { | |
protected: | |
int attackValue; | |
public: | |
virtual ~Weapon() = default; | |
int type; | |
virtual bool usable() const = 0; | |
Weapon(int attack, int type) : attackValue(attack), type(type) {} | |
int getAttack() { return attackValue; } | |
}; | |
class Sword : public Weapon { | |
public: | |
explicit Sword(WarriorPtr); | |
bool usable() const override { return attackValue > 0; } | |
bool attack(WarriorPtr dst); | |
}; | |
class Arrow : public Weapon { | |
public: | |
int remaining = 3; | |
static int R; | |
explicit Arrow(WarriorPtr); | |
bool usable() const override { return remaining > 0; } | |
void use(WarriorPtr src, WarriorPtr dst); | |
}; | |
int Arrow::R; | |
class Bomb : public Weapon { | |
public: | |
explicit Bomb(WarriorPtr); | |
bool usable() const override { return true; } | |
void use(WarriorPtr src, WarriorPtr dst); | |
}; | |
template<typename T> | |
Weapon *make(Warrior *param = nullptr) { | |
return new T{param}; | |
} | |
WeaponCreator WeaponList[] = {make<Sword>, make<Bomb>, make<Arrow>}; | |
} | |
class Warrior { | |
protected: | |
int id; | |
int attackValue; | |
int position; | |
bool territory; | |
bool dying = false; | |
weapon::WeaponPtr weapons[3]{}; | |
public: | |
bool shotToDeath = false; | |
int strength; | |
bool justWon = false; | |
virtual ~Warrior() { | |
for (int i = 0; i < 2; i++) { | |
delete weapons[i]; | |
} | |
} | |
bool isDying() const { return dying; } | |
void setDying(bool a) { dying = a; } | |
friend class Wolf; | |
void takeDamage(int damage) { | |
strength -= damage; | |
} | |
virtual void walk() { | |
if (isDead()) { return; } | |
if (getTerritory()) { | |
++position; | |
} else { | |
--position; | |
} | |
if (position != N + 1 && position != 0) { | |
std::cout << epoch.format() << ' ' | |
<< SIDE(this) << ' ' << getName() << ' ' | |
<< id << " marched to city " << position << ' ' | |
<< "with " << strength << " elements and force " << attackValue | |
<< std::endl; | |
} | |
if (getTerritory() && position == N + 1) { | |
std::cout << epoch.format() << ' ' | |
<< SIDE(this) << ' ' << getName() << ' ' | |
<< id << " reached blue headquarter " | |
<< "with " << strength << " elements and force " << attackValue | |
<< std::endl; | |
} else if (!getTerritory() && position == 0) { | |
std::cout << epoch.format() << ' ' | |
<< SIDE(this) << ' ' << getName() << ' ' | |
<< id << " reached red headquarter " | |
<< "with " << strength << " elements and force " << attackValue | |
<< std::endl; | |
} | |
} | |
bool isDead() const { return strength <= 0; } | |
bool getTerritory() const { return territory; } | |
int getID() const { return id; } | |
int getStrength() const { return strength; } | |
int getPosition() const { return position; } | |
int getAttack() const { return attackValue; } | |
int getAttackActive() const { | |
auto swordAttack = (weapons[0] != nullptr) ? weapons[0]->getAttack() : 0; | |
return attackValue + swordAttack; | |
} | |
virtual int getAttackPassive() const { | |
auto swordAttack = (weapons[0] != nullptr) ? weapons[0]->getAttack() : 0; | |
return attackValue / 2 + swordAttack; | |
} | |
virtual const char *const getName() const = 0; | |
virtual void describe() { | |
if (isDead()) { return; } | |
std::cout << epoch.format() << ' ' | |
<< SIDE(this) << ' ' | |
<< getName() << ' ' << id << ' ' | |
<< "has "; | |
auto arrow = static_cast<weapon::Arrow *>(weapons[2]); | |
auto bomb = static_cast<weapon::Bomb *>(weapons[1]); | |
auto sword = static_cast<weapon::Sword *>(weapons[0]); | |
bool anyWeapons = false; | |
if (arrow != nullptr) { | |
if (arrow->usable()) { | |
anyWeapons = true; | |
std::cout << "arrow(" << arrow->remaining << ")"; | |
} else { | |
weapons[2] = nullptr; | |
} | |
} | |
if (bomb != nullptr) { | |
if (anyWeapons) { std::cout << ','; } | |
anyWeapons = true; | |
std::cout << "bomb"; | |
} | |
if (sword != nullptr) { | |
if (anyWeapons) { std::cout << ','; } | |
anyWeapons = true; | |
std::cout << "sword(" << sword->getAttack() << ")"; | |
} | |
if (!anyWeapons) { | |
std::cout << "no weapon"; | |
} | |
std::cout << std::endl; | |
} | |
void attack(WarriorPtr dst, City *city); | |
Warrior(int id, Headquarter const &head, int defaultStrength, int defaultAttack) | |
: id(id), territory(head.getName() == "red"), strength(defaultStrength), | |
attackValue(defaultAttack), weapons{} { | |
if (territory) { | |
position = 0; | |
} else { | |
position = N + 1; | |
} | |
} | |
void shoot(WarriorPtr dst) { | |
if ((isDead() && !isDying()) || dst->isDead()) { return; } | |
if (weapons[2] != nullptr) { | |
static_cast<weapon::Arrow *>(weapons[2])->use(this, dst); | |
} | |
if (dst->isDead()) { | |
dst->shotToDeath = true; | |
} | |
} | |
void blow(WarriorPtr dst) { | |
if (isDead() || dst->isDead()) { return; } | |
if (weapons[1] != nullptr) { | |
static_cast<weapon::Bomb *>(weapons[1])->use(this, dst); | |
} | |
} | |
void kill() { | |
strength = 0; | |
} | |
void cleanWeapons() { | |
for (auto &i : weapons) { | |
if (i != nullptr && !i->usable()) { | |
delete i; | |
i = nullptr; | |
} | |
} | |
} | |
}; | |
class Dragon : public Warrior { | |
private: | |
double morale; | |
constexpr static auto name = "dragon"; | |
public: | |
friend void City::event40(); | |
static int defaultStrength; | |
static int defaultAttack; | |
const char *const getName() const override { return name; } | |
void reportMorale() const { | |
std::cout << "Its morale is "; | |
std::cout << std::fixed << std::setprecision(2) << morale; | |
std::cout.copyfmt(std::ios(nullptr)); | |
std::cout << std::endl; | |
} | |
Dragon(int id, Headquarter const &head) | |
: Warrior(id, head, defaultStrength, defaultAttack) { | |
// decrement life in castle first before creating warrior! | |
morale = static_cast<double>(head.getStrength()) / strength; | |
weapons[id % 3] = weapon::WeaponList[id % 3](this); | |
} | |
void cheer() const { | |
if (!isDead() && morale > 0.8) { | |
// cheer | |
std::cout << epoch.format() << ' ' | |
<< SIDE(this) << ' ' | |
<< name << ' ' << id << ' ' | |
<< "yelled in city " << position << std::endl; | |
} | |
} | |
}; | |
int Dragon::defaultStrength; | |
int Dragon::defaultAttack; | |
class Ninja : public Warrior { | |
private: | |
constexpr static auto name = "ninja"; | |
public: | |
static int defaultStrength; | |
static int defaultAttack; | |
const char *const getName() const override { return name; } | |
int getAttackPassive() const override { | |
return 0; | |
} | |
Ninja(int id, Headquarter const &head) | |
: Warrior(id, head, defaultStrength, defaultAttack) { | |
weapons[id % 3] = weapon::WeaponList[id % 3](this); | |
weapons[(id + 1) % 3] = weapon::WeaponList[(id + 1) % 3](this); | |
} | |
}; | |
int Ninja::defaultStrength; | |
int Ninja::defaultAttack; | |
class Iceman : public Warrior { | |
private: | |
constexpr static auto name = "iceman"; | |
bool gainingPower = false; | |
public: | |
static int defaultStrength; | |
static int defaultAttack; | |
const char *const getName() const override { return name; } | |
Iceman(int id, Headquarter const &head) | |
: Warrior(id, head, defaultStrength, defaultAttack) { | |
weapons[id % 3] = weapon::WeaponList[id % 3](this); | |
} | |
void walk() override { | |
if (gainingPower) { | |
if (strength > 9) { | |
strength -= 9; | |
} else { | |
if (!isDead()) { strength = 1; } | |
} | |
attackValue += 20; | |
gainingPower = false; | |
} else { | |
gainingPower = true; | |
} | |
Warrior::walk(); | |
} | |
}; | |
int Iceman::defaultStrength; | |
int Iceman::defaultAttack; | |
class Lion : public Warrior { | |
private: | |
int loyalty; | |
constexpr static auto name = "lion"; | |
public: | |
bool escaped = false; | |
friend void City::event40(); | |
static int defaultStrength; | |
static int defaultAttack; | |
static unsigned loyaltyDecrease; | |
const char *const getName() const override { return name; } | |
bool isLoyal() const { | |
return loyalty > 0; | |
} | |
void reportLoyalty() const { | |
std::cout << "Its loyalty is " << loyalty << std::endl; | |
} | |
void describe() override { | |
if (escaped) { return; } | |
Warrior::describe(); | |
} | |
void tryEscape() { | |
if (escaped) { return; } | |
if (!isLoyal() && position != (territory ? N + 1 : 0)) { | |
escaped = true; | |
std::cout << epoch.format() << ' ' | |
<< SIDE(this) << ' ' << name << ' ' | |
<< id << ' ' | |
<< "ran away" << std::endl; | |
} | |
} | |
void walk() override { | |
if (escaped) { return; } | |
Warrior::walk(); | |
} | |
Lion(int id, Headquarter const &head) | |
: Warrior(id, head, defaultStrength, defaultAttack) { | |
// decrement life in castle first before creating warrior! | |
loyalty = head.getStrength(); | |
} | |
}; | |
int Lion::defaultStrength; | |
int Lion::defaultAttack; | |
unsigned Lion::loyaltyDecrease; | |
class Wolf : public Warrior { | |
private: | |
constexpr static auto name = "wolf"; | |
public: | |
static int defaultStrength; | |
static int defaultAttack; | |
const char *const getName() const override { return name; } | |
void loot(WarriorPtr dst) { | |
if (isDead()) { return; } | |
for (int i = 0; i < 3; i++) { | |
if (weapons[i] != nullptr) { continue; } | |
weapons[i] = dst->weapons[i]; | |
dst->weapons[i] = nullptr; | |
} | |
} | |
Wolf(int id, Headquarter const &head) | |
: Warrior(id, head, defaultStrength, defaultAttack) { | |
} | |
}; | |
int Wolf::defaultStrength; | |
int Wolf::defaultAttack; | |
void Warrior::attack(WarriorPtr dst, City *city) { | |
if (isDead() || dst->isDead()) { return; } | |
dst->takeDamage(getAttack()); | |
if (weapons[0]) { | |
static_cast<weapon::Sword *>(weapons[0])->attack(dst); | |
} | |
cleanWeapons(); | |
std::cout << epoch.format() << ' ' | |
<< SIDE(this) << ' ' << getName() << ' ' << getID() << ' ' | |
<< "attacked " << SIDE(dst) << ' ' << dst->getName() << ' ' << dst->getID() << ' ' | |
<< "in city " << city->getID() << ' ' | |
<< "with " << getStrength() << ' ' | |
<< "elements and force " << getAttack() << std::endl; | |
if (!dst->isDead() && dynamic_cast<Ninja *>(dst) == nullptr) { | |
takeDamage(dst->getAttack() / 2); | |
if (dst->weapons[0]) { | |
static_cast<weapon::Sword *>(dst->weapons[0])->attack(this); | |
} | |
dst->cleanWeapons(); | |
std::cout << epoch.format() << ' ' | |
<< SIDE(dst) << ' ' << dst->getName() << ' ' << dst->getID() << ' ' | |
<< "fought back against " << SIDE(this) << ' ' << getName() << ' ' << getID() << ' ' | |
<< "in city " << city->getID() << std::endl; | |
} | |
} | |
bool weapon::Sword::attack(WarriorPtr dst) { | |
if (!usable()) { return false; } | |
dst->takeDamage(attackValue); | |
attackValue = attackValue * 8 / 10; | |
return true; | |
} | |
void weapon::Arrow::use(WarriorPtr src, WarriorPtr dst) { | |
if (dst->getPosition() == 0 || dst->getPosition() == N + 1) { | |
// the target is in the headquarter | |
return; | |
} | |
if (!usable()) { return; } | |
dst->takeDamage(R); | |
dst->setDying(true); | |
--remaining; | |
std::cout << epoch.format() << ' ' | |
<< SIDE(src) << ' ' | |
<< src->getName() << ' ' | |
<< src->getID() << " shot"; | |
if (dst->isDead()) { | |
std::cout << " and killed " | |
<< SIDE(dst) << ' ' | |
<< dst->getName() << ' ' | |
<< dst->getID(); | |
} | |
std::cout << std::endl; | |
} | |
void weapon::Bomb::use(WarriorPtr src, WarriorPtr dst) { | |
src->kill(); | |
dst->kill(); | |
std::cout << epoch.format() << ' ' | |
<< SIDE(src) << ' ' | |
<< src->getName() << ' ' | |
<< src->getID() << " used a bomb and killed " | |
<< SIDE(dst) << ' ' | |
<< dst->getName() << ' ' | |
<< dst->getID() << std::endl; | |
} | |
weapon::Sword::Sword(WarriorPtr warrior) | |
: weapon::Weapon(warrior->getAttack() * 2 / 10, 0) {} | |
weapon::Arrow::Arrow(WarriorPtr warrior) | |
: weapon::Weapon(warrior->getAttack() * 3 / 10, 2) {} | |
weapon::Bomb::Bomb(WarriorPtr warrior) | |
: weapon::Weapon(warrior->getAttack() * 4 / 10, 1) {} | |
template<typename T> | |
Warrior *make(int param1, Headquarter const ¶m2) { | |
return new T{param1, param2}; | |
} | |
WarriorCreator redSequence[] = {make<Iceman>, make<Lion>, make<Wolf>, make<Ninja>, make<Dragon>}; | |
WarriorCreator blueSequence[] = {make<Lion>, make<Dragon>, make<Ninja>, make<Iceman>, make<Wolf>}; | |
Headquarter::Headquarter(const std::string &name, int strength, WarriorCreator seq[]) | |
: name(name), | |
warriorSequence(seq, seq + 5), | |
City(strength, nullptr, nullptr, -1) { | |
if (name == "red") { | |
id = 0; | |
} else { | |
id = N + 1; | |
} | |
} | |
void initCities() { | |
std::vector<City *> cities; | |
cities.push_back(redHead); | |
for (int i = 1; i <= N; i++) { | |
cities.push_back(new City(nullptr, nullptr, i)); | |
} | |
cities.push_back(blueHead); | |
redHead->next = cities[1]; | |
blueHead->previous = cities[N]; | |
for (int i = 1; i <= N; i++) { | |
cities[i]->previous = cities[i - 1]; | |
cities[i]->next = cities[i + 1]; | |
} | |
} | |
void City::event0() {} | |
void Headquarter::event0() { | |
if (strength < warriorSequence[currentWarriorIndex](0, *this)->getStrength()) { | |
// wait until we have enough strength to make a warrior | |
return; | |
} | |
strength -= warriorSequence[currentWarriorIndex](0, *this)->getStrength(); | |
auto newWarrior = warriorSequence[currentWarriorIndex](index++, *this); | |
std::cout << epoch.format() << ' ' | |
<< name << ' ' | |
<< newWarrior->getName() << ' ' | |
<< newWarrior->getID() << ' ' | |
<< "born" << std::endl; | |
// remove 0-attack swords | |
newWarrior->cleanWeapons(); | |
auto newLion = dynamic_cast<Lion *>(newWarrior); | |
if (newLion != nullptr) { | |
newLion->reportLoyalty(); | |
} | |
auto newDragon = dynamic_cast<Dragon *>(newWarrior); | |
if (newDragon != nullptr) { | |
newDragon->reportMorale(); | |
} | |
if (name == "red") { | |
red = newWarrior; | |
} else { | |
blue = newWarrior; | |
} | |
warriors.push_back(newWarrior); | |
currentWarriorIndex = (currentWarriorIndex + 1) % 5; | |
} | |
void City::event5() { | |
auto newRed = dynamic_cast<Lion *>(red); | |
if (newRed != nullptr && newRed->getPosition() != N + 1) { | |
newRed->tryEscape(); | |
} | |
auto newBlue = dynamic_cast<Lion *>(blue); | |
if (newBlue != nullptr && newBlue->getPosition() != 0) { | |
newBlue->tryEscape(); | |
} | |
} | |
void City::event10() { | |
auto takenFlag = false; | |
if (previous != nullptr && previous->red != nullptr) { | |
if (getID() == N + 1 && red) { | |
takenFlag = true; | |
} | |
redArrival = previous->red; | |
previous->red = nullptr; | |
redArrival->walk(); | |
if (takenFlag) { | |
std::cout << epoch.format() << ' ' | |
<< "blue headquarter was taken" | |
<< std::endl; | |
endOfWar = true; | |
} | |
if (getID() == N + 1) { | |
red = redArrival; | |
redArrival = nullptr; | |
} | |
} | |
if (previous != nullptr) { | |
previous->red = previous->redArrival; | |
previous->redArrival = nullptr; | |
} | |
if (next != nullptr && next->blue != nullptr) { | |
if (next->blue->isDead()) { | |
next->blue = nullptr; | |
} else { | |
if (!getID() && blue) { | |
takenFlag = true; | |
} | |
blue = next->blue; | |
blue->walk(); | |
if (takenFlag) { | |
std::cout << epoch.format() << ' ' | |
<< "red headquarter was taken" | |
<< std::endl; | |
endOfWar = true; | |
} | |
next->blue = nullptr; | |
} | |
} | |
auto redLion = dynamic_cast<Lion *>(red); | |
auto blueLion = dynamic_cast<Lion *>(blue); | |
if (blue && | |
(blue->isDead() || | |
(blueLion && blueLion->escaped))) { blue = nullptr; } | |
if (red && | |
(red->isDead() || | |
(redLion && redLion->escaped))) { red = nullptr; } | |
} | |
void City::event20() { | |
strength += 10; | |
} | |
void City::event30() { | |
if (blue != nullptr && red == nullptr) { | |
blueHead->strength += strength; | |
std::cout << epoch.format() << ' ' | |
<< SIDE(blue) << ' ' | |
<< blue->getName() << ' ' << blue->getID() << ' ' | |
<< "earned " << strength << " elements for his headquarter" << std::endl; | |
strength = 0; | |
} else if (red != nullptr && blue == nullptr) { | |
redHead->strength += strength; | |
std::cout << epoch.format() << ' ' | |
<< SIDE(red) << ' ' | |
<< red->getName() << ' ' << red->getID() << ' ' | |
<< "earned " << strength << " elements for his headquarter" << std::endl; | |
strength = 0; | |
} | |
} | |
void City::event35() { | |
if (red != nullptr && next != nullptr && next->blue != nullptr) { | |
red->shoot(next->blue); | |
red->setDying(false); | |
} | |
if (blue != nullptr && previous != nullptr && previous->red != nullptr) { | |
blue->shoot(previous->red); | |
blue->setDying(false); | |
} | |
} | |
void City::event38() { | |
if (red == nullptr || blue == nullptr | |
|| red->isDead() || blue->isDead()) { return; } | |
bool redAttack; | |
if (flag == UNSET) { | |
redAttack = (id % 2 != 0); | |
} else { | |
redAttack = flag == RED; | |
} | |
if (redAttack) { | |
if (red->getAttackActive() >= blue->getStrength()) { | |
blue->blow(red); | |
} else if (blue->getAttackPassive() >= red->getStrength()) { | |
red->blow(blue); | |
} | |
} else { | |
if (blue->getAttackActive() >= red->getStrength()) { | |
red->blow(blue); | |
} else if (red->getAttackPassive() >= blue->getStrength()) { | |
blue->blow(red); | |
} | |
} | |
} | |
void City::event40() { | |
if (red == nullptr || blue == nullptr) { return; } | |
auto redOldStrength = red->getStrength(); | |
auto blueOldStrength = blue->getStrength(); | |
if (redOldStrength < 0) { redOldStrength = 0; } | |
if (blueOldStrength < 0) { blueOldStrength = 0; } | |
auto newDragonRed = dynamic_cast<Dragon *>(red); | |
auto newDragonBlue = dynamic_cast<Dragon *>(blue); | |
bool redAttack; | |
if (flag == UNSET) { | |
redAttack = (id % 2 != 0); | |
} else { | |
redAttack = flag == RED; | |
} | |
if (redAttack) { | |
red->attack(blue, this); | |
} else { | |
blue->attack(red, this); | |
} | |
if (!(red->isDead() || blue->isDead())) { | |
blueBuffer = redBuffer = false; | |
if (newDragonRed) { | |
newDragonRed->morale -= 0.2; | |
if (redAttack) { | |
newDragonRed->cheer(); | |
} | |
} | |
if (newDragonBlue) { | |
newDragonBlue->morale -= 0.2; | |
if (!redAttack) { | |
newDragonBlue->cheer(); | |
} | |
} | |
} else if (red->isDead() && blue->isDead()) {} | |
else { | |
if (red->isDead()) { | |
if (!red->shotToDeath) { | |
std::cout << epoch.format() << ' ' | |
<< SIDE(red) << ' ' << red->getName() << ' ' << red->getID() << ' ' | |
<< "was killed in city " << id << std::endl; | |
} | |
if (newDragonBlue) { | |
newDragonBlue->morale += 0.2; | |
if (!redAttack) { | |
newDragonBlue->cheer(); | |
} | |
} | |
blueHead->strength += strength; | |
std::cout << epoch.format() << ' ' | |
<< SIDE(blue) << ' ' | |
<< blue->getName() << ' ' << blue->getID() << ' ' | |
<< "earned " << strength << " elements for his headquarter" << std::endl; | |
strength = 0; | |
if (dynamic_cast<Lion *>(red)) { | |
blue->strength += redOldStrength; | |
} | |
auto newBlue = dynamic_cast<Wolf *>(blue); | |
if (newBlue != nullptr) { | |
newBlue->loot(red); | |
} | |
redBuffer = false; | |
if (blueBuffer && flag != BLUE) { | |
// blue has already won once | |
blueBuffer = false; | |
flag = BLUE; | |
std::cout << epoch.format() << ' ' | |
<< "blue flag raised in city " << id << std::endl; | |
} else { | |
blueBuffer = true; | |
} | |
blue->justWon = true; | |
} else { | |
if (!blue->shotToDeath) { | |
std::cout << epoch.format() << ' ' | |
<< SIDE(blue) << ' ' << blue->getName() << ' ' << blue->getID() << ' ' | |
<< "was killed in city " << id << std::endl; | |
} | |
if (newDragonRed) { | |
newDragonRed->morale += 0.2; | |
if (redAttack) { | |
newDragonRed->cheer(); | |
} | |
} | |
redHead->strength += strength; | |
std::cout << epoch.format() << ' ' | |
<< SIDE(red) << ' ' | |
<< red->getName() << ' ' << red->getID() << ' ' | |
<< "earned " << strength << " elements for his headquarter" << std::endl; | |
strength = 0; | |
if (dynamic_cast<Lion *>(blue)) { | |
red->strength += blueOldStrength; | |
} | |
auto newRed = dynamic_cast<Wolf *>(red); | |
if (newRed != nullptr) { | |
newRed->loot(blue); | |
} | |
blueBuffer = false; | |
if (redBuffer && flag != RED) { | |
// blue has already won once | |
redBuffer = false; | |
flag = RED; | |
std::cout << epoch.format() << ' ' | |
<< "red flag raised in city " << id << std::endl; | |
} else { | |
redBuffer = true; | |
} | |
red->justWon = true; | |
} | |
} | |
auto newLionRed = dynamic_cast<Lion *>(red); | |
auto newLionBlue = dynamic_cast<Lion *>(blue); | |
if (newLionRed != nullptr) { | |
if (!newLionRed->isDead() && !blue->isDead()) { | |
newLionRed->loyalty -= Lion::loyaltyDecrease; | |
} | |
} | |
if (newLionBlue != nullptr) { | |
if (!newLionBlue->isDead() && !red->isDead()) { | |
newLionBlue->loyalty -= Lion::loyaltyDecrease; | |
} | |
} | |
} | |
void Headquarter::event40_reward() { | |
sort(warriors.begin(), warriors.end(), | |
[this](WarriorPtr a, WarriorPtr b) { | |
if (this->getID()) { // we are blue; red's id is N + 1 | |
return a->getPosition() < b->getPosition(); | |
} else { | |
return a->getPosition() > b->getPosition(); | |
} | |
}); | |
for (auto &a : warriors) { | |
if (a->isDead() || !a->justWon) { continue; } | |
if (strength >= 8) { | |
a->strength += 8; | |
strength -= 8; | |
} | |
a->justWon = false; | |
} | |
} | |
void City::event50() {} | |
void City::event55_red() { | |
if (red != nullptr) { | |
red->describe(); | |
} | |
} | |
void City::event55_blue() { | |
if (blue != nullptr) { | |
blue->describe(); | |
} | |
} | |
City::~City() { | |
delete red; | |
delete blue; | |
delete redArrival; | |
} | |
using eventType = void (City::*)(); | |
const eventType events[] = { | |
&City::event0, | |
&City::event5, | |
&City::event10, | |
&City::event20, | |
&City::event30, | |
&City::event35, | |
&City::event38, | |
&City::event40, | |
&City::event40_reward, | |
&City::event50, | |
&City::event55_red, | |
&City::event55_blue, | |
}; | |
const unsigned checkpoints[] = { | |
0, 5, 10, 20, 30, 35, 38, 40, 40, 50, 55, 55, | |
}; | |
void tick() { | |
City *curr = redHead; | |
for (int i = 0; i < sizeof(checkpoints) / sizeof(checkpoints[0]); i++) { | |
epoch.minute = checkpoints[i]; | |
if (epoch.isEnd()) { | |
endOfWar = true; | |
return; | |
} | |
const auto currEvent = events[i]; | |
while (curr != nullptr) { | |
(curr->*currEvent)(); | |
curr = curr->next; | |
} | |
// reset the curr pointer | |
curr = redHead; | |
if (endOfWar) { return; } | |
} | |
++epoch.hour; | |
} | |
void runEval(int caseNo) { | |
std::cout << "Case " << caseNo << ":" << std::endl; | |
// initialization | |
epoch = Epoch(); | |
int M; | |
endOfWar = false; | |
std::cin >> M; | |
std::cin >> N; | |
std::cin >> weapon::Arrow::R; | |
std::cin >> Lion::loyaltyDecrease; | |
std::cin >> T; | |
std::cin >> Dragon::defaultStrength; | |
std::cin >> Ninja::defaultStrength; | |
std::cin >> Iceman::defaultStrength; | |
std::cin >> Lion::defaultStrength; | |
std::cin >> Wolf::defaultStrength; | |
std::cin >> Dragon::defaultAttack; | |
std::cin >> Ninja::defaultAttack; | |
std::cin >> Iceman::defaultAttack; | |
std::cin >> Lion::defaultAttack; | |
std::cin >> Wolf::defaultAttack; | |
redHead = new Headquarter("red", M, redSequence); | |
blueHead = new Headquarter("blue", M, blueSequence); | |
initCities(); | |
while (!endOfWar) { | |
tick(); | |
} | |
delete redHead; | |
delete blueHead; | |
} | |
int main() { | |
int n; | |
std::cin >> n; | |
for (int i = 1; i <= n; i++) { | |
runEval(i); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment