Skip to content

Instantly share code, notes, and snippets.

@KireinaHoro
Created March 31, 2018 03:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KireinaHoro/0f9b74a6bff047c18ea53427ce51e02d to your computer and use it in GitHub Desktop.
Save KireinaHoro/0f9b74a6bff047c18ea53427ce51e02d to your computer and use it in GitHub Desktop.
#include <algorithm>
#include <deque>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <unordered_map>
#include <vector>
// useless headers
#include <cstring>
class Warrior;
class Headquarter;
using WarriorPtr = Warrior *;
using WarriorCreator = WarriorPtr(*)(int, Headquarter const &);
class City {
protected:
WarriorPtr red = nullptr;
WarriorPtr blue = nullptr;
int id;
public:
virtual void event0();
virtual void event5();
virtual void event10();
virtual void event35();
virtual void event40();
virtual void event50();
virtual void event55();
virtual void dispatchEvent() {
}
};
class Headquarter : public City {
private:
std::string name;
int index = 1;
std::vector<WarriorCreator> warriorSequence;
int currentWarriorIndex = 0;
int strength;
bool running = true;
std::unordered_map<WarriorCreator, int> warriorsCounter;
std::vector<WarriorPtr> warriors;
public:
Headquarter(std::string name, int strength, WarriorCreator seq[]);
void spawn();
std::string getName() const { return name; }
bool getState() const { return running; }
int getStrength() const { return strength; }
};
// current time
struct {
public:
unsigned hour;
unsigned minute;
std::string format() const {
std::ostringstream os;
os << std::setfill('0') << std::setw(3) << hour
<< std::setw(2) << minute;
return os.str();
}
} epoch;
// number of cities
int N;
Headquarter *redHead, *blueHead;
namespace weapon {
class Weapon;
const char *names[] = {
"sword",
"bomb",
"arrow",
};
using WeaponPtr = Weapon *;
using WeaponCreator = WeaponPtr(*)(Warrior *);
class Weapon {
protected:
int attackValue;
public:
int type;
virtual bool usable() const = 0;
virtual bool attack(WarriorPtr src, WarriorPtr dst) = 0;
virtual const char *const getName() const = 0;
virtual bool operator<(WeaponPtr const &a) const {
return type < a->type;
}
Weapon(int attack, int type) : attackValue(attack), type(type) {}
};
class Sword : public Weapon {
private:
constexpr static auto startRatio = 0.2;
constexpr static auto name = "sword";
// constexpr static auto wearRatio = 0.8;
public:
const char *const getName() const override { return name; }
explicit Sword(WarriorPtr);
bool usable() const override { return true; }
bool attack(WarriorPtr src, WarriorPtr dst) override;
};
bool cmpForLoot(WeaponPtr const &, WeaponPtr const &);
class Arrow : public Weapon {
private:
constexpr static auto name = "arrow";
constexpr static auto startRatio = 0.3;
int remaining = 2;
public:
const char *const getName() const override { return name; }
// static int attackValue;
explicit Arrow(WarriorPtr);
bool usable() const override { return remaining > 0; }
bool attack(WarriorPtr src, WarriorPtr dst) override;
bool operator<(WeaponPtr const &a) const override {
auto newA = dynamic_cast<Arrow *>(a);
if (newA) {
return remaining < newA->remaining;
} else {
return this < a;
}
}
friend bool cmpForLoot(WeaponPtr const &, WeaponPtr const &);
};
// // TODO: R
// int Arrow::attackValue;
class Bomb : public Weapon {
private:
constexpr static auto name = "bomb";
constexpr static auto startRatio = 0.4;
bool used = false;
public:
const char *const getName() const override { return name; }
explicit Bomb(WarriorPtr);
bool usable() const override { return !used; }
bool attack(WarriorPtr src, WarriorPtr dst) override;
};
template<typename T>
Weapon *make(Warrior *param = nullptr) {
return new T{param};
}
WeaponCreator WeaponList[] = {make<Sword>, make<Bomb>, make<Arrow>};
bool cmpForLoot(WeaponPtr const &a, WeaponPtr const &b) {
auto newA = dynamic_cast<Arrow *>(a);
auto newB = dynamic_cast<Arrow *>(b);
if (newA != nullptr && newB != nullptr) {
return newA->remaining > newB->remaining;
} else {
return a < b;
}
}
}
class Warrior {
protected:
int id;
int strength;
int attackValue;
int position;
bool territory;
std::deque<weapon::WeaponPtr> weapons;
void sortWeapons() {
std::sort(weapons.begin(), weapons.end());
}
void sortWeaponsForLoot() {
std::sort(weapons.begin(), weapons.end(), weapon::cmpForLoot);
}
public:
friend class Wolf;
void takeDamage(int damage) {
strength -= damage;
}
virtual void walk() {
if (getTerritory()) {
++position;
} else {
--position;
}
std::cout << epoch.format() << ' '
<< (territory ? "red" : "blue") << ' ' << getName() << ' '
<< id << " marched to city " << position << ' '
<< "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 getAttack() const { return attackValue; }
int getPosition() const { return position; }
virtual const char *const getName() const = 0;
virtual void describe() const = 0;
virtual void attack(WarriorPtr dst) {
sortWeapons();
dst->sortWeapons();
auto iter = weapons.begin();
auto dstIter = dst->weapons.begin();
bool everAttacked = true;
bool dstEverAttacked = true;
do {
if (!isDead()) {
while (!(*iter)->attack(this, dst)) {
if (++iter == weapons.end()) {
iter = weapons.begin();
everAttacked = false;
break;
}
}
} else {
break;
}
if (!dst->isDead()) {
while (!(*dstIter)->attack(dst, this)) {
if (++dstIter == dst->weapons.end()) {
dstIter = dst->weapons.begin();
dstEverAttacked = false;
break;
}
}
} else {
break;
}
} while (weapons.size() && dst->weapons.size()
&& (everAttacked || dstEverAttacked));
}
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;
}
}
};
class Dragon : public Warrior {
private:
// double morale;
constexpr static auto name = "dragon";
public:
static int defaultStrength;
static int defaultAttack;
const char *const getName() const override { return name; }
// double getMorale() const { return morale; }
void describe() const override {
}
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.push_back(weapon::WeaponList[id % 3](this));
}
void attack(WarriorPtr dst) override {
Warrior::attack(dst);
if (!isDead()) {
// cheer
std::cout << epoch.format() << ' '
<< (territory ? "red" : "blue") << ' '
<< 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; }
void describe() const override {
}
Ninja(int id, Headquarter const &head)
: Warrior(id, head, defaultStrength, defaultAttack) {
weapons.push_back(weapon::WeaponList[id % 3](this));
weapons.push_back(weapon::WeaponList[(id + 1) % 3](this));
}
};
int Ninja::defaultStrength;
int Ninja::defaultAttack;
class Iceman : public Warrior {
private:
constexpr static auto name = "iceman";
constexpr static auto walkDamageRatio = 0.9;
public:
static int defaultStrength;
static int defaultAttack;
const char *const getName() const override { return name; }
void describe() const override {
}
Iceman(int id, Headquarter const &head)
: Warrior(id, head, defaultStrength, defaultAttack) {
weapons.push_back(weapon::WeaponList[id % 3](this));
}
void walk() override {
strength *= walkDamageRatio;
Warrior::walk();
}
};
int Iceman::defaultStrength;
int Iceman::defaultAttack;
class Lion : public Warrior {
private:
int loyalty;
bool escaped = false;
constexpr static auto name = "lion";
public:
static int defaultStrength;
static int defaultAttack;
static unsigned loyaltyDecrease;
const char *const getName() const override { return name; }
bool isLoyal() const {
return loyalty > 0;
}
void tryEscape() {
if (escaped) { return; }
if (!isLoyal() && position != (territory ? N + 1 : 0)) {
escaped = true;
std::cout << epoch.format() << ' '
<< (territory ? "red" : "blue") << ' ' << name << ' '
<< id << ' '
<< "ran away" << std::endl;
}
}
void walk() override {
loyalty -= loyaltyDecrease;
Warrior::walk();
}
void describe() const override {
std::cout << "Its loyalty is " << loyalty << std::endl;
}
Lion(int id, Headquarter const &head)
: Warrior(id, head, defaultStrength, defaultAttack) {
// decrement life in castle first before creating warrior!
weapons.push_back(weapon::WeaponList[id % 3](this));
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 describe() const override {}
void loot(WarriorPtr dst, int cityID) {
dst->sortWeaponsForLoot();
int counter = 0;
int previousType = 0x7f7f7f7f;
while (weapons.size() < 10) {
auto trophy = dst->weapons.front();
if (previousType == 0x7f7f7f7f) {
previousType = trophy->type;
} else if (previousType != trophy->type) {
break;
}
++counter;
weapons.push_back(dst->weapons.front());
dst->weapons.pop_front();
}
std::cout << epoch.format() << ' '
<< (territory ? "red" : "blue") << ' ' << name << ' '
<< id << ' '
<< "took " << counter << ' '
<< weapon::names[previousType] << ' '
<< "from " << (dst->territory ? "red" : "blue") << ' '
<< dst->getName() << ' ' << dst->id << ' '
<< "in city " << cityID << std::endl;
}
Wolf(int id, Headquarter const &head)
: Warrior(id, head, defaultStrength, defaultAttack) {
}
};
int Wolf::defaultStrength;
int Wolf::defaultAttack;
bool weapon::Sword::attack(WarriorPtr src, WarriorPtr dst) {
if (!usable()) { return false; }
dst->takeDamage(attackValue);
return true;
}
bool weapon::Arrow::attack(WarriorPtr src, WarriorPtr dst) {
if (!usable()) { return false; }
dst->takeDamage(attackValue);
--remaining;
return true;
}
bool weapon::Bomb::attack(WarriorPtr src, WarriorPtr dst) {
if (!usable()) { return false; }
auto newSrc = dynamic_cast<Ninja *>(src);
if (newSrc == nullptr) {
// not a ninja
src->takeDamage(attackValue / 2);
}
dst->takeDamage(attackValue);
used = true;
return true;
}
weapon::Sword::Sword(WarriorPtr warrior)
: weapon::Weapon(static_cast<int>(startRatio * warrior->getAttack()), 0) {}
weapon::Arrow::Arrow(WarriorPtr warrior)
: weapon::Weapon(static_cast<int>(startRatio * warrior->getAttack()), 2) {}
weapon::Bomb::Bomb(WarriorPtr warrior)
: weapon::Weapon(static_cast<int>(startRatio * warrior->getAttack()), 1) {}
template<typename T>
Warrior *make(int param1, Headquarter const &param2) {
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(std::string name, int strength, WarriorCreator seq[])
: strength(strength), name(std::move(name)),
warriorSequence(seq, seq + 5) {
for (const auto &a : warriorSequence) {
warriorsCounter.insert({a, 0});
}
}
void City::event0() {}
void City::event5() {
auto newRed = dynamic_cast<Lion *>(red);
if (newRed != nullptr) {
newRed->tryEscape();
}
auto newBlue = dynamic_cast<Lion *>(blue);
if (newBlue != nullptr) {
newBlue->tryEscape();
}
}
void City::event10() {
if (red != nullptr) {
red->walk();
}
if (blue != nullptr) {
blue->walk();
}
}
void City::event35() {
auto newRed = dynamic_cast<Wolf *>(red);
auto newBlue = dynamic_cast<Wolf *>(blue);
if (newRed != nullptr && newBlue != nullptr) {
return;
} else if (newRed == nullptr && newBlue == nullptr) {
return;
} else if (newRed != nullptr && blue != nullptr) {
newRed->loot(blue, id);
} else if (newBlue != nullptr && red != nullptr) {
newBlue->loot(red, id);
}
}
void City::event40() {
if (id % 2) {
red->attack(blue);
} else {
blue->attack(red);
}
}
void Headquarter::spawn() {
if (!running) {
return;
}
// int attempt = 0;
// while (strength < warriorSequence[currentWarriorIndex](0, *this)->getStrength()) {
// if (attempt++ >= 5) {
// std::cout << epoch.format() << ' '
// << name << ' '
// << "headquarter stops making warriors" << std::endl;
// running = false;
// return;
// }
// currentWarriorIndex = (currentWarriorIndex + 1) % 5;
// }
if (strength < warriorSequence[currentWarriorIndex](0, *this)->getStrength()) {
running = false;
return;
}
strength -= warriorSequence[currentWarriorIndex](0, *this)->getStrength();
auto newWarrior = warriorSequence[currentWarriorIndex](index++, *this);
++warriorsCounter[warriorSequence[currentWarriorIndex]];
std::cout << epoch.format() << ' '
<< name << ' '
<< newWarrior->getName() << ' '
<< newWarrior->getID() << ' '
<< "born with strength " << newWarrior->getStrength() << ','
<< warriorsCounter[warriorSequence[currentWarriorIndex]] << ' '
<< newWarrior->getName() << ' '
<< "in " << name << " headquarter" << std::endl;
newWarrior->describe();
warriors.push_back(newWarrior);
currentWarriorIndex = (currentWarriorIndex + 1) % 5;
}
void tick() {
redHead->spawn();
blueHead->spawn();
epoch.minute = 5;
// ++epoch;
}
void runEval(int caseNo) {
std::cout << "Case " << caseNo << ":" << std::endl;
// strength of headquarters
int M;
// end time
int T;
std::cin >> M;
std::cin >> N;
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);
while (redHead->getState() || blueHead->getState()) {
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