首页 > 编程语言 >北京大学程序设计MOOC-魔兽世界大作业(三)

北京大学程序设计MOOC-魔兽世界大作业(三)

时间:2023-01-08 10:35:07浏览次数:52  
标签:std MOOC 魔兽 string hour int 程序设计 minute name


程序设计-魔兽世界大作业

上一篇作业解析与代码:​​魔兽世界-装备​​

项目OJ提交:​​魔兽世界-开战​

思路与类架构

题目需求分析与设计

魔兽世界是两方阵营战斗的游戏,双方阵营制造武士,武士拥有武器。阵营中间是若干城市,武士在城市中行走。如果在一个城市中,两方不同阵营的武士碰面了,就会战斗。直到有武士过关斩将到了对面阵营,就算游戏结束,到达对面阵营的武士方取得胜利,有地方武士到达的阵营会爆炸。

这个题目细节非常多,包括如下:

【1】 行军细节

1.1.行军武士状态的细节:在行军的过程中,iceman武士边走边掉血;lion武士边走忠诚度越低。如果血掉光了,或者没有忠诚度了,就会从战场消失(或叛逃,即消失),但是已经到对面的lion不会叛逃。
1.2.行军消息播报的细节:在播报的时候,是要按照城市编号顺序播报的。所以在代码中设计了printCities对象,这是存储播报信息的。为什么要设计这个对象呢?因为:如果有武士到达对面阵营,游戏终止,但是同时刻还有其他武士的行军,这也是要播报的。如果游戏逻辑和播报逻辑不分离的话,那就无法处理其他武士行军的播报了

【2】战斗细节

2.1. 武器的使用细节:在战斗的过程中,双方武士先会按照顺序(详情见题目)对武器排序,然后按顺序循环使用武器,即“一件件使用武器”。题目中说:“如果有多件同类型的武器,则都要用上”,这句话没有必要提,因为同类型的武器,循环使用,也都会用上,不会出现用不上的情况。千万不要理解成:如果同类型的武器,则一次性用上,我在这里踩坑了!
2.2.战斗结果的细节:战斗有四种结果,红方武士战胜了蓝方;蓝方武士战胜了红方;两方都还活着,平局;两方都阵亡了,也是平局。然后战斗结束后,战胜的一方要俘获战败方的武器,要注意武器的使用更新。
2.3.战斗终止的细节:有两种条件会引起战斗终止:有至少一方阵亡了,战斗终止,活着的武士仍在当前城市,准备下一次的行军和战斗;两方都存活,这时两边的武士都会准备下一次的行军和战斗。判断有一方阵亡很容易,但是如何判断两方都存活呢
2.4.判断战斗是否平局的细节:一次战斗在这种情况下会平局:已经没有可用的武器了会平局,同时,两方武士拥有的所有武器都无法向对面造成伤害了。所以在循环使用武器的过程中,要更新武器的状态,我设计的是:在循环使用武器时,会做判断当前武器是否可用,如果连续size个武器无法使用则没有武器了,size表示战斗开始时总武器数量。并且要设计获得当前武器能造成的最高伤害的方法,如果两边的武器都无法造成伤害,并且也没有可用的武器了,那就不需要战斗了。

【3】城市信息细节

这个游戏是按照时间顺序播报的,且播报任务按照城市编号顺序进行。所以,不应该由武士、阵营管理播报信息,而是由城市来管理。一个城市有四个重要信息:红方武士信息,蓝方武士信息,红方武士播报信息,蓝方武士播报信息。我觉得有两点重要:①武士的移动会导致当前城市的武士为NULL,并将当前武士移交给下一个城市;②我的设计是把所有武士的播报信息先交给城市管理,缓存,实现播报和武士行为分开,然后单独处理城市播报逻辑。

整体的类架构关系如下

阵营→制造武士,武士→拥有武器。武士类以及武器类都是基类,具体的不同的武士有不同的行为和属性,因此具体的武士是派生类;武器相对单一,且任意时刻制造的相同类型的武器都一样,所以武器实现了武器池,通过工厂模式按模板制造武器

由于城市对象是全局共有的,且代码实现中并没有太复杂的逻辑关系。这里的逻辑关系指多态性,武士和武器的多态关系复杂些,所以城市并没有设计类,而是采用STL实现。

AC代码实现细节

#include <cstdio>
#include <string>
#include <vector>
#include <unordered_map>
#include <memory>
#include <list>
#include <algorithm>

struct ATTACK {
int first, second;
};
// 0-sword, 1-bomb, 2-arrow
const ATTACK atk[3] = {
{2, 10}, {4, 10}, {3, 10}
};

std::unordered_map<std::string, int> iniCity;
std::unordered_map<std::string, int> warriorStrength;
std::unordered_map<std::string, int> warriorHealth;

class Controller;
class Weapon;
class Warrior;
class Wolf;

using ShWp = std::shared_ptr<Weapon>;
using ShWr = std::shared_ptr<Warrior>;
enum ATTACK_STATE { RED_IS_ATTACKER, BLUE_IS_ATTACKER };
bool cmpRob(const ShWp& wp1, const ShWp& wp2);
bool cmpBattle(const ShWp& wp1, const ShWp& wp2);

// cities[i] = {red_wr, blue_wr} or {red_wr, null} or {null, blue_wr}
std::vector<std::pair<ShWr, ShWr>> cities;
std::vector<std::pair<std::string, std::string>> printCities;

class Warrior {
friend class Controller;
friend class Dragon;
friend class Ninja;
friend class Iceman;
friend class Lion;
friend class Wolf;
protected:
std::string camp, name;
int id, health, strength, remMeta, curCity;
std::list<ShWp> weapons;
std::unordered_map<std::string, int> wpCount;

public:
int getHealth() const { return health; }
int getStrength() const { return strength; }
virtual std::string getName() const = 0;
virtual std::string getCamp() const = 0;
void setHealth(int health_) { health = health_; }

public:
Warrior(
const std::string& camp_,
const std::string& name_,
int id_, int health_, int strength_,
int remMeta_, int curCity_
) : camp(camp_), name(name_), id(id_), health(health_),
strength(strength_), remMeta(remMeta_), curCity(curCity_) { }

virtual void born(int hour, int minute) {
printf("%03d:%02d %s %s %d born\n",
hour, minute, camp.c_str(), name.c_str(), id);
}

void capture(ShWr& loser);
int getMaxAttack();
bool isWithoutBombAndArrow() const;
void clearWeapon();

/// <summary>
/// return the marched city information, such as:
/// "RED_WIN" is reputed "Red Headquarter is winner",
/// "BLUE_WIN" is reputed "Blue Headquarter is winner",
/// "KEEP_ON" is reputed "Please go on"
/// </summary>
virtual std::string march(int hour, int minute) {
if (health <= 0) { return "KEEP_ON"; }
char buf[256] = { '\0' };
if ("red" == camp) {
curCity = std::min(curCity + 1, iniCity["blue"]);
if (curCity == iniCity["blue"]) {
snprintf(buf, sizeof(buf) - 1, "%03d:%02d red %s %d reached blue headquarter with %d elements and force %d\n%03d:%02d blue headquarter was taken\n",
hour, minute, name.c_str(), id, health, strength, hour, minute);
printCities[curCity].first = std::string(buf);
return "RED_WIN";
}
else {
snprintf(buf, sizeof(buf) - 1, "%03d:%02d red %s %d marched to city %d with %d elements and force %d\n",
hour, minute, name.c_str(), id, curCity, health, strength);
printCities[curCity].first = std::string(buf);
}
}
else {
curCity = std::max(curCity - 1, iniCity["red"]);
if (curCity == iniCity["red"]) {
snprintf(buf, sizeof(buf) - 1, "%03d:%02d blue %s %d reached red headquarter with %d elements and force %d\n%03d:%02d red headquarter was taken\n",
hour, minute, name.c_str(), id, health, strength, hour, minute);
printCities[curCity].second = std::string(buf);
return "BLUE_WIN";
}
else {
snprintf(buf, sizeof(buf) - 1, "%03d:%02d blue %s %d marched to city %d with %d elements and force %d\n",
hour, minute, name.c_str(), id, curCity, health, strength);
printCities[curCity].second = std::string(buf);
}
}
return "KEEP_ON";
}

virtual ~Warrior() { }
};

using CITY = std::vector<std::pair<ShWr, ShWr>>;
using CITY_INFO = std::vector<std::pair<std::string, std::string>>;
void setWarroirInCity(int cityIdx, ShWr& wr, CITY& city) {
if ("red" == wr->getCamp()) { city[cityIdx].first = wr; }
else if ("blue" == wr->getCamp()) { city[cityIdx].second = wr; }
}

void copyCityFrom(CITY& outCity, const CITY& inCity) {
int citySize = (int)outCity.size();
if (outCity.size() != inCity.size()) { return; }
for (int i = 0; i < citySize; ++i) {
outCity[i].first = inCity[i].first;
outCity[i].second = inCity[i].second;
}
}

void clearCitiesInfo(CITY_INFO& info) {
int citySize = (int)info.size();
for (int i = 0; i < citySize; ++i) {
printCities[i].first = printCities[i].second = "NULL";
}
}

void printCitiesInfo(CITY_INFO& info) {
int citySize = (int)info.size();
for (int i = 0; i < citySize; ++i) {
if ("NULL" != printCities[i].first) { printf("%s", printCities[i].first.c_str()); }
if ("NULL" != printCities[i].second) { printf("%s", printCities[i].second.c_str()); }
}
clearCitiesInfo(printCities);
}

class Weapon {
protected:
bool canUsed;
public:
Weapon(bool canUsed_ = true) : canUsed(canUsed_) { }

/// <returns>return the current attack to attacked.</returns>
int baseAttack(ShWr& attacker, ShWr& attacked, const ATTACK& atk) {
int curAttack = attacker->getStrength() * atk.first / atk.second;
int curHealth = attacked->getHealth() - curAttack;
attacked->setHealth(curHealth);
return curAttack;
}

virtual int attack(ShWr& attacker, ShWr& attacked) = 0;
virtual std::shared_ptr<Weapon> createWeapon() = 0;
virtual int getWeaponID() const = 0;
virtual std::string getWeaponName() const = 0;

bool getCanUsed() const { return canUsed; }
};

class Sword : public Weapon {
private:
static int weaponID;
static std::string weaponName;
public:
int attack(ShWr& attacker, ShWr& attacked) {
return baseAttack(attacker, attacked, atk[0]);
}

ShWp createWeapon() { return std::make_shared<Sword>(); }
int getWeaponID() const { return weaponID; }
std::string getWeaponName() const { return weaponName; }
};
std::string Sword::weaponName = "sword";
int Sword::weaponID = 0;

class Bomb : public Weapon {
private:
int usableNums;
static int weaponID;
static std::string weaponName;

public:
Bomb() : usableNums(1) { }

int attack(ShWr& attacker, ShWr& attacked) {
int attackToSelf = -1;
if (usableNums > 0) {
attackToSelf = baseAttack(attacker, attacked, atk[1]);
usableNums--;
if (usableNums <= 0) { canUsed = false; }
if ("ninja" != attacker->getName()) {
attackToSelf = attackToSelf * 5 / 10;
int curUserHealth = attacker->getHealth();
int userHealth = curUserHealth - attackToSelf;
attacker->setHealth(userHealth);
}
}
return attackToSelf;
}

ShWp createWeapon() { return std::make_shared<Bomb>(); }
int getWeaponID() const { return weaponID; }
std::string getWeaponName() const { return weaponName; }
};
std::string Bomb::weaponName = "bomb";
int Bomb::weaponID = 1;

class Arrow : public Weapon {
private:
int usableNums;
static int weaponID;
static std::string weaponName;

public:
Arrow() : usableNums(2) { }

int attack(ShWr& attacker, ShWr& attacked) {
int curAtk = -1;
if (usableNums > 0) {
usableNums--;
if (usableNums <= 0) { canUsed = false; }
curAtk = baseAttack(attacker, attacked, atk[2]);
}
return curAtk;
}

ShWp createWeapon() { return std::make_shared<Arrow>(); }
int getWeaponID() const { return weaponID; }
std::string getWeaponName() const { return weaponName; }
int getUsableNums() const { return usableNums; }
};
std::string Arrow::weaponName = "arrow";
int Arrow::weaponID = 2;

const std::vector<ShWp> WEAPONPOOL = {
std::make_shared<Sword>(), std::make_shared<Bomb>(), std::make_shared<Arrow>()
};

bool cmpRob(const ShWp& wp1, const ShWp& wp2) {
int wid1 = wp1->getWeaponID();
int wid2 = wp2->getWeaponID();
if ("arrow" == wp1->getWeaponName() && "arrow" == wp2->getWeaponName()) {
int usable1 = std::dynamic_pointer_cast<Arrow>(wp1)->getUsableNums();
int usable2 = std::dynamic_pointer_cast<Arrow>(wp2)->getUsableNums();
if (usable1 != usable2) { return usable1 < usable2; }
}
return wid1 > wid2;
}

bool cmpBattle(const ShWp& wp1, const ShWp& wp2) {
int wid1 = wp1->getWeaponID();
int wid2 = wp2->getWeaponID();
if ("arrow" == wp1->getWeaponName() && "arrow" == wp2->getWeaponName()) {
int usable1 = std::dynamic_pointer_cast<Arrow>(wp1)->getUsableNums();
int usable2 = std::dynamic_pointer_cast<Arrow>(wp2)->getUsableNums();
if (usable1 != usable2) { return usable1 < usable2; }
}
return wid1 < wid2;
}

int Warrior::getMaxAttack() {
int res = 0;
for (const auto& wp : weapons) {
if (!wp->getCanUsed()) { continue; }
int curAtk = 0, wpId = 0;
if ("sword" == wp->getWeaponName()) { wpId = 0; }
else if ("bomb" == wp->getWeaponName()) { wpId = 1; }
else if ("arrow" == wp->getWeaponName()) { wpId = 2; }
curAtk = strength * atk[wpId].first / atk[wpId].second;
res = std::max(res, curAtk);
}
return res;
}

bool Warrior::isWithoutBombAndArrow() const {
bool res = true;
for (const auto& wp : weapons) {
if (!wp->getCanUsed()) { continue; }
std::string curWpName = wp->getWeaponName();
if ("bomb" == curWpName || "arrow" == curWpName) { return false; }
}
return true;
}

void Warrior::clearWeapon() {
std::list<ShWp>::iterator itr = weapons.begin();
std::vector<std::list<ShWp>::iterator> willErase;
for (; weapons.end() != itr; ++itr) {
if (!(*itr)->getCanUsed()) {
willErase.push_back(itr);
--wpCount[(*itr)->getWeaponName()];
}
}
for (auto& itr : willErase) { weapons.erase(itr); }
}

void Warrior::capture(ShWr& loser) {
loser->clearWeapon();
loser->weapons.sort(cmpRob);
int curWpSize = (int)weapons.size();
while (curWpSize <= 10 && !loser->weapons.empty()) {
ShWp& wp = loser->weapons.back();
if (!wp->getCanUsed()) { continue; }
weapons.push_back(wp);
++wpCount[wp->getWeaponName()];
--loser->wpCount[wp->getWeaponName()];
loser->weapons.pop_back();
curWpSize++;
}
}

class Dragon : public Warrior {
private:
static std::string name;

public:
Dragon(
const std::string& camp_,
int id_, int health_, int strength_, int remMeta_, int curCity_
) : Warrior(camp_, name, id_, health_, strength_, remMeta_, curCity_) {
weapons.push_back(WEAPONPOOL[id_ % 3]->createWeapon());
++wpCount[WEAPONPOOL[id_ % 3]->getWeaponName()];
}

std::string getName() const { return name; }
std::string getCamp() const { return camp; }

void hail(int hour, int minute, int cityId) {
printf("%03d:%02d %s dragon %d yelled in city %d\n",
hour, minute, camp.c_str(), id, cityId);
}
};
std::string Dragon::name = "dragon";

class Ninja : public Warrior {
private:
static std::string name;

public:
Ninja(
const std::string& camp_,
int id_, int health_, int strength_, int remMeta_, int curCity_
) : Warrior(camp_, name, id_, health_, strength_, remMeta_, curCity_) {
weapons.push_back(WEAPONPOOL[id_ % 3]->createWeapon());
++wpCount[WEAPONPOOL[id_ % 3]->getWeaponName()];
weapons.push_back(WEAPONPOOL[(id_ + 1) % 3]->createWeapon());
++wpCount[WEAPONPOOL[(id_ + 1) % 3]->getWeaponName()];
}

std::string getName() const { return name; }
std::string getCamp() const { return camp; }
};
std::string Ninja::name = "ninja";

class Iceman : public Warrior {
private:
static std::string name;

public:
Iceman(
const std::string& camp_,
int id_, int health_, int strength_, int remMeta_, int curCity_
) : Warrior(camp_, name, id_, health_, strength_, remMeta_, curCity_) {
weapons.push_back(WEAPONPOOL[id_ % 3]->createWeapon());
++wpCount[WEAPONPOOL[id_ % 3]->getWeaponName()];
}

std::string getName() const { return name; }
std::string getCamp() const { return camp; }

std::string march(int hour, int minute) {
int decHealth = health / 10;
health -= decHealth;
return Warrior::march(hour, minute);
}
};
std::string Iceman::name = "iceman";

class Lion : public Warrior {
private:
int loyalty;
static std::string name;

public:
Lion(
const std::string& camp_,
int id_, int health_, int strength_, int remMeta_, int curCity_
) : Warrior(camp_, name, id_, health_, strength_, remMeta_, curCity_), loyalty(remMeta_) {
weapons.push_back(WEAPONPOOL[id_ % 3]->createWeapon());
++wpCount[WEAPONPOOL[id_ % 3]->getWeaponName()];
}

void born(int hour, int minute) {
Warrior::born(hour, minute);
printf("Its loyalty is %d\n", loyalty);
}

void runAway(int hour, int minute) {
printf("%03d:%02d %s lion %d ran away\n",
hour, minute, camp.c_str(), id);
}

std::string getName() const { return name; }
std::string getCamp() const { return camp; }
int getLoyalty() const { return loyalty; }
int getCity() const { return curCity; }

std::string march(int hour, int minute, int K) {
loyalty -= K;
return Warrior::march(hour, minute);
}
};
std::string Lion::name = "lion";

class Wolf : public Warrior {
private:
static std::string name;

public:
Wolf(
const std::string& camp_,
int id_, int health_, int strength_, int remMeta_, int curCity_
) : Warrior(camp_, name, id_, health_, strength_, remMeta_, curCity_) { }

void grab(ShWr& enemy, int hour, int minute, int cityId) {
if (enemy->weapons.empty()) { return; }
enemy->weapons.sort(cmpRob);
if ("wolf" != enemy->getName()) {
int curWpSize = (int)weapons.size(), wpIdx = 0;
int* robCntPtr = nullptr;
std::string robWp = "NULL";
// sword-0, bomb-1, arrow-2
if (enemy->wpCount["sword"] > 0) {
robCntPtr = &enemy->wpCount["sword"], robWp = "sword";
}
else if (enemy->wpCount["bomb"] > 0) {
robCntPtr = &enemy->wpCount["bomb"], robWp = "bomb";
}
else if (enemy->wpCount["arrow"] > 0) {
robCntPtr = &enemy->wpCount["arrow"], robWp = "arrow";
}
if (!robCntPtr) { return; }
int canBeRob = std::min(*robCntPtr, 10 - curWpSize);
if (canBeRob > 0 && curWpSize <= 10) {
printf("%03d:%02d %s %s %d took %d %s from %s %s %d in city %d\n",
hour, minute, camp.c_str(), name.c_str(), id, canBeRob, robWp.c_str(),
enemy->camp.c_str(), enemy->name.c_str(), enemy->id, cityId);
while (canBeRob > 0 && curWpSize <= 10) {
if (enemy->weapons.empty()) {
break;
}
ShWp& curWp = enemy->weapons.back();
++wpCount[curWp->getWeaponName()];
weapons.push_back(curWp);
enemy->weapons.pop_back();
++curWpSize, --canBeRob;
--* robCntPtr;
}
}
}
}

std::string getName() const { return name; }
std::string getCamp() const { return camp; }
};
std::string Wolf::name = "wolf";

using ShWr = std::shared_ptr<Warrior>;
class Headquarter {
friend class Controller;
private:
std::string name;
std::vector<std::string> order;
std::list<ShWr> warroirs;
int healthMeta, curID;
bool canBornWr;
size_t curIdx;

public:
Headquarter(
const std::string& name_,
const std::vector<std::string>& order_, int healthMeta_
) : name(name_), order(order_), healthMeta(healthMeta_),
curID(1), canBornWr(true), curIdx(0) { }

void born(int hour, int minute) {
if (!canBornWr) {
return;
}
std::string curWr = order[curIdx];
int curHealth = warriorHealth[curWr];
if (healthMeta < curHealth) {
canBornWr = false;
return;
}
int curStrength = warriorStrength[curWr];
int curCity = iniCity[name];
healthMeta -= curHealth;
curIdx = (curIdx + 1) % order.size();
if ("dragon" == curWr) {
warroirs.push_back(std::make_shared<Dragon>(name, curID,
curHealth, curStrength, healthMeta, curCity));
}
else if ("ninja" == curWr) {
warroirs.push_back(std::make_shared<Ninja>(name, curID,
curHealth, curStrength, healthMeta, curCity));
}
else if ("iceman" == curWr) {
warroirs.push_back(std::make_shared<Iceman>(name, curID,
curHealth, curStrength, healthMeta, curCity));
}
else if ("lion" == curWr) {
warroirs.push_back(std::make_shared<Lion>(name, curID,
curHealth, curStrength, healthMeta, curCity));
}
else if ("wolf" == curWr) {
warroirs.push_back(std::make_shared<Wolf>(name, curID,
curHealth, curStrength, healthMeta, curCity));
}
warroirs.back()->born(hour, minute);
setWarroirInCity(curCity, warroirs.back(), cities);
curID++;
}
};

class Controller {
public:
static void runAway(Headquarter& red, Headquarter& blue, int hour, int minute) {
int citySize = (int)cities.size();
for (int i = 0; i < citySize; ++i) {
ShWr& redWr = cities[i].first;
ShWr& blueWr = cities[i].second;
if (redWr && "lion" == redWr->name) {
int targetCity = iniCity["blue"];
std::shared_ptr<Lion> tempRedLionPtr =
std::dynamic_pointer_cast<Lion>(redWr);
int curLoyalty = tempRedLionPtr->getLoyalty();
int curCity = tempRedLionPtr->getCity();
if (curLoyalty <= 0 && curCity != targetCity) {
tempRedLionPtr->runAway(hour, minute);
red.warroirs.remove(redWr);
cities[redWr->curCity].first = nullptr;
}
}
if (blueWr && "lion" == blueWr->name) {
int targetCity = iniCity["red"];
std::shared_ptr<Lion> tempBlueLionPtr =
std::dynamic_pointer_cast<Lion>(blueWr);
int curLoyalty = tempBlueLionPtr->getLoyalty();
int curCity = tempBlueLionPtr->getCity();
if (curLoyalty <= 0 && curCity != targetCity) {
tempBlueLionPtr->runAway(hour, minute);
red.warroirs.remove(redWr);
cities[blueWr->curCity].second = nullptr;
}
}
}
}

static std::string wrMarch(ShWr& wr, int hour, int minute, int K, CITY& tempCity) {
std::string retInfo = "KEEP_ON";
if ("lion" == wr->name) {
std::shared_ptr<Lion> tempLionPtr =
std::dynamic_pointer_cast<Lion>(wr);
retInfo = tempLionPtr->march(hour, minute, K);
}
else {
retInfo = wr->march(hour, minute);
}
setWarroirInCity(wr->curCity, wr, tempCity);
return retInfo;
}

static std::string march(Headquarter& red, Headquarter& blue, int hour, int minute, int K) {
std::string retInfo = "KEEP_ON";
int citySize = (int)cities.size();
std::vector<std::pair<ShWr, ShWr>> tempCities;
tempCities.resize(citySize, { nullptr, nullptr });
for (int i = 0; i < citySize; ++i) {
ShWr& redWr = cities[i].first;
ShWr& blueWr = cities[i].second;
if (redWr) {
std::string curInfo = wrMarch(redWr, hour, minute, K, tempCities);
if ("KEEP_ON" == retInfo && "KEEP_ON" != curInfo) { retInfo = curInfo; }
if (redWr->health <= 0) { tempCities[redWr->curCity].first = nullptr; }
}
if (blueWr) {
std::string curInfo = wrMarch(blueWr, hour, minute, K, tempCities);
if ("KEEP_ON" == retInfo && "KEEP_ON" != curInfo) { retInfo = curInfo; }
if (blueWr->health <= 0) { tempCities[blueWr->curCity].second = nullptr; }
}
}
if ("KEEP_ON" != retInfo) { return retInfo; }
copyCityFrom(cities, tempCities);
clearWarroir(red);
clearWarroir(blue);
return retInfo;
}

static void grab(int hour, int minute) {
int citySize = (int)cities.size(); // citySize >= 2
for (int i = 1; i < citySize - 1; ++i) {
if (!cities[i].first || !cities[i].second) { continue; }
if ("wolf" == cities[i].first->name) {
std::shared_ptr<Wolf> tempWolfPtr =
std::dynamic_pointer_cast<Wolf>(cities[i].first);
tempWolfPtr->grab(cities[i].second, hour, minute, i);
}
else if ("wolf" == cities[i].second->name) {
std::shared_ptr<Wolf> tempWolfPtr =
std::dynamic_pointer_cast<Wolf>(cities[i].second);
tempWolfPtr->grab(cities[i].first, hour, minute, i);
}
}
}

static void clearWarroir(Headquarter& hq) {
std::list<ShWr>::iterator itr = hq.warroirs.begin();
std::vector<std::list<ShWr>::iterator> willErase;
for (; itr != hq.warroirs.end(); ++itr) {
if ((*itr)->health <= 0) {
int itrCity = (*itr)->curCity;
if ("red" == (*itr)->camp) { cities[itrCity].first = nullptr; }
else { cities[itrCity].second = nullptr; }
willErase.push_back(itr);
}
}
for (auto& itr : willErase) { hq.warroirs.erase(itr); }
}

static void printBattle(int hour, int minute, int cityIdx, ShWr& loser, ShWr& winner) {
printf("%03d:%02d %s %s %d killed %s %s %d in city %d remaining %d elements\n",
hour, minute, winner->camp.c_str(), winner->name.c_str(),
winner->id, loser->camp.c_str(), loser->name.c_str(), loser->id,
cityIdx, winner->health);
winner->capture(loser);
if ("red" == loser->camp) { cities[cityIdx].first = nullptr; }
else if ("blue" == loser->camp) { cities[cityIdx].second = nullptr; }
}

static void procBattle(std::list<ShWp>::iterator& wpItr, ShWr& attacker, ShWr& attacked) {
if (wpItr == attacker->weapons.end()) { return; }
int cnt = 0;
while (!(*wpItr)->getCanUsed()) {
if (cnt == (int)attacker->weapons.size()) { return; }
++wpItr;
++cnt;
if (wpItr == attacker->weapons.end()) {
wpItr = attacker->weapons.begin();
}
}
ShWp& curWp = *wpItr;
std::string wpName = curWp->getWeaponName();
int res = curWp->attack(attacker, attacked);
++wpItr;
if (wpItr == attacker->weapons.end()) {
wpItr = attacker->weapons.begin();
}
}

static bool procPrintBattle(int hour, int minute, int cityIdx, ShWr& wr1, ShWr& wr2) {
if (wr1->health > 0 && wr2->health > 0) { return true; }
else if (wr1->health > 0 && wr2->health <= 0) {
printBattle(hour, minute, cityIdx, wr2, wr1);
}
else if (wr1->health <= 0 && wr2->health > 0) {
printBattle(hour, minute, cityIdx, wr1, wr2);
}
else if (wr1->health <= 0 && wr2->health <= 0) {
ShWr redWr = nullptr, blueWr = nullptr;
if ("red" == wr1->camp) { redWr = wr1, blueWr = wr2; }
else { redWr = wr2, blueWr = wr1; }
printf("%03d:%02d both red %s %d and blue %s %d died in city %d\n",
hour, minute, redWr->name.c_str(), redWr->id,
blueWr->name.c_str(), blueWr->id, cityIdx);
cities[cityIdx].first = cities[cityIdx].second = nullptr;
}
return false;
}

static void battleRound(int hour, int minute, int cityIdx, ShWr& attacker, ShWr& attacked, bool& isAllAlive) {
isAllAlive = true;
std::list<ShWp>::iterator attackerItr = attacker->weapons.begin();
std::list<ShWp>::iterator attackedItr = attacked->weapons.begin();
while (attacker->health > 0 && attacked->health > 0) {
procBattle(attackerItr, attacker, attacked);
if (!procPrintBattle(hour, minute, cityIdx, attacker, attacked)) {
isAllAlive = false; break;
}
procBattle(attackedItr, attacked, attacker);
if (!procPrintBattle(hour, minute, cityIdx, attacked, attacker)) {
isAllAlive = false; break;
}
if (attacker->isWithoutBombAndArrow() && attacked->isWithoutBombAndArrow() &&
!attacker->getMaxAttack() && !attacked->getMaxAttack()) {
break;
}
}
if (attacker) { attacker->clearWeapon(); }
if (attacked) { attacked->clearWeapon(); }
}

static void battle(int hour, int minute, Headquarter& red, Headquarter& blue) {
int citySize = (int)cities.size();
for (int cityIdx = 1; cityIdx < citySize - 1; ++cityIdx) {
auto& redWr = cities[cityIdx].first;
auto& blueWr = cities[cityIdx].second;
if (!redWr || !blueWr) { continue; }
redWr->weapons.sort(cmpBattle), blueWr->weapons.sort(cmpBattle);
if (redWr->health > 0 && blueWr->health > 0) {
bool isAllAlive = true;
if (cityIdx & 1) {
battleRound(hour, minute, cityIdx, redWr, blueWr, isAllAlive);
}
else {
battleRound(hour, minute, cityIdx, blueWr, redWr, isAllAlive);
}
if (isAllAlive) {
printf("%03d:%02d both red %s %d and blue %s %d were alive in city %d\n",
hour, minute, redWr->name.c_str(), redWr->id,
blueWr->name.c_str(), blueWr->id, cityIdx);
}
}
if (redWr && redWr->health > 0 && "dragon" == redWr->name) {
yell(hour, minute, cityIdx, "red", redWr);
}
if (blueWr && blueWr->health > 0 && "dragon" == blueWr->name) {
yell(hour, minute, cityIdx, "blue", blueWr);
}
}
clearWarroir(red);
clearWarroir(blue);
}

static void reportHealthOfHQ(const Headquarter& hq, int hour, int minute) {
printf("%03d:%02d %d elements in %s headquarter\n",
hour, minute, hq.healthMeta, hq.name.c_str());
}

static void reportWpOfWr(int hour, int minute) {
int citySize = (int)cities.size();
for (int i = 0; i < citySize; ++i) {
ShWr& redWr = cities[i].first;
ShWr& blueWr = cities[i].second;
if (redWr) {
redWr->clearWeapon();
printf("%03d:%02d red %s %d has %d sword %d bomb %d arrow and %d elements\n",
hour, minute, redWr->name.c_str(), redWr->id, redWr->wpCount["sword"],
redWr->wpCount["bomb"], redWr->wpCount["arrow"], redWr->health);
}
if (blueWr) {
blueWr->clearWeapon();
printf("%03d:%02d blue %s %d has %d sword %d bomb %d arrow and %d elements\n",
hour, minute, blueWr->name.c_str(), blueWr->id, blueWr->wpCount["sword"],
blueWr->wpCount["bomb"], blueWr->wpCount["arrow"], blueWr->health);
}
}
}

static void yell(int hour, int minute, int cityIdx,
const std::string& hq, const ShWr& wr) {
printf("%03d:%02d %s dragon %d yelled in city %d\n",
hour, minute, hq.c_str(), wr->id, cityIdx);
}
};

int main() {
int caseNums;
scanf("%d", &caseNums);
for (int cs = 1; cs <= caseNums; ++cs) {
int M, N, K, T;
int dragonS, ninjaS, icemanS, lionS, wolfS;
int dragonH, ninjaH, icemanH, lionH, wolfH;
scanf("%d%d%d%d%d%d%d%d%d%d%d%d%d%d", &M, &N, &K, &T,
&dragonH, &ninjaH, &icemanH, &lionH, &wolfH,
&dragonS, &ninjaS, &icemanS, &lionS, &wolfS);
iniCity["red"] = 0;
iniCity["blue"] = N + 1;
cities.resize(N + 2, { nullptr, nullptr });
printCities.resize(N + 2, { "NULL", "NULL" });
warriorStrength = {
{"dragon", dragonS}, {"ninja", ninjaS},
{"iceman", icemanS}, {"lion", lionS}, {"wolf", wolfS}
};
warriorHealth = {
{"dragon", dragonH}, {"ninja", ninjaH},
{"iceman", icemanH}, {"lion", lionH}, {"wolf", wolfH}
};
Headquarter red(
"red", { "iceman", "lion", "wolf", "ninja", "dragon" }, M);
Headquarter blue(
"blue", { "lion", "dragon", "ninja", "iceman","wolf" }, M);
printf("Case %d:\n", cs);
for (int curTime = 0; curTime <= T; ++curTime) {
int hour = curTime / 60, minute = curTime % 60;
if (0 == minute) {
red.born(hour, minute);
blue.born(hour, minute);
}
else if (5 == minute) {
Controller::runAway(red, blue, hour, minute);
}
else if (10 == minute) {
std::string retInfo = Controller::march(red, blue, hour, minute, K);
printCitiesInfo(printCities);
if ("KEEP_ON" != retInfo) { break; }
}
else if (35 == minute) {
Controller::grab(hour, minute);
}
else if (40 == minute) {
Controller::battle(hour, minute, red, blue);
}
else if (50 == minute) {
Controller::reportHealthOfHQ(red, hour, minute);
Controller::reportHealthOfHQ(blue, hour, minute);
}
else if (55 == minute) {
Controller::reportWpOfWr(hour, minute);
}
}
cities.clear();
printCities.clear();
}
return 0;
}

总结

总算解决掉魔兽世界大作业三部曲了!去年学习北大这门MOOC的时候,一共45道作业题我就差这一道没做出来了,今年圆梦。辛辛苦苦编码+Debug连续干了七八天,希望后续继续学习面向对象和系统设计的过程中有新的思路,并且得以改进!期待下一部:魔兽世界-终极版吧!附上提交截图:

北京大学程序设计MOOC-魔兽世界大作业(三)_课程设计


标签:std,MOOC,魔兽,string,hour,int,程序设计,minute,name
From: https://blog.51cto.com/u_15262702/5996521

相关文章