P2482 [SDOI2010] 猪国杀 代码(暂未AC)

WG-MingJunYi / 2024-07-13 / 原文

#include<bits/stdc++.h>
using namespace std;
namespace work{

const int maxPlayerNumber = 11;

int n,m,top;//玩家数,牌堆中的牌数,目前的牌堆顶
unordered_map<string,int> transCard;//牌型编号
unordered_map<string,int> transRole;//角色编号

vector<int> cardHeap;//牌堆

int prince = 1,enemy,princePos;//反贼数量和主公数量,主公位置

int Sstate = 0;//场上无懈可击状态

struct Player{
	int role,state,health,Psum,Wsum;//玩家角色,装备(是否装备上诸葛连弩),体力值,桃的数量,无懈可击的数量
	string endState = "ALIVE";//在场状态(死亡判断)
	bool usedKill;//是否在出牌阶段使用了‘杀’
	list<int> card;//手牌
}P[maxPlayerNumber];

int emo[maxPlayerNumber];//对每个玩家的态度 (1 - 主公,2 - 跳忠,3 - 跳反,4 - 类反)

void init() {
	transRole["MP"] = 1;transRole["ZP"] = 2;transRole["FP"] = 3;
	transCard["P"] = 1;transCard["K"] = 2;transCard["D"] = 3;transCard["F"] = 4;
	transCard["N"] = 5;transCard["W"] = 6;transCard["J"] = 7;transCard["Z"] = 8;
}

void getData() {
	//读数据
	cin>>n>>m;
	string s;
	for(int i = 1;i<=n;i++) {
		cin>>s;
		P[i].role = transRole[s];
		P[i].health = 4;
		if(s == "MP") princePos = i;
		if(P[i].role == 3) enemy++;
		for(int j = 1;j<=4;j++) {
			cin>>s;
			P[i].card.emplace_back(transCard[s]);
			if(s == "P") P[i].Psum++; 
		}
	}
	emo[princePos] = 1;
	for(int i = 1;i<=m;i++) {
		cin>>s;
		cardHeap.emplace_back(transCard[s]);
	}
}

bool Check() {
	//判断局面情况
	if(!prince) return -1;
	if(!enemy) return 1;
	return 0;
}

int now = 1;

void getCard(int player){
	//摸牌
	if(cardHeap[top] == 1) P[player].Psum++;
	if(cardHeap[top] == 7) P[player].Wsum++;
	P[player].card.emplace_back(cardHeap[top++]);
	if(top == m) top = m - 1;
}

void usePeach(int player) {
	//被动使用桃
	auto it = P[player].card.begin();
	for(;it != P[player].card.end() && P[player].health <= 0;it++) {
		if(*it == 1) {
			//桃数量减少,生命值增加,移除一枚桃
			P[player].Psum--;
			P[player].health++;
			P[player].card.erase(it);
			it--;
		}
	}
}


void Death(int player,int Damage){
	//死亡判定  死亡者     伤害来源
	if(P[player].role == 1) prince = 0;
	else if(P[player].role == 2 && P[Damage].role == 1) {
		//主公 - kill -> 忠臣
		P[Damage].state = 0;
		P[Damage].Psum = 0;
		P[Damage].Wsum = 0;
		list<int> emp;
		swap(emp,P[Damage].card);
	}else if(P[player].role == 3) {
		// ? - kill -> 反贼
		getCard(Damage);getCard(Damage);getCard(Damage);
	}
	P[player].endState = "DEAD";
}

void getDamage(int player,int given){
	//造成伤害
	P[player].health--;
	//无力回天 -> 判定死亡
	if(P[player].health <= 0 && P[player].Psum + P[player].health <= 0) Death(player,given);
	else usePeach(player);//使用桃回血
}

bool useDefence(int player) {
	//被动使用闪
	auto it = P[player].card.begin();
	for(;it != P[player].card.end();it++) {
		if(*it == 3) {
			P[player].card.erase(it);
			return true;
		}
	}
	return false;
}

bool useKill(int player) {
	//被动使用杀
	auto it = P[player].card.begin();
	for(;it != P[player].card.end();it++) {
		if(*it == 2) {
			P[player].card.erase(it);
			return true;
		}
	}
	return false;
}

void Kill(int given,int recieve){
	//使用杀
	P[given].state = 1;
	if(useDefence(recieve)) return;
	else getDamage(recieve,given);
	//主公身份不需要更改
	if(P[given].role == 1) return;
	//跳忠/主公 + 反贼 -> 跳反
	if((emo[recieve] == 1 || emo[recieve] == 2) && P[given].role == 3) emo[given] = 3;
	//跳反 + 忠臣 -> 跳忠
	if(emo[recieve] == 3 && P[given].role == 2) emo[given] = 2;  
}

void useWatertight(int player,int recieve) {
	//使用无懈可击
	auto it = P[player].card.begin();
	for(;it != P[player].card.end();it++) {
		if(*it == 7) {
			P[player].card.erase(it);
			break;
		}
	}
	Sstate ^= 1;
	//无懈 + 非主公 + 主公/跳忠 -> 此人跳忠
	if(P[player].role != 1 && (emo[recieve] == 1 || emo[recieve] == 2) && Sstate) emo[player] = 2;
	P[player].Wsum--;
}

bool askWatertight(int recieve,int given){
	//询问无懈可击
	int tag = 0;//响应圈数计数器
	int now_given = given;//锦囊发起者
	for(int i = now_given;;i++) {
		if(i == n + 1) i = 1;
		if(i == now_given) tag++;
		if(tag == 2) break;//询问 1 圈后没人响应
		if(P[i].Wsum) continue;
		//注意无懈可击使用后,需重新询问全体成员
		//未被无懈状态 + 忠臣 + 跳忠/主公
		if(!Sstate && P[i].role == 2 && (emo[recieve] == 1 || emo[recieve] == 2)) {
			useWatertight(i,recieve);
			tag = 0;
			now_given = i;
		}
		//被无懈 + 忠臣 + 跳反
		else if(Sstate && P[i].role == 2 && emo[recieve] == 3) {
			useWatertight(i,recieve);
			tag = 0;
			now_given = i;
		}
		//被无懈 + 主公 + 跳反/类反  
		else if(Sstate && P[i].role == 1 && (emo[recieve] == 3 || emo[recieve] == 4)) {
			useWatertight(i,recieve);
			tag = 0;
			now_given = i;
		}
	}
	return Sstate;
}

void Fight(int given,int recieve){
	//决斗
	if(askWatertight(recieve,given)) return;
	if(P[given].role == 1 && P[recieve].role == 2) getDamage(recieve,given);
	else {
		while(useKill(recieve)) swap(given,recieve);
		getDamage(recieve,given);
		if(P[given].role == 1) return;
		if((emo[recieve] == 1 || emo[recieve] == 2) && P[given].role == 3) emo[given] = 3;
		if(emo[recieve] == 3 && P[given].role == 2) emo[given] = 2;   
	}
}

void SavageAssault(int player){
	//南蛮入侵
	for(int i = player + 1;i != player;i++) {
		//每回合使用无懈可击时刷新场上无懈可击状态
		Sstate = 0;
		if(i == n + 1) i = 1;
		//询问无懈可击
		if(askWatertight(i,player)) continue;
		//判断是否有‘杀’可以响应
		if(!useKill(i)) {
			//没有杀,扣血
			getDamage(i,player);
			//如果让主公掉血,被判断为 ‘类反贼’
			if(i == princePos) if(!emo[i]) emo[i] = 4;
		}
	}
}


void ArcheryAttack(int player){
	//万箭齐发
	for(int i = player + 1;i != player;i++) {
		Sstate = 0;
		if(i == n + 1) i = 1;
		//询问无懈可击
		if(askWatertight(i,player)) continue;
		//判断是否有‘闪’可以响应
		if(!useDefence(i)) {
			//没有闪,扣血
			getDamage(i,player);
			//如果让主公掉血,被判断为 ‘类反贼’
			if(i == princePos) if(!emo[i]) emo[i] = 4;
		}
	}
}


void use(int player,list<int>::iterator it) {
	//使用牌
	int card = *it;
	if(card == 1 && P[player].health < 4) {
		P[player].Psum--;
		P[player].health++;
		P[player].card.erase(it);
	}
	else if(card == 2 && ((!P[player].usedKill) || (P[player].state))) {
		//使用杀时,只有距离为 1 的位置才能使用,如果没有必要使用就跳过

		//只有正向的距离是 1,反向距离不用考虑
		for(int i = player + 1;i != player;i++){
			if(i == n + 1) i = 1;
			if(P[i].health < 0) continue;
			if(P[player].role == 1 && (emo[i] == 3 || emo[i] == 4)) {
				P[player].card.erase(it);
				Kill(player,i);
				return;
			}else if(P[player].role == 2 && emo[i] == 3) {
				P[player].card.erase(it);
				Kill(player,i);
				return;
			}else break;
		}
	} else if(card == 4) {
		//使用决斗
		for(int i = player + 1;i != player;i++) {
			if(i == n + 1) i = 1;
			if(P[i].health < 0) continue;
			if(P[player].role == 1 && (emo[i] == 3 || emo[i] == 4)) {
				P[player].card.erase(it);
				Fight(player,i);
				return;
			}else if(P[player].role == 2 && emo[i] == 3) {
				emo[player] = 2;
				P[player].card.erase(it);
				Fight(player,i);
				return;
			} 
		}
		Sstate = 0;
	}else if(card == 5) {
		//使用南蛮入侵
		P[player].card.erase(it);

		SavageAssault(player);

		Sstate = 0;
	}else if(card == 6) {
		//使用万箭齐发
		P[player].card.erase(it);

		ArcheryAttack(player);

		Sstate = 0;
	}else if(card == 8) {
		//装备诸葛连弩
		P[player].state = 1;
		P[player].card.erase(it);
	}
}

void use_The_Card(int player){
	//遍历手牌
	auto it = P[player].card.begin();
	for(;it != P[player].card.end();it++) {
		int card = *it;
		auto it2 = it;
		it++;
		use(player,it2);
		it--;
		if(card == 8) it = P[player].card.begin();
		Check();
	}
}

void PlayerOption(int player){
	//玩家操作
	getCard(player);getCard(player);
	use_The_Card(player);
	P[player].usedKill = 0;
}

void solve(){
	getData();
	while(!Check()){
		if(P[now].health > 0) PlayerOption(now);
		now++;
		if(now == n + 1) now = 1;
	}
	//结束局面
	if(Check() == 1) {
		cout<<"MP\n";
		for(int i = 1;i<=n;i++) {
			if(P[i].endState == "DEAD") cout<<P[i].endState;
			else for(auto j:P[i].card) cout<<j<<" ";
			cout<<'\n';
		}
	}else {
		cout<<"FP\n";
		for(int i = 1;i<=n;i++) {
			if(P[i].endState == "DEAD") cout<<P[i].endState;
			else for(auto j:P[i].card) cout<<j<<" ";
			cout<<'\n';
		}
	}
}

}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	work::init();
	work::solve();
	return 0;
}