题解 P2482 【[SDOI2010]猪国杀】
_虹_
2018-12-17 17:57:06
疑似史上 ~~最易理解~~代码最长 猪国杀
听说某位蒟da蒻lao因为不会面向过程写了面向对象。~~我oi白学。~~
除了上面的大佬们提到的坑点,加上几个我自己写的时候发现的注意点:
1. **无论锦囊牌是不是生效,出了就会触发献殷勤/表敌意。**
2. ** 跳身份很好处理,只要触发了献殷勤/表敌意,把自己的身份表明就好了。**
3. 猪都很耿直,能表明身份就表明身份。
4. 无懈可击是对被攻击的猪献殷勤/表敌意。
写完30分的时候过了一遍代码逻辑,总体应该还是挺清晰的,代码里也有些中英混杂的注释。~~所以不想额外加注释了。~~
代码效率不高,也有几个凑活的地方,比如class_world::piglist应该是一个环状链表,再用一个数组做索引进行o(1)的查找和删除(world类外部持有list::iterator总觉得不太好)
class_basic_pig::cardlist也应该是一个链表,然后我就全都vector解决了。。。。
应该没有什么隐蔽的错误。只是虽然我很尽力了,耦合貌似还是蛮高的。。。。。
开发规范本来就没有正经学习,现在也忘得很干净了。
但是程序中各种命名还是尽力保证可读性,试图去遵守一下命名规范的(虽然没成功吧)。~~不过后来改bug导致某些命名和其它命名不太一致。 大家谅解一下。~~
虽然代码1000来行,不过可读性应该还行吧...~~(心虚)~~
**不想看代码建议直接看结尾,提供vs2015 project下载,观赏效果更佳。**
### 下面大量类继承,多态警告:
```cpp
// luogu-judger-enable-o2
#include <vector>
#include <queue>
#include <list>
#include <iostream>
#include <cstdlib>
using namespace std;
enum enum_status
{
DEAD = 0, UNKNOW = 1, FRIEND = 2, ENEMY = 3, ETBE = 4
};
enum enum_card
{
BLOOD = 1, KILL = 2, MISS = 3, FIGHT = 4, N_ATK = 5, W_ATK = 6, J_DF = 7, ARM = 8
};//无懈可击是J_DF,这个鬼东西我是真不会起名了
enum enum_kind
{
MAIN_PIG = 1, FRIEND_PIG = 2, ENEMY_PIG = 3
};
#define reg register
#define null NULL
#define MAXBLOOD 4
struct Event;
class class_basic_pig
{
public:
enum_kind Kind;
enum_status Status;
bool Armed;
int num;//数组下标
int Blood;
vector<enum_card> CardList;
class_basic_pig(const int _num, enum_kind _kind) :num(_num), Kind(_kind),Armed(false),Blood(MAXBLOOD),Status(UNKNOW){};
void N_Attack();
void W_Attack();
virtual void N_AttackBy(class_basic_pig*)=0;
virtual void W_AttackBy(class_basic_pig*)=0;
virtual void C_AttackBy(class_basic_pig*)=0;
void StartFightWith(class_basic_pig*);//start to fight with ptr
virtual const bool FightWith(class_basic_pig*)=0;//fight with ptr
bool DropCard(enum_card);//return true if pig has this card to drop,or false if hasnt
void Hurt();//pig is hurt,try to heal,updata pigs status
//virtual void Updata();//updata pigs status
//virtual void SpecialDefence();//if use special defence card
virtual bool Usable(const enum_card&,bool&);//if the card usable//子类重载并且调用basic类的函数
virtual const bool IsEnemy(const enum_status&)=0;//判断是否为敌人
virtual void CheckAfterAttack(class_basic_pig* ptr) = 0;//造成伤害后结算
void Turn();
virtual void UseCard(enum_card)=0;
virtual bool UseSpecialDefence(Event)=0;//true: used,false: didnt use
virtual void UpdataIdentity() = 0;
};
struct Event
{
class_basic_pig* source;//锦囊牌发出者
class_basic_pig* target;//锦囊牌接受者
bool Good;//true:献殷勤,false:表敌意
Event(class_basic_pig* s = null, class_basic_pig* t = null, bool b = false) :source(s), target(t), Good(b) {};
};
class class_world
{
public:
vector<class_basic_pig*> PigList;
queue<enum_card> CardPool;
class_basic_pig* GetEnemy(int num, class_basic_pig* ptr);
class_basic_pig* GetNext(int num);
class_basic_pig* GetLast(int num);
enum_card GetCard()
{
enum_card t = CardPool.front();
if (CardPool.size() > 1)
{
CardPool.pop();
}
return t;
}
void EndGame();
void GameBegin();
bool CheckSpecialDefnece(Event);//if oridary event can happen,return true,else return false
}World;
class class_main_pig:public class_basic_pig
{
public:
class_main_pig(const int _num):class_basic_pig(_num, MAIN_PIG){};
virtual void N_AttackBy(class_basic_pig*);
virtual void W_AttackBy(class_basic_pig*);
virtual void C_AttackBy(class_basic_pig*);
virtual bool Usable(const enum_card&,bool&);
virtual const bool IsEnemy(const enum_status&);
virtual const bool FightWith(class_basic_pig*);
virtual void CheckAfterAttack(class_basic_pig*);
virtual void UseCard(enum_card);
virtual bool UseSpecialDefence(Event);
virtual void UpdataIdentity() {};
};
class class_friend_pig :public class_basic_pig
{
public:
class_friend_pig(const int _num) :class_basic_pig(_num, FRIEND_PIG) {};
virtual void N_AttackBy(class_basic_pig*);
virtual void W_AttackBy(class_basic_pig*);
virtual void C_AttackBy(class_basic_pig*);
virtual bool Usable(const enum_card&, bool&);
virtual const bool IsEnemy(const enum_status&);
virtual const bool FightWith(class_basic_pig*);
virtual void CheckAfterAttack(class_basic_pig*);
virtual void UseCard(enum_card);
virtual bool UseSpecialDefence(Event);
virtual void UpdataIdentity();
};
class class_enemy_pig :public class_basic_pig
{
public:
class_enemy_pig(const int _num) :class_basic_pig(_num, ENEMY_PIG) {};
virtual void N_AttackBy(class_basic_pig*);
virtual void W_AttackBy(class_basic_pig*);
virtual void C_AttackBy(class_basic_pig*);
virtual bool Usable(const enum_card&, bool&);
virtual const bool IsEnemy(const enum_status&);
virtual const bool FightWith(class_basic_pig*);
virtual void CheckAfterAttack(class_basic_pig*);
virtual void UseCard(enum_card);
virtual bool UseSpecialDefence(Event);
virtual void UpdataIdentity();
};
char un_translate(enum_card card)
{
char ch;
switch (card)
{
case BLOOD:
ch = 'P';
break;
case KILL:
ch = 'K';
break;
case MISS:
ch = 'D';
break;
case FIGHT:
ch = 'F';
break;
case N_ATK:
ch = 'N';
break;
case W_ATK:
ch = 'W';
break;
case J_DF:
ch = 'J';
break;
case ARM:
ch = 'Z';
break;
}
return ch;
}
void class_basic_pig::N_Attack()
{
class_basic_pig* ptr = null;
int pos = num;
while ((ptr = World.GetNext(pos)) && ptr->num!=num )
{
pos = ptr->num;
ptr->N_AttackBy(this);
CheckAfterAttack(ptr);
}
}
void class_basic_pig::W_Attack()
{
class_basic_pig* ptr = null;
int pos = num;
while ((ptr = World.GetNext(pos)) && ptr->num != num)
{
pos = ptr->num;
ptr->W_AttackBy(this);
CheckAfterAttack(ptr);
}
}
bool class_basic_pig::DropCard(enum_card c)
{
int s = CardList.size();
for (reg int i = 0; i < s; ++i)
{
if (CardList[i] == c)
{
CardList.erase(CardList.begin()+i);
return true;
}
}
return false;
}
bool class_basic_pig::Usable(const enum_card& c,bool& tag)
{
if ((c == BLOOD&&Blood < MAXBLOOD) ||
c == N_ATK || c == W_ATK || c == ARM)
return true;
class_basic_pig* ptr = World.GetNext(num);//杀
if ((Armed || (!tag)) && c == KILL && IsEnemy(ptr->Status))
{
tag = true;
return true;
}
return false;
}
void class_basic_pig::StartFightWith(class_basic_pig* ptr)
{
UpdataIdentity();
if (!World.CheckSpecialDefnece(Event(this, ptr, false)))
{
return;
}
int i = 1;
while (i % 2 ?
ptr->FightWith(this) :
FightWith(ptr))
{
++i;//do nothing
}
if (i % 2)//ptr hurt
{
CheckAfterAttack(ptr);
}
else
{
ptr->CheckAfterAttack(this);
}
}
void class_basic_pig::Hurt()
{
--Blood;
if (Blood < 1)
{
while (Blood < 1 && DropCard(BLOOD))
++Blood;//heal
if (Blood < 1)
{
Status = DEAD;
if (Kind == MAIN_PIG)
{
World.EndGame();
}
bool tag = false;
for (reg int j = 0; j < World.PigList.size(); ++j)
{
if (World.PigList[j]->Kind == ENEMY_PIG&&World.PigList[j]->Status != DEAD)
{
tag = true;
}
}
if (!tag)
{
World.EndGame();
}
}
}
}
void class_basic_pig::Turn()
{
CardList.push_back(World.GetCard());
CardList.push_back(World.GetCard());
bool tag = true;
bool kill_tag = false;
while (tag&&Status!=DEAD)
{
tag = false;
for (reg int i = 0; i < CardList.size(); ++i)
{
if (Usable(CardList[i], kill_tag))
{
tag = true;
UseCard(CardList[i]);
break;
}
}
}
}
class_basic_pig* class_world::GetEnemy(int num, class_basic_pig* ptr)// (now pos,check func)
{
int tot = PigList.size();
for (reg int i = 0; i < tot; ++i)
{
if (ptr->IsEnemy(PigList[(++num) % tot]->Status))//pig is able to attack because of the status
{
return PigList[num%tot];
}
}
return null;
}
class_basic_pig* class_world::GetNext(int num)//now pos
{
int tot = PigList.size();
for (reg int i = 0; i < tot; ++i)
{
if (PigList[(++num) % tot]->Status != DEAD)//pig is alive
{
return PigList[num % tot];
}
}
return null;
}
class_basic_pig* class_world::GetLast(int num)//now pos
{
int tot = PigList.size();
for (reg int i = 0; i < tot; ++i)
{
if (PigList[(tot + (--num)) % tot]->Status != DEAD)//pig is alive
{
return PigList[(tot + (num)) % tot];
}
}
return null;
}
void class_world::EndGame()
{
if (PigList[0]->Status == DEAD)
cout << "FP" << endl;
else
cout << "MP" << endl;
for (reg int i = 0; i < PigList.size(); ++i)
{
if (PigList[i]->Status == DEAD)
{
cout << "DEAD" << endl;
}
else
{
for (reg int j = 0; j < PigList[i]->CardList.size(); ++j)
{
cout << un_translate(PigList[i]->CardList[j]) << ' ';
}
cout << endl;
}
}
exit(-1);//i think this might stop you from AC on luogu if you just copy the code.
}
void class_world::GameBegin()
{
int tot=PigList.size();
for (reg int i = 0;; ++i)
{
i = i%tot;
if(PigList[i]->Status!=DEAD)
PigList[i]->Turn();
}
}
bool class_world::CheckSpecialDefnece(Event e)//if oridary event can happen,return true,else return false
{
class_basic_pig* ptr = e.source;
if (!ptr)
return true;
int num = ptr->num;
do
{
if (ptr->UseSpecialDefence(e))
{
ptr->UpdataIdentity();
if (CheckSpecialDefnece(Event(ptr, e.target, !e.Good)))//happend
{
return false;
}
return true;
}
} while ((ptr = GetNext(ptr->num))->num != num);
return true;
}
void class_main_pig::N_AttackBy(class_basic_pig* ptr)
{
if (!World.CheckSpecialDefnece(Event(ptr, this, false)))
{
return;
}
if (DropCard(KILL))
{
return;//丢弃杀
}
else
{
if (ptr->Status == UNKNOW)
ptr->Status = ETBE;
Hurt();
}
}
void class_main_pig::W_AttackBy(class_basic_pig* ptr)
{
if (!World.CheckSpecialDefnece(Event(ptr, this, false)))
{
return;
}
if (DropCard(MISS))
{
return;//丢弃闪
}
else
{
if (ptr->Status == UNKNOW)
ptr->Status = ETBE;
Hurt();
}
}
bool class_main_pig::Usable(const enum_card& c,bool& tag)//check if this card usable
{
if (class_basic_pig::Usable(c,tag))
{
return true;
}
//ptr = World.GetEnemy(num, ((const bool (class_basic_pig::*)(const enum_status&))this->IsEnemy));
if (c == FIGHT)
{
if (World.GetEnemy(num, this))//have enemy
return true;
}
return false;
}
const bool class_main_pig::IsEnemy(const enum_status& s)
{
return s == ENEMY || s == ETBE;
}
void class_main_pig::C_AttackBy(class_basic_pig* ptr)
{
ptr->Status = ENEMY;
if (DropCard(MISS))
{
;//丢弃闪
}
else
{
Hurt();
}
}
const bool class_main_pig::FightWith(class_basic_pig* ptr)//fight with ptr
{
if (DropCard(KILL))
{
return true;
}
else
{
Hurt();
return false;
}
}
void class_main_pig::CheckAfterAttack(class_basic_pig* ptr)//胜者结算
{
if(ptr->Status == DEAD)
{
if (ptr->Kind == FRIEND_PIG)
{
CardList.clear();
Armed = false;
}
else
{
CardList.push_back(World.GetCard());
CardList.push_back(World.GetCard());
CardList.push_back(World.GetCard());
}
}
}
void class_main_pig::UseCard(enum_card c)
{
DropCard(c);
class_basic_pig* ptr;
switch (c)
{
case KILL:
ptr = World.GetNext(num);
ptr->C_AttackBy(this);
CheckAfterAttack(ptr);
break;
case BLOOD:
++Blood;
break;
case N_ATK:
N_Attack();
break;
case W_ATK:
W_Attack();
break;
case ARM:
Armed = true;
break;
case FIGHT:
ptr=World.GetEnemy(num, this);
StartFightWith(ptr);
break;
}
}
bool class_main_pig::UseSpecialDefence(Event e)
{
bool tag = false;
if (e.target->Status == FRIEND)
{
if (!e.Good)//event表示对友军表敌意
{
tag= true;//使用无懈可击献殷勤
}
}
if (e.target->Status == ENEMY)
{
if (e.Good)//对敌军献殷勤
{
tag= true;//表敌意
}
}
if (tag)
{
tag = DropCard(J_DF);
}
return tag;
}
//////////////////////////////////////////////////////////////////////
void class_friend_pig::N_AttackBy(class_basic_pig* ptr)
{
if (!World.CheckSpecialDefnece(Event(ptr, this, false)))
{
return;
}
if (DropCard(KILL))
{
return;//丢弃杀
}
else
{
Hurt();
}
}
void class_friend_pig::W_AttackBy(class_basic_pig* ptr)
{
if (!World.CheckSpecialDefnece(Event(ptr, this, false)))
{
return;
}
if (DropCard(MISS))
{
return;//丢弃闪
}
else
{
Hurt();
}
}
bool class_friend_pig::Usable(const enum_card& c, bool& tag)//check if this card usable
{
if (class_basic_pig::Usable(c, tag))
{
return true;
}
//ptr = World.GetEnemy(num, ((const bool (class_basic_pig::*)(const enum_status&))this->IsEnemy));
if (c == FIGHT)
{
if (World.GetEnemy(num,this))//have enemy
return true;
}
return false;
}
const bool class_friend_pig::IsEnemy(const enum_status& s)
{
return s == ENEMY;
}
void class_friend_pig::C_AttackBy(class_basic_pig* ptr)
{
if (ptr->Kind == MAIN_PIG)//
;
else
ptr->Status = ENEMY;
if (DropCard(MISS))
{
;//丢弃闪
}
else
{
Hurt();
}
}
const bool class_friend_pig::FightWith(class_basic_pig* ptr)//fight with ptr
{
if (ptr->Kind == MAIN_PIG)
{
Hurt();
return false;
}
if (DropCard(KILL))
{
return true;
}
else
{
Hurt();
return false;
}
return false;
}
void class_friend_pig::CheckAfterAttack(class_basic_pig* ptr)//胜者(攻击者)结算
{
if (ptr->Status == DEAD)
{
if(ptr->Kind==ENEMY_PIG)
{
CardList.push_back(World.GetCard());
CardList.push_back(World.GetCard());
CardList.push_back(World.GetCard());
}
}
}
void class_friend_pig::UseCard(enum_card c)
{
DropCard(c);
class_basic_pig* ptr;
switch (c)
{
case KILL:
ptr = World.GetNext(num);
ptr->C_AttackBy(this);
CheckAfterAttack(ptr);
break;
case BLOOD:
++Blood;
break;
case N_ATK:
N_Attack();
break;
case W_ATK:
W_Attack();
break;
case ARM:
Armed = true;
break;
case FIGHT:
ptr = World.GetEnemy(num, this);
StartFightWith(ptr);
break;
}
}
bool class_friend_pig::UseSpecialDefence(Event e)
{
bool tag = false;
if (e.target->Status == FRIEND)
{
if (!e.Good)//event表示对友军表敌意
{
tag= true;//使用无懈可击献殷勤
}
}
if (e.target->Status == ENEMY)
{
if (e.Good)//对敌军献殷勤
{
tag= true;//表敌意
}
}
if (tag)
{
tag = DropCard(J_DF);
}
return tag;
}
void class_friend_pig::UpdataIdentity()
{
Status = FRIEND;
}
/////////////////////////////////////////////////////////////////////
void class_enemy_pig::N_AttackBy(class_basic_pig* ptr)
{
if (!World.CheckSpecialDefnece(Event(ptr, this, false)))
{
return;
}
if (DropCard(KILL))
{
return;//丢弃杀
}
else
{
Hurt();
}
}
void class_enemy_pig::W_AttackBy(class_basic_pig* ptr)
{
if (!World.CheckSpecialDefnece(Event(ptr, this, false)))
{
return;
}
if (DropCard(MISS))
{
return;//丢弃闪
}
else
{
Hurt();
}
}
bool class_enemy_pig::Usable(const enum_card& c, bool& tag)//check if this card usable
{
if (class_basic_pig::Usable(c, tag))
{
return true;
}
//ptr = World.GetEnemy(num, ((const bool (class_basic_pig::*)(const enum_status&))this->IsEnemy));
if (c == FIGHT)
{
return true;
}
return false;
}
const bool class_enemy_pig::IsEnemy(const enum_status& s)
{
return s == FRIEND;
}
void class_enemy_pig::C_AttackBy(class_basic_pig* ptr)
{
ptr->Status = FRIEND;
if (DropCard(MISS))
{
;//丢弃闪
}
else
{
Hurt();
}
}
const bool class_enemy_pig::FightWith(class_basic_pig* ptr)//fight with ptr
{
if (DropCard(KILL))
{
return true;
}
else
{
Hurt();
return false;
}
return false;
}
void class_enemy_pig::CheckAfterAttack(class_basic_pig* ptr)//胜者结算
{
if (ptr->Status == DEAD)
{
if (ptr->Kind == ENEMY_PIG)
{
CardList.push_back(World.GetCard());
CardList.push_back(World.GetCard());
CardList.push_back(World.GetCard());
}
}
}
void class_enemy_pig::UseCard(enum_card c)
{
DropCard(c);
class_basic_pig* ptr;
switch (c)
{
case KILL:
ptr = World.GetNext(num);
ptr-> C_AttackBy(this);
CheckAfterAttack(ptr);
break;
case BLOOD:
++Blood;
break;
case N_ATK:
N_Attack();
break;
case W_ATK:
W_Attack();
break;
case ARM:
Armed = true;
break;
case FIGHT:
ptr = World.PigList[0];//主猪
StartFightWith(ptr);
break;
}
}
bool class_enemy_pig::UseSpecialDefence(Event e)
{
bool tag = false;
if (e.target->Status == ENEMY)
{
if (!e.Good)//event表示对友军表敌意
{
tag= true;//使用无懈可击献殷勤
}
}
if (e.target->Status == FRIEND)
{
if (e.Good)//对敌军献殷勤
{
tag= true;//表敌意
}
}
if (tag)
{
tag = DropCard(J_DF);
}
return tag;
}
void class_enemy_pig::UpdataIdentity()
{
Status = ENEMY;
}
enum_card translate(char ch)
{
enum_card card;
switch (ch)
{
case 'P':
card = BLOOD;
break;
case 'K':
card = KILL;
break;
case 'D':
card = MISS;
break;
case 'F':
card = FIGHT;
break;
case 'N':
card = N_ATK;
break;
case 'W':
card = W_ATK;
break;
case 'J':
card = J_DF;
break;
case 'Z':
card = ARM;
break;
}
return card;
}
int main()
{
int n, m;
char ch;
cin >> n >> m;
class_basic_pig* ptr;
for (reg int i = 0; i < n; ++i)
{
cin >> ch;
switch (ch)
{
case 'M':
ptr = new class_main_pig(i);
break;
case 'Z':
ptr = new class_friend_pig(i);
break;
case 'F':
ptr = new class_enemy_pig(i);
break;
}
World.PigList.push_back(ptr);
cin >> ch;
for (reg int j = 0; j < 4; ++j)
{
cin >> ch;
ptr->CardList.push_back(translate(ch));
}
}
World.PigList[0]->Status = FRIEND;
for (reg int i = 0; i < m; ++i)
{
cin >> ch;
World.CardPool.push(translate(ch));
}
World.GameBegin();
return 0;
}
```
刚刚上传工程才发现文件夹只有10几mb大,印象中vs一个工程100多mb的样子啊。。。。
**分享链接中,测试数据来自LOJ。**
**vs2015 project下载:**
[度盘链接](https://pan.baidu.com/s/1eoVcX2Zz1LkBpbVHyGZKxA)
提取码:6nbh
希望管理大大给个通过。