北京大学MOOC 程序设计与算法(三)魔兽世界三(开战)

魔兽世界三(开战)

题目来源

北京大学MOOC 程序设计与算法(三)魔兽世界3(2020秋季)

题目描述

魔兽世界三(开战)

总时间限制: 2000ms 内存限制: 65536kB

魔兽世界的西面是红魔军的司令部,东面是蓝魔军的司令部。两个司令部之间是依次排列的若干城市,城市从西向东依次编号为1,2,3 … N ( N <= 20)。红魔军的司令部算作编号为0的城市,蓝魔军的司令部算作编号为N+1的城市。司令部有生命元,用于制造武士。

两军的司令部都会制造武士。武士一共有dragon 、ninja、iceman、lion、wolf 五种。每种武士都有编号、生命值、攻击力这三种属性。

双方的武士编号都是从1开始计算。红方制造出来的第n 个武士,编号就是n。同样,蓝方制造出来的第n 个武士,编号也是n。

武士在刚降生的时候有一个初始的生命值,生命值在战斗中会发生变化,如果生命值减少到0(生命值变为负数时应当做变为0处理),则武士死亡(消失)。

武士可以拥有武器。武器有三种,sword, bomb,和arrow,编号分别为0,1,2。

sword的攻击力是使用者当前攻击力的20%(去尾取整)。

bomb的攻击力是使用者当前攻击力的40%(去尾取整),但是也会导致使用者受到攻击,对使用者的攻击力是对敌人取整后的攻击力的1/2(去尾取整)。Bomb一旦使用就没了。

arrow的攻击力是使用者当前攻击力的30%(去尾取整)。一个arrow用两次就没了。

武士降生后就朝对方司令部走,在经过的城市如果遇到敌人(同一时刻每个城市最多只可能有1个蓝武士和一个红武士),就会发生战斗。战斗的规则是:

在奇数编号城市,红武士先发起攻击

在偶数编号城市,蓝武士先发起攻击

战斗开始前,双方先对自己的武器排好使用顺序,然后再一件一件地按顺序使用。编号小的武器,排在前面。若有多支arrow,用过的排在前面。排好序后,攻击者按此排序依次对敌人一件一件地使用武器。如果一种武器有多件,那就都要用上。每使用一件武器,被攻击者生命值要减去武器攻击力。如果任何一方生命值减为0或小于0即为死去。有一方死去,则战斗结束。

双方轮流使用武器,甲用过一件,就轮到乙用。某一方把自己所有的武器都用过一轮后,就从头开始再用一轮。如果某一方没有武器了,那就挨打直到死去或敌人武器用完。武器排序只在战斗前进行,战斗中不会重新排序。

如果双方武器都用完且都还活着,则战斗以平局结束。如果双方都死了,也算平局。

有可能由于武士自身攻击力太低,而导致武器攻击力为0。攻击力为0的武器也要使用。如果战斗中双方的生命值和武器的状态都不再发生变化,则战斗结束,算平局。

战斗的胜方获得对方手里的武器。武士手里武器总数不超过10件。缴获武器时,按照武器种类编号从小到大缴获。如果有多件arrow,优先缴获没用过的。

如果战斗开始前双方都没有武器,则战斗视为平局。如果先攻击方没有武器,则由后攻击方攻击。

不同的武士有不同的特点。

编号为n的dragon降生时即获得编号为n%3 的武器。dragon在战斗结束后,如果还没有战死,就会欢呼。

编号为n的ninjia降生时即获得编号为n%3 和(n+1)%3的武器。ninja 使用bomb不会让自己受伤。

编号为n的iceman降生时即获得编号为n%3 的武器。iceman每前进一步,生命值减少10%(减少的量要去尾取整)。

编号为n的lion降生时即获得编号为n%3 的武器。lion 有“忠诚度”这个属性,其初始值等于它降生之后其司令部剩余生命元的数目。每前进一步忠诚度就降低K。忠诚度降至0或0以下,则该lion逃离战场,永远消失。但是已经到达敌人司令部的lion不会逃跑。lion在己方司令部可能逃跑。

wolf降生时没有武器,但是在战斗开始前会抢到敌人编号最小的那种武器。如果敌人有多件这样的武器,则全部抢来。Wolf手里武器也不能超过10件。如果敌人arrow太多没法都抢来,那就先抢没用过的。如果敌人也是wolf,则不抢武器。

以下是不同时间会发生的不同事件:

在每个整点,即每个小时的第0分, 双方的司令部中各有一个武士降生。

红方司令部按照iceman、lion、wolf、ninja、dragon 的顺序制造武士。

蓝方司令部按照lion、dragon、ninja、iceman、wolf 的顺序制造武士。

制造武士需要生命元。

制造一个初始生命值为m 的武士,司令部中的生命元就要减少m 个。

如果司令部中的生命元不足以制造某本该造的武士,那就从此停止制造武士。

在每个小时的第5分,该逃跑的lion就在这一时刻逃跑了。

在每个小时的第10分:所有的武士朝敌人司令部方向前进一步。即从己方司令部走到相邻城市,或从一个城市走到下一个城市。或从和敌军司令部相邻的城市到达敌军司令部。

在每个小时的第35分:在有wolf及其敌人的城市,wolf要抢夺对方的武器。

在每个小时的第40分:在有两个武士的城市,会发生战斗。

在每个小时的第50分,司令部报告它拥有的生命元数量。

在每个小时的第55分,每个武士报告其拥有的武器情况。

武士到达对方司令部后就算完成任务了,从此就呆在那里无所事事。

任何一方的司令部里若是出现了敌人,则认为该司令部已被敌人占领。

任何一方的司令部被敌人占领,则战争结束。战争结束之后就不会发生任何事情了。

给定一个时间,要求你将从0点0分开始到此时间为止的所有事件按顺序输出。事件及其对应的输出样例如下:

  1. 武士降生

输出样例:000:00 blue dragon 1 born

表示在0点0分,编号为1的蓝魔dragon武士降生

如果造出的是lion,那么还要多输出一行,例:

000:00 blue lion 1 born

Its loyalty is 24

表示该lion降生时的忠诚度是24

  1. lion逃跑

输出样例:000:05 blue lion 1 ran away

表示在0点5分,编号为1的蓝魔lion武士逃走

  1. 武士前进到某一城市

输出样例:

000:10 red iceman 1 marched to city 1 with 20 elements and force 30

表示在0点10分,红魔1号武士iceman前进到1号城市,此时他生命值为20,攻击力为30

对于iceman,输出的生命值应该是变化后的数值

  1. wolf抢敌人的武器

000:35 blue wolf 2 took 3 bomb from red dragon 2 in city 4

表示在0点35分,4号城市中,红魔1号武士wolf 抢走蓝魔2号武士dragon 3个bomb。为简单起见,武器不写复数形式

  1. 报告战斗情况

战斗只有3种可能的输出结果:

000:40 red iceman 1 killed blue lion 12 in city 2 remaining 20 elements

表示在0点40分,1号城市中,红魔1号武士iceman 杀死蓝魔12号武士lion后,剩下生命值20

000:40 both red iceman 1 and blue lion 12 died in city 2

注意,把红武士写前面

000:40 both red iceman 1 and blue lion 12 were alive in city 2

注意,把红武士写前面

  1. 武士欢呼

输出样例:003:40 blue dragon 2 yelled in city 4

  1. 武士抵达敌军司令部

输出样例:001:10 red iceman 1 reached blue headquarter with 20 elements and force 30

(此时他生命值为20,攻击力为30)对于iceman,输出的生命值和攻击力应该是变化后的数值

  1. 司令部被占领

输出样例:003:10 blue headquarter was taken

9)司令部报告生命元数量

000:50 100 elements in red headquarter

000:50 120 elements in blue headquarter

表示在0点50分,红方司令部有100个生命元,蓝方有120个

10)武士报告情况

000:55 blue wolf 2 has 2 sword 3 bomb 0 arrow and 7 elements

为简单起见,武器都不写复数形式。elements一律写复数,哪怕只有1个

交代武器情况时,次序依次是:sword,bomb, arrow。

输出事件时:

首先按时间顺序输出;

同一时间发生的事件,按发生地点从西向东依次输出. 武士前进的事件, 算是发生在目的地。

在一次战斗中有可能发生上面的 5 至 6 号事件。这些事件都算同时发生,其时间就是战斗开始时间。一次战斗中的这些事件,序号小的应该先输出。

两个武士同时抵达同一城市,则先输出红武士的前进事件,后输出蓝武士的。

对于同一城市,同一时间发生的事情,先输出红方的,后输出蓝方的。

显然,8号事件发生之前的一瞬间一定发生了7号事件。输出时,这两件事算同一时间发生,但是应先输出7号事件

虽然任何一方的司令部被占领之后,就不会有任何事情发生了。但和司令部被占领同时发生的事件,全都要输出。

输入
第一行是t,代表测试数据组数

每组样例共三行。

第一行,4个整数 M,N,K, T。其含义为:
每个司令部一开始都有M个生命元( 1 <= M <= 100000)
两个司令部之间一共有N个城市( 1 <= N <= 20 )
lion每前进一步,忠诚度就降低K。(0<=K<=100)
要求输出从0时0分开始,到时间T为止(包括T) 的所有事件。T以分钟为单位,0 <= T <= 6000

第二行:五个整数,依次是 dragon 、ninja、iceman、lion、wolf 的初始生命值。它们都大于0小于等于200

第三行:五个整数,依次是 dragon 、ninja、iceman、lion、wolf 的攻击力。它们都大于0小于等于200
输出
对每组数据,先输出一行:

Case n:

如对第一组数据就输出 Case 1:

然后按恰当的顺序和格式输出到时间T为止发生的所有事件。每个事件都以事件发生的时间开头,时间格式是“时: 分”,“时”有三位,“分”有两位。

样例输入

1
20 1 10 400
20 20 30 10 20
5 5 5 5 5

样例输出

Case 1:
000:00 blue lion 1 born
Its loyalty is 10
000:10 blue lion 1 marched to city 1 with 10 elements and force 5
000:50 20 elements in red headquarter
000:50 10 elements in blue headquarter
000:55 blue lion 1 has 0 sword 1 bomb 0 arrow and 10 elements
001:05 blue lion 1 ran away
001:50 20 elements in red headquarter
001:50 10 elements in blue headquarter
002:50 20 elements in red headquarter
002:50 10 elements in blue headquarter
003:50 20 elements in red headquarter
003:50 10 elements in blue headquarter
004:50 20 elements in red headquarter
004:50 10 elements in blue headquarter
005:50 20 elements in red headquarter
005:50 10 elements in blue headquarter

本题的完整测试数据可以在MOOC上下载。链接: 程序设计与算法(三)C++面向对象程序设计

题目分析

老规矩,先把2的代码原样粘过来(然后开始漫长的修改过程
这道题要实现的是比较完整的过程了,首先需要把各个类进行一些规整,然后考虑时间线上一系列事件的实现。

类的最终设计
Weapon类

在2的基础上增加攻击力(attack)和耐久度(durability)属性。由于各种武器的属性没有较大差异,因此不需要设计派生类,继续沿用2中以id属性区分的方法。根据题目要求,一,炸弹(bomb)和弓箭(arrow)的耐久度分别为1,2,剑(sword)的耐久度设为-1,且不会减少;二,武器的攻击力随着武器主人的变化需要刷新,故增加refreshAttack函数。

Soldier类

增加阵营(camp)、攻击力(attack)、是否存活(alive)、位置(location)以及武器相关属性。由于武器存在增删操作,使用vector<Weapon *>向量保存武器。
增加攻击、死亡、刷新武器、抢夺战利品、报告状况以及相关方法。其中攻击和武器刷新是程序核心之一。武器刷新包括武器排序和废弃武器的移除。武器的排序要考虑两种情况:一种是用武器时,此时要把arrow耐久低的排在前面;另一种是抢战利品时,此时要把arrow耐久高的排在前面。

HeadQuarter类

移除了各兵种数量统计的count数组。根据题目要求:如果当前应该制造的士兵无法制造,就停止制造的变化,修改了BornSoldier函数。

士兵的移动以及战斗

程序的重点之一在于如何实现在某个城市展开战斗。其实不难发现,在任何时刻,一个城市中至多有两位不同阵营的士兵展开战斗。因此不需要真正做一个city类来存放士兵,而只需利用士兵的location属性判断战斗是否发生。

为此需要实现对战场上双方所有士兵的排序。解决方法是设计一个公共的soldierPool数组,双方任何士兵被制造时同时将其指针放入该数组中。这样我们可以轻易地写出一个实现按照从西向东,红在蓝前面规则排序,同时移除已阵亡士兵的refreshSoldierPool函数。在战斗时,我们只需要先调用该函数,然后依次检查两个相邻的士兵的location是否相同即可。

时间线(timeline)的设计

按照题目要求写出每个小时发生的各个事件的函数,然后一项项填坑吧。我的设计:
born(),lionEscape(),march(),wolfTakeWeapon(),battle(),reportPower(),reportStatus()
具体实现见完整代码。

多组数据的初始化问题

不要忘记在每组数据结束后清空soldierPool数组。

完整代码

残留了一些调试代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <iomanip>

using namespace std;

class Weapon {
public:
    char _name[20]{};
    int _id; //id =0, sword; =1, bomb; =2, arrow
    int _attack;
    int _durability;
public:
    Weapon(int id, const char *name, int durability) {
        _id = id;
        strcpy(_name, name);
        _durability = durability;
    }

    Weapon(const Weapon &weapon, int ownerAttack) {
        _id = weapon._id;
        strcpy(_name, weapon._name);
        _durability = weapon._durability;
        refreshAttack(ownerAttack);
    }

    void refreshAttack(int ownerAttack) {
        switch (_id) {
            case 0:
                _attack = ownerAttack * 2 / 10;
                break;
            case 1:
                _attack = ownerAttack * 4 / 10;
                break;
            case 2:
                _attack = ownerAttack * 3 / 10;
                break;
        }
    }
};

Weapon *weaponPool[3] = {new Weapon(0, "sword", -1), new Weapon(1, "bomb", 1),
                         new Weapon(2, "arrow", 2)};

bool compWeaponUse(const Weapon *pWeapon1, const Weapon *pWeapon2) {
    if (pWeapon1->_id != pWeapon2->_id) return pWeapon1->_id < pWeapon2->_id;
    //弓箭耐久度高的排在后面
    if (pWeapon1->_id == 2) {
        return pWeapon1->_durability < pWeapon2->_durability;
    }
    return true;
}

bool compWeaponTake(const Weapon *pWeapon1, const Weapon *pWeapon2) {
    if (pWeapon1->_id != pWeapon2->_id) return pWeapon1->_id < pWeapon2->_id;
    //弓箭耐久度低的排在后面 用于缴获战利品
    if (pWeapon1->_id == 2) {
        return pWeapon1->_durability > pWeapon2->_durability;
    }
    return true;
}


class Soldier {
public:
    int _id = -1; //士兵身份标志,0:dragon; 1:ninja; 2:iceman; 3:lion; 4:wolf
    char _camp[10]; //士兵所在阵营, 0:red 1:blue
    int _seqNum; //士兵在本司令部队列中的位置
    bool _alive = true;
    int _hp;
    int _attack;
    char _name[20];
    int _location = 0;
    vector<Weapon *> _weapons;
    int _weaponNum;
    int _weaponSeq = 0;
public:
    Soldier() {}

    Soldier(int id, const char *camp, int seqNum, const char *name, int hp, int attack) :
            _id(id), _seqNum(seqNum), _hp(hp), _attack(attack) {
        strcpy(_camp, camp);
        strcpy(_name, name);
    }

    void die() {
        _alive = false;
    }

    void checkdie() {
        if (_hp <= 0) die();
    }

    //针对可能出现soldier所有sword的攻击力均为0且耐久度不会耗损问题的判断出口
    bool weaponAllZero() {
        bool flag = true;
        auto it = _weapons.begin();
        for (; it != _weapons.end(); it++) {
            if (!((*it)->_id == 0 && (*it)->_attack == 0)) {
                flag = false;
                break;
            }
        }
        return flag;
    }

    Weapon *getWeapon() {
        if (_weapons.empty()) {
            return nullptr;
        }
        _weaponNum = _weapons.size();
        if (_weaponSeq >= _weaponNum) _weaponSeq = 0;
        return _weapons[_weaponSeq++];
    }

    void removeWasteWeapons() {
        auto it = _weapons.begin();
        for (; it != _weapons.end(); it++) {
            if ((*it)->_durability == 0) {
                it = _weapons.erase(it);
                if (it == _weapons.end()) break;
            }
        }
    }

    void refreshWeapons() {
        removeWasteWeapons();
        _weaponSeq = 0;
        sort(_weapons.begin(), _weapons.end(), compWeaponUse);
    }

    void attack(Soldier *obj) {
        Weapon *weapon = getWeapon();
        if (weapon == nullptr)
            return;
        if (weapon->_durability == 0) {
            return;
        }
        //cout << this->_camp << " " << this->_name << " " << this->_seqNum << " hp: " << this->_hp << " attack: "
        //     << this->_attack <<
        //     " use weapon: " << weapon->_name << " cause damage: " << weapon->_attack << " dur " << weapon->_durability
        //     << endl;
        obj->_hp -= weapon->_attack;
        if (weapon->_id == 1 && this->_id != 1) {
            this->_hp -= (weapon->_attack / 2);
            //cout << "bomb damage to self: " << weapon->_attack / 2 << endl;
        }
        if (weapon->_id == 1 || weapon->_id == 2) {
            //cout << "durability down" << endl;
            weapon->_durability--;
        }
        this->removeWasteWeapons();
        this->checkdie();
        obj->checkdie();
        //cout << this->_name << " " << this->_seqNum << " use " << weapon->_name << " deal "
        //<< weapon->_attack <<" damage to enemy, remaining dur: " << weapon->_durability << endl;
    }

    //抢完武器未排序
    void takeBooty(Soldier *obj) {
        if (obj->_weapons.empty()) return;
        //cout << obj->_camp <<" "<<obj->_name<<" "<<obj->_seqNum<<" has:"<<endl;
        //for(auto it = obj->_weapons.begin();it!=obj->_weapons.end();it++){
        //   cout<<(*it)->_name<<" with dur "<<(*it)->_durability<<endl;
        //}
        sort(obj->_weapons.begin(), obj->_weapons.end(), compWeaponTake);
        auto it = obj->_weapons.begin();
        for (; it != obj->_weapons.end(); it++) {
            //cout <<(*it)->_name<<" with dur "<<(*it)->_durability<<" taken"<<endl;
            if (this->_weapons.size() >= 10) break;
            this->_weapons.push_back(*it);
            //抢武器时要刷新攻击力
            (*it)->refreshAttack(this->_attack);
        }
        obj->_weapons.clear();
    }

    void report() {
        if (!_alive) return;
        int swordCount = 0, bombCount = 0, arrowCount = 0;
        auto it = _weapons.begin();
        //cout << _camp << " " << _name << " " << _seqNum << " has " << endl;

        //for(;it!=_weapons.end();it++)   cout << (*it)->_name << " with dur "<<(*it)->_durability<<endl;
        for (; it != _weapons.end(); it++) {
            if ((*it)->_id == 0) swordCount++;
            else if ((*it)->_id == 1) bombCount++;
            else if ((*it)->_id == 2) arrowCount++;
        }
        cout << _camp << " " << _name << " " << _seqNum << " has ";
        cout << swordCount << " sword " << bombCount << " bomb " << arrowCount << " arrow "
             << "and " << _hp << " elements" << endl;
    }

    virtual void PrintSpecialBornInfo() {};

    ~Soldier() {
        _weapons.clear();
    }
};

class Dragon : public Soldier {
public:
    double _morale;
public:
    Dragon(const char *camp, int totalNum, int leftPower, int hp, int attack)
            : Soldier(0, camp, totalNum, "dragon", hp, attack), _morale((double) leftPower / hp) {
        _weapons.push_back(new Weapon(*weaponPool[totalNum % 3], attack));
    }

};

class Ninja : public Soldier {
public:
    Ninja(const char *camp, int totalNum, int hp, int attack)
            : Soldier(1, camp, totalNum, "ninja", hp, attack) {
        _weapons.push_back(new Weapon(*weaponPool[totalNum % 3], attack));
        _weapons.push_back(new Weapon(*weaponPool[(totalNum + 1) % 3], attack));
    }

};

class Iceman : public Soldier {
public:
    Iceman(const char *camp, int totalNum, int hp, int attack)
            : Soldier(2, camp, totalNum, "iceman", hp, attack) {
        _weapons.push_back(new Weapon(*weaponPool[totalNum % 3], attack));
    }

};

class Lion : public Soldier {
public:
    int _loyalty;
public:
    Lion(const char *camp, int totalNum, int leftPower, int hp, int attack)
            : Soldier(3, camp, totalNum, "lion", hp, attack), _loyalty(leftPower) {
        _weapons.push_back(new Weapon(*weaponPool[totalNum % 3], attack));
    }

    void PrintSpecialBornInfo() override {
        cout << "Its loyalty is " << _loyalty << endl;
    }
};

class Wolf : public Soldier {
public:
    Wolf(const char *camp, int totalNum, int hp, int attack)
            : Soldier(4, camp, totalNum, "wolf", hp, attack) {}
};

int soldierHp[5];
int soldierAttack[5];
int currentTime, stopTime, cityNum;
int loyalDrop;
vector<Soldier *> soldierpool; //储存双方所有士兵用于排序 由西向东输出事件

bool compSoldier(const Soldier *pSoldier1, const Soldier *pSoldier2) {
    if (pSoldier1->_location != pSoldier2->_location) return pSoldier1->_location < pSoldier2->_location;
    return !strcmp(pSoldier1->_camp, "red"); //1号士兵为红阵营,则1号在2号前面
}

void refreshSoldierpool() {
    auto it = soldierpool.begin();
    for (; it != soldierpool.end(); it++) {
        if (!(*it)->_alive) {
            it = soldierpool.erase(it);
            if (it == soldierpool.end()) break;
        }
    }
    sort(soldierpool.begin(), soldierpool.end(), compSoldier);
}

class HeadQuarter {
private:
    int _id; //指挥部id 0:red 1:blue
    char _name[20];
    int _power;//剩余生命力
    int _seq[5];//出兵顺序
    int _pos;//出兵顺序当前位置
    int _totalNum;//士兵总数
    Soldier *_soldierList[100];//士兵队列
public:
    HeadQuarter(int id, const char name[], int power, const int seq[]) {
        _id = id;
        _totalNum = 0;
        _pos = 0;
        strcpy(_name, name);
        _power = power;
        for (int i = 0; i < 5; i++) {
            _seq[i] = seq[i];
        }
    }

    void BornSoldier() {
        if (_pos >= 5) _pos -= 5;
        if (_power >= soldierHp[_seq[_pos]]) {
            _power -= soldierHp[_seq[_pos]];
            Soldier *newSoldier = AddSoldier(_seq[_pos]);
            PrintBornInfo(newSoldier);
            ++_pos;
        }
    }

    Soldier *AddSoldier(int id) {
        switch (id) {
            case 0:
                _soldierList[_totalNum] = new Dragon(_name, _totalNum + 1, _power, soldierHp[id], soldierAttack[id]);
                break;
            case 1:
                _soldierList[_totalNum] = new Ninja(_name, _totalNum + 1, soldierHp[id], soldierAttack[id]);
                break;
            case 2:
                _soldierList[_totalNum] = new Iceman(_name, _totalNum + 1, soldierHp[id], soldierAttack[id]);
                break;
            case 3:
                _soldierList[_totalNum] = new Lion(_name, _totalNum + 1, _power, soldierHp[id], soldierAttack[id]);
                break;
            case 4:
                _soldierList[_totalNum] = new Wolf(_name, _totalNum + 1, soldierHp[id], soldierAttack[id]);
                break;
            default:
                cerr << "Fail to generate legal soldier!" << endl;
                exit(0);
        }
        soldierpool.push_back(_soldierList[_totalNum]);
        if (this->_id == 0) _soldierList[_totalNum]->_location = 0;
        else if (this->_id == 1) _soldierList[_totalNum]->_location = cityNum + 1;
        ++_totalNum;
        return _soldierList[_totalNum - 1];
    }

    void PrintBornInfo(Soldier *soldier) {
        cout << setfill('0') << setw(3) << right << currentTime << ":00 "
             << _name << " " << soldier->_name << " " << soldier->_seqNum << " born" << endl;
        soldier->PrintSpecialBornInfo();
    }

    friend void reportPower();

    ~HeadQuarter() {
        for (int i = 0; i < _totalNum; i++) {
            _soldierList[i] = nullptr;
        }
        memset(_soldierList, 0, sizeof(_soldierList));
    }
};

HeadQuarter *red, *blue;

void born() {
    red->BornSoldier();
    blue->BornSoldier();
}

void lionEscape() {
    auto it = soldierpool.begin();
    for (; it != soldierpool.end(); it++) {
        //000:05 blue lion 1 ran away
        if ((*it)->_id == 3 && (*it)->_alive) {
            Lion *lion = dynamic_cast<Lion *>(*it);
            if (lion->_loyalty <= 0) {
                cout << setfill('0') << setw(3) << right << currentTime << ":05 "
                     << lion->_camp << " " << lion->_name << " " << lion->_seqNum << " ran away" << endl;
                lion->die();
            }
        }
    }
}

bool march() {
    int winFlag = 0; //0:未分胜负 1:red lose 2:blue lose
    bool printFlagRed = false, printFlagBlue = false;
    auto it = soldierpool.begin();
    for (; it != soldierpool.end(); it++) {
        Soldier *soldier = *it;
        if (!soldier->_alive) continue;
        if (!strcmp(soldier->_camp, "red")) {
            if (soldier->_location < cityNum + 1) {
                soldier->_location++;
            }
        } else if (!strcmp(soldier->_camp, "blue")) {
            if (soldier->_location > 0) {
                soldier->_location--;
            }
        }
        if (soldier->_id == 3) {
            Lion *lion = dynamic_cast<Lion *>(soldier);
            lion->_loyalty -= loyalDrop;
        } else if (soldier->_id == 2) {
            Iceman *iceman = dynamic_cast<Iceman *>(soldier);
            iceman->_hp -= iceman->_hp / 10;
        }
    }
    refreshSoldierpool();
    for (it = soldierpool.begin(); it != soldierpool.end(); it++) {
        Soldier *soldier = *it;
        cout << setfill('0') << setw(3) << right << currentTime << ":10 ";
        cout << soldier->_camp << " " << soldier->_name << " " << soldier->_seqNum;
        if (soldier->_location == 0) {
            //001:10 red iceman 1 reached blue headquarter with 20 elements and force 30
            cout << " reached red headquarter";
            //007:10 red headquarter was taken
            winFlag = 1;
        } else if (soldier->_location == cityNum + 1) {
            cout << " reached blue headquarter";
            winFlag = 2;
        } else {
            cout << " marched to city " << soldier->_location;
        }
        cout << " with " << soldier->_hp << " elements and force " << soldier->_attack << endl;
        //" and "<< soldier->_weapons.size()<<" weapons"<<
        //007:10 red headquarter was taken
        if (winFlag == 1 && !printFlagRed) {
            cout << setfill('0') << setw(3) << right << currentTime << ":10 "
                 << "red headquarter was taken" << endl;
            printFlagRed = true;
        } else if (winFlag == 2 && !printFlagBlue) {
            cout << setfill('0') << setw(3) << right << currentTime << ":10 "
                 << "blue headquarter was taken" << endl;
            printFlagBlue = true;
        }
    }
    return winFlag != 0;
}

void take(Soldier *wolf, Soldier *obj) {
    if (obj->_weapons.empty()) return;
    int takeWeaponCount = 0;
    char takeWeaponName[20];
    sort(obj->_weapons.begin(), obj->_weapons.end(), compWeaponTake);
    auto objIt = obj->_weapons.begin();
    int weaponId = (*objIt)->_id;
    while ((*objIt)->_id == weaponId && wolf->_weapons.size() <= 10) {
        strcpy(takeWeaponName, (*objIt)->_name);
        takeWeaponCount++;
        wolf->_weapons.push_back(*objIt);
        //wolf抢来的武器要刷新攻击力
        (*objIt)->refreshAttack(wolf->_attack);
        objIt = obj->_weapons.erase(objIt);
        if (objIt == obj->_weapons.end()) break;
    }
    cout << setfill('0') << setw(3) << right << currentTime << ":35 "
         << wolf->_camp << " " << wolf->_name << " " << wolf->_seqNum
         << " took " << takeWeaponCount << " " << takeWeaponName << " from "
         << obj->_camp << " " << obj->_name << " " << obj->_seqNum
         << " in city " << wolf->_location << endl;
    wolf->refreshWeapons();
    obj->refreshWeapons();
}

void wolfTakeWeapon() {
    auto it = soldierpool.begin();
    for (; it < soldierpool.end() - 1; it++) {
        Soldier *soldier1 = *it;
        Soldier *soldier2 = *(it + 1);
        if (soldier1->_location == soldier2->_location) {
            if (soldier1->_id == 4 && soldier2->_id == 4) {
                it++;
                continue;
            }
            if (soldier1->_id == 4) {
                take(soldier1, soldier2);
                it++;
            }
            if (soldier2->_id == 4) {
                take(soldier2, soldier1);
                it++;
            }
        }
    }
}

void printKill(Soldier *winner, Soldier *loser, int location) {
    cout << setfill('0') << setw(3) << right << currentTime << ":40 "
         << winner->_camp << " " << winner->_name << " " << winner->_seqNum
         << " killed " << loser->_camp << " " << loser->_name << " " << loser->_seqNum
         << " in city " << location << " remaining " << winner->_hp << " elements" << endl;
}

void printDraw(Soldier *soldier1, Soldier *soldier2, int location, bool info) {
    //info: =false, both die; =true, both alive
    //000:40 both red iceman 1 and blue lion 12 were alive in city 2
    //000:40 both red iceman 1 and blue lion 12 died in city 2
    cout << setfill('0') << setw(3) << right << currentTime << ":40 "
         << "both " << soldier1->_camp << " " << soldier1->_name << " " << soldier1->_seqNum
         << " and " << soldier2->_camp << " " << soldier2->_name << " " << soldier2->_seqNum;
    if (!info) cout << " died in city ";
    else cout << " were alive in city ";
    cout << location << endl;
}

void printYell(Soldier *soldier, int location) {
    //000:40 red iceman 1 killed blue lion 12 in city 2 remaining 20 elements
    cout << setfill('0') << setw(3) << right << currentTime << ":40 "
         << soldier->_camp << " " << soldier->_name << " " << soldier->_seqNum
         << " yelled in city " << location << endl;
}

bool fightCheck(Soldier *soldier1, Soldier *soldier2, int location) {
    if (soldier1->_alive && !soldier2->_alive) {
        printKill(soldier1, soldier2, location);
        soldier1->takeBooty(soldier2);
        return true;
    } else if (!soldier1->_alive && soldier2->_alive) {
        printKill(soldier2, soldier1, location);
        soldier2->takeBooty(soldier1);
        return true;
    } else if (!soldier1->_alive && !soldier2->_alive) {
        printDraw(soldier1, soldier2, location, false);
        return true;
    } else if (soldier1->_alive && soldier2->_alive) {
        if ((soldier1->_weapons.empty() && soldier2->_weapons.empty()) ||
            (soldier1->weaponAllZero() && soldier2->weaponAllZero())) {
            printDraw(soldier1, soldier2, location, true);
            return true;
        }
    }
    return false;
}

void fight(int location, Soldier *soldier1, Soldier *soldier2) {
    if (!strcmp(soldier1->_camp, "blue") && !strcmp(soldier2->_camp, "red")) swap(soldier1, soldier2);
    soldier1->refreshWeapons();
    soldier2->refreshWeapons();
    if (location % 2 == 1) {
        while (true) {
            soldier1->attack(soldier2);
            if (fightCheck(soldier1, soldier2, location)) break;
            soldier2->attack(soldier1);
            if (fightCheck(soldier1, soldier2, location)) break;
        }
    } else {
        while (true) {
            soldier2->attack(soldier1);
            if (fightCheck(soldier1, soldier2, location)) break;
            soldier1->attack(soldier2);
            if (fightCheck(soldier1, soldier2, location)) break;
        }
    }
    soldier1->refreshWeapons();
    soldier2->refreshWeapons();
    if (soldier1->_id == 0 && soldier1->_alive) printYell(soldier1, location);
    if (soldier2->_id == 0 && soldier2->_alive) printYell(soldier2, location);
}

void battle() {
    auto it = soldierpool.begin();
    for (; it < soldierpool.end() - 1; it++) {
        Soldier *soldier1 = *it;
        Soldier *soldier2 = *(it + 1);
        //由于在march后对士兵队列做过排序,故战斗只可能发生在相邻的两个士兵之间
        //理论上不可能出现三个士兵在一个城市的情况
        if (soldier1->_location == soldier2->_location) {
            fight(soldier1->_location, soldier1, soldier2);
            ++it;
        }
    }
}

void reportPower() {
    cout << setfill('0') << setw(3) << right << currentTime << ":50 "
         << red->_power << " elements in " << red->_name << " headquarter" << endl;
    cout << setfill('0') << setw(3) << right << currentTime << ":50 "
         << blue->_power << " elements in " << blue->_name << " headquarter" << endl;
}

void reportStatus() {
    auto it = soldierpool.begin();
    for (; it != soldierpool.end(); it++) {
        //000:55 blue wolf 2 has 2 sword 3 bomb 0 arrow and 7 elements
        if (!(*it)->_alive) continue;
        cout << setfill('0') << setw(3) << right << currentTime << ":55 ";
        (*it)->report();
    }
}

void timeline(bool &win) {
    born();
    refreshSoldierpool();
    if (currentTime * 60 + 5 > stopTime) return;
    lionEscape();
    refreshSoldierpool();
    if (currentTime * 60 + 10 > stopTime) return;
    win = march(); //march内已做过refreshSoldierPool
    if (win) return;
    if (currentTime * 60 + 35 > stopTime) return;
    wolfTakeWeapon();
    if (currentTime * 60 + 40 > stopTime) return;
    battle();
    refreshSoldierpool();
    if (currentTime * 60 + 50 > stopTime) return;
    reportPower();
    if (currentTime * 60 + 55 > stopTime) return;
    reportStatus();
}

int main() {
    int caseTotal;
    cin >> caseTotal;
    int caseNum = 0;
    while (caseNum < caseTotal) {
        ++caseNum;
        currentTime = 0;
        int power;
        cin >> power >> cityNum >> loyalDrop >> stopTime;
        int redSeq[5] = {2, 3, 4, 1, 0}, blueSeq[5] = {3, 0, 1, 2, 4};
        red = new HeadQuarter(0, "red", power, redSeq);
        blue = new HeadQuarter(1, "blue", power, blueSeq);
        for (int i = 0; i < 5; ++i) {
            cin >> soldierHp[i];
        }
        for (int i = 0; i < 5; ++i) {
            cin >> soldierAttack[i];
        }
        cout << "Case " << caseNum << ":" << endl;
        bool win = false;
        while (currentTime * 60 <= stopTime) {
            timeline(win);
            if (win) break;
            currentTime++;
        }
        soldierpool.clear();
    }
    return 0;
}
  • 8
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
问题描述 魔兽世界的西面是红魔军的司令部,东面是蓝魔军的司令部。两个司令部之间是依次排列的若干城市,城市从西向东依次编号为1,2,3 …. N ( N <= 20 )。红魔军的司令部算作编号为0的城市,蓝魔军的司令部算作编号为N+1的城市。司令部有生命元,用于制造武士。 两军的司令部都会制造武士。武士一共有 dragon 、ninja、iceman、lion、wolf 五种。每种武士都有编号、生命值、攻击力这种属性。 双方的武士编号都是从1开始计算。红方制造出来的第 n 个武士,编号就是n。同样,蓝方制造出来的第 n 个武士,编号也是n。 武士在刚降生的时候有一个初始的生命值,生命值在战斗中会发生变化,如果生命值减少到0(生命值变为负数时应当做变为0处理),则武士死亡(消失)。 有的武士可以拥有武器。武器有种,sword, bomb,和arrow,编号分别为0,1,2。 武士降生后就朝对方司令部走,在经过的城市如果遇到敌人(同一时刻每个城市最多只可能有1个蓝武士和一个红武士),就会发生战斗。每次战斗只有一方发起主动进攻一次。被攻击者生命值会减去进攻者的攻击力值和进攻者手中sword的攻击力值。被进攻者若没死,就会发起反击,被反击者的生命值要减去反击者攻击力值的一半(去尾取整)和反击者手中sword的攻击力值。反击可能致敌人于死地。 如果武士在战斗中杀死敌人(不论是主动进攻杀死还是反击杀死),则其司令部会立即向其发送8个生命元作为奖励,使其生命值增加8。当然前提是司令部得有8个生命元。如果司令部的生命元不足以奖励所有的武士,则优先奖励距离敌方司令部近的武士。 如果某武士在某城市的战斗中杀死了敌人,则该武士的司令部立即取得该城市中所有的生命元。注意,司令部总是先完成全部奖励工作,然后才开始从各个打了胜仗的城市回收生命元。对于因司令部生命元不足而领不到奖励的武士,司令部也不会在取得战利品生命元后为其补发奖励。 如果一次战斗的结果是双方都幸存(平局),则双方都不能拿走发生战斗的城市的生命元。 城市可以插旗子,一开始所有城市都没有旗子。在插红旗的城市,以及编号为奇数的无旗城市,由红武士主动发起进攻。在插蓝旗的城市,以及编号为偶数的无旗城市,由蓝武士主动发起进攻。 当某个城市有连续两场战斗都是同一方的武士杀死敌人(两场战斗之间如果有若干个战斗时刻并没有发生战斗,则这两场战斗仍然算是连续的;但如果中间有平局的战斗,就不算连续了) ,那么该城市就会插上胜方的旗帜,若原来插着败方的旗帜,则败方旗帜落下。旗帜一旦插上,就一直插着,直到被敌人更换。一个城市最多只能插一面旗帜,旗帜没被敌人更换前,也不会再次插同颜色的旗。 各种武器有其特点: sword武器的初始攻击力为拥有它的武士的攻击力的20%(去尾取整)。但是sword每经过一次战斗(不论是主动攻击还是反击),就会变钝,攻击力变为本次战斗前的80% (去尾取整)。sword攻击力变为0时,视为武士失去了sword。如果武士降生时得到了一个初始攻击力为0的sword,则视为武士没有sword. arrow有一个攻击力值R。如果下一步要走到的城市有敌人,那么拥有arrow的武士就会放箭攻击下一个城市的敌人(不能攻击对方司令部里的敌人)而不被还击。arrow使敌人的生命值减少R,若减至小于等于0,则敌人被杀死。arrow使用3次后即被耗尽,武士失去arrow。两个相邻的武士可能同时放箭把对方射死。 拥有bomb的武士,在战斗开始前如果判断自己将被杀死(不论主动攻击敌人,或者被敌人主动攻击都可能导致自己被杀死,而且假设武士可以知道敌人的攻击力和生命值),那么就会使用bomb和敌人同归于尽。武士不预测对方是否会使用bomb。 武士使用bomb和敌人同归于尽的情况下,不算是一场战斗,双方都不能拿走城市的生命元,也不影响城市的旗帜。 不同的武士有不同的特点。 dragon可以拥有一件武器。编号为n的dragon降生时即获得编号为 n%3 的武器。dragon还有“士气”这个属性,是个浮点数,其值为它降生后其司令部剩余生命元的数量除以造dragon所需的生命元数量。dragon 在一次在它主动进攻的战斗结束后,如果还没有战死,而且士气值大于0.8,就会欢呼。dragon每取得一次战斗的胜利(敌人被杀死),士气就会增加0.2,每经历一次未能获胜的战斗,士气值就会减少0.2。士气增减发生在欢呼之前。 ninjia可以拥有两件武器。编号为n的ninjia降生时即获得编号为 n%3 和 (n+1)%3的武器。ninja 挨打了也从不反击敌人。 iceman有一件武器。编号为n的iceman降生时即获得编号为 n%3 的武器。iceman 每前进两步,在第2步完成的时候,生命值

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值