坑点:删牌;每次某位玩家阵亡带来的影响;按照从左往右顺序出牌,每次出牌后重新从左往右扫牌;及时结算;决斗使得出牌方死亡;无懈可击作用于无懈可击 etc
#include<iostream> #include<sstream> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<algorithm> #include<functional> #include<iomanip> #include<numeric> #include<cmath> #include<queue> #include<vector> #include<set> #include<cctype> #include<stack> #include<map> const double PI = acos(-1.0); const int INF = 0x3f3f3f3f; const int NINF = -INF - 1; const int maxn = 2e3 + 10; const double eps = 1e-9; typedef long long ll; using namespace std; int n, m; char deck[maxn];//牌组 int deck_num; struct node{ string id; char hand[maxn]; int hp; int crossbow;//连弩 int hand_num; }player[15]; int winner = 0; int num_use_kill;//单局使用杀的数量 int cur_player[15];//存活玩家 int killer[15];//伤害来源 int dis[15][15]; int maybe_FP[15], sure_FP[15], sure_ZP[15];//类反贼,反贼,忠臣 char last_card; int game_over = 0; void init(){ for(int i = 1; i <= n; ++i) maybe_FP[i] = 0, sure_FP[i] = 0, sure_ZP[i] = 0; for(int i = 1; i <= n; ++i) memset(player[i].hand, 0, sizeof(player[i].hand)); } void push_end_hand(int id, char c){//增加手牌 player[id].hand_num++; player[id].hand[player[id].hand_num] = c; } void delete_hand(int id, int pos){//删除手牌 player[id].hand_num--; for(int i = pos; i <= player[id].hand_num; ++i) player[id].hand[i] = player[id].hand[i + 1]; } char pop_top_deck(){//取出牌组顶端牌 char ans = deck[1]; deck_num--; for(int i = 1; i <= deck_num; ++i) deck[i] = deck[i + 1]; return ans; } void count_dis(){//计算距离 for(int i = 1; i <= n; ++i){ for(int j = 1; j <= n; ++j){ if(j >= i){ dis[i][j] = j - i; for(int k = i + 1; k < j; ++k) { if(!cur_player[k]) dis[i][j]--; } } else{ dis[i][j] = n - i + j; for(int k = i + 1; k <= n; ++k) { if(!cur_player[k]) dis[i][j]--; } for(int k = 1; k < j; ++k){ if(!cur_player[k]) dis[i][j]--; } } } } } void Draw(int x, int p){//摸牌 // if(player[x].hand_num == 0) cout << "当前手牌为空" << endl; while(p--){ char tmp; if(deck_num == 0) tmp = last_card; else tmp = pop_top_deck(); push_end_hand(x, tmp); } } int check_end(){//检查游戏是否结束 if(player[1].hp <= 0) { winner = 1;//winner为1,反贼获胜 return 1; } int flag = 0; for(int i = 2; i <= n; ++i){ if(player[i].id == "FP" && player[i].hp > 0){ flag = 1; break; } } if(flag) return 0; else { winner = 2;//winner为2,猪公获胜 return 1; } } void Reward_punishment(){ for(int i = 1; i <= n; ++i){ if(player[i].hp <= 0 && cur_player[i]){ int aim = killer[i]; if(player[i].id == "FP"){ Draw(aim, 3); } else if(player[i].id == "ZP" && player[aim].id == "MP"){ player[1].crossbow = 0; player[1].hand_num = 0; } } } } void mark_death(){ for(int i = 1; i <= n; ++i){ if(player[i].hp <= 0 && cur_player[i]) cur_player[i] = 0; } } int cur_eff(int x){//出一张牌后的影响 int near_death = 0;//是否有人濒死 for(int i = 1; i <= n; ++i){ if(player[i].hp <= 0 && cur_player[i]){ near_death++;//存在濒死 for(int j = 1; j <= player[i].hand_num; ++j){ if(player[i].hand[j] == 'P'){ player[i].hp = 1; delete_hand(i, j); near_death--;//濒死已经救活 break; } } } } if(near_death){//存在濒死未救活 if(check_end()) { mark_death(); // cout << "游戏结束" << endl; return 1;//当前出牌导致游戏结束 } Reward_punishment();//击杀奖励与惩罚 mark_death(); count_dis(); if(!cur_player[x]){//出牌方死亡 // cout << "出牌方死亡" << endl; return 1; } } return 0; } void res_D(int x, int source){//闪 int flag = 0; for(int i = 1; i <= player[x].hand_num; ++i){ if(player[x].hand[i] == 'D'){ flag = 1; delete_hand(x, i); break; } } if(!flag) { // cout << "使用杀造成1点伤害" << endl; player[x].hp--; killer[x] = source; if(cur_eff(source)) game_over = 1; } } void res_K(int x){//杀 if(player[x].id == "MP"){ for(int i = 2; i <= n; ++i){ if(dis[x][i] == 1 && cur_player[i]){//杀的距离只有1 if(maybe_FP[i] || sure_FP[i]){ res_D(i, x); } break; } } } else if(player[x].id == "ZP"){ for(int i = x + 1; i < n + x; ++i){ int tmp = i; if(tmp > n) tmp -= n; if(dis[x][tmp] == 1 && cur_player[tmp]){ if(sure_FP[tmp]){//跳忠 res_D(tmp, x); sure_ZP[x] = 1; maybe_FP[x] = 0; sure_FP[x] = 0; } break; } } } else if(player[x].id == "FP"){ for(int i = x + 1; i < n + x; ++i){ int tmp = i; if(tmp > n) tmp -= n; if(dis[x][tmp] == 1 && cur_player[tmp]){ if(tmp == 1 || sure_ZP[tmp]){//跳反 res_D(tmp, x); sure_FP[x] = 1; maybe_FP[x] = 0; sure_ZP[x] = 0; } break; } } } } //使用无懈可击无效无懈可击 int J_to_J(int x, int fac){//fac=0,表示目标为主公方;fac=1,表示目标为反贼 int cur_use_J = x;//这次使用无懈可击的玩家 int do_J = 0; if(fac == 0){ for(int i = x; i < n + x; ++i){ int tmp = i; if(tmp > n) tmp -= n; if(!cur_player[tmp]) continue; if(player[tmp].id == "FP"){ for(int j = 1; j <= player[tmp].hand_num; ++j){ if(player[tmp].hand[j] == 'J'){ // cout << tmp << "使用了无懈可击" << endl; do_J = 1; sure_FP[tmp] = 1; maybe_FP[tmp] = 0; sure_ZP[tmp] = 0; delete_hand(tmp, j); cur_use_J = tmp; break; } } if(do_J) break;; } } } else if(fac == 1){ for(int i = x; i < n + x; ++i){ int tmp = i; if(tmp > n) tmp -= n; if(!cur_player[tmp]) continue; if(player[tmp].id == "MP"){ for(int j = 1; j <= player[tmp].hand_num; ++j) { if (player[tmp].hand[j] == 'J') { // cout << "主公使用了无懈可击" << endl; do_J = 1; delete_hand(tmp, j); cur_use_J = tmp; break; } } } else if(player[tmp].id == "ZP"){ for(int j = 1; j <= player[tmp].hand_num; ++j) { if (player[tmp].hand[j] == 'J') { do_J = 1; sure_ZP[tmp] = 1; maybe_FP[tmp] = 0; sure_FP[tmp] = 0; delete_hand(tmp, j); cur_use_J = tmp; break; } } } if(do_J) break; } } if(do_J == 0) return 1; else { if(J_to_J(cur_use_J, fac ^ 1)) return 0; else return 1; } } int res_J(int x, int source){//无懈可击,能触发无懈可击,其身份必然被确定 int do_J = 0;//是否成功无懈可击 int find_J = 0;//是否找到无懈可击 if(player[x].id == "MP"){ for(int i = source; i < n + source; ++i){ int tmp = i; if(tmp > n) tmp -= n; if(!cur_player[tmp]) continue; if(player[tmp].id == "MP"){//主公自救 for(int j = 1; j <= player[tmp].hand_num; ++j){ if(player[tmp].hand[j] == 'J'){ // cout << "主公使用无懈可击" << endl; delete_hand(tmp, j); if(J_to_J(1, 0)) do_J = 1; find_J = 1; break; } } } else if(player[tmp].id == "ZP"){//忠臣献殷勤,将导致跳忠 for(int j = 1; j <= player[tmp].hand_num; ++j){ if(player[tmp].hand[j] == 'J'){ // cout << "忠臣帮助主公使用了无懈可击" << endl; delete_hand(tmp, j); if(J_to_J(tmp, 0)) do_J = 1; sure_ZP[tmp] = 1; maybe_FP[tmp] = 0; sure_FP[tmp] = 0; find_J = 1; break; } } } if(find_J) break; } } else if(player[x].id == "ZP"){ for(int i = source; i < n + source; ++i){ int tmp = i; if(tmp > n) tmp -= n; if(!cur_player[tmp]) continue; if(player[tmp].id == "MP"){//主公出手救跳忠忠臣 for(int j = 1; j <= player[tmp].hand_num; ++j){ if(player[tmp].hand[j] == 'J'){ delete_hand(tmp, j); if(J_to_J(1, 0)) do_J = 1; find_J = 1; break; } } } else if(player[tmp].id == "ZP"){ for(int j = 1; j <= player[tmp].hand_num; ++j){ if(player[tmp].hand[j] == 'J'){ delete_hand(tmp, j); if(J_to_J(tmp, 0)) do_J = 1; sure_ZP[tmp] = 1; maybe_FP[tmp] = 0; sure_FP[tmp] = 0; find_J = 1; break; } } } if(find_J) break; } } else if(player[x].id == "FP"){ for(int i = source; i < n + source; ++i){//锦囊牌按序依次出牌 int tmp = i; if(tmp > n) tmp -= n; if(!cur_player[tmp]) continue; if(player[tmp].id == "FP"){ for(int j = 1; j <= player[tmp].hand_num; ++j){ if(player[tmp].hand[j] == 'J'){//对跳反献殷勤将导致跳反 delete_hand(tmp, j); if(J_to_J(tmp, 1)) do_J = 1; sure_FP[tmp] = 1; maybe_FP[tmp] = 0; sure_ZP[tmp] = 0; find_J = 1; break; } } } if(find_J) break; } } if(do_J) return 1; else return 0; } void do_F(int x, int aim, int num_kill){//进行决斗 int aim_num_kill = 0;//被决斗方'杀'的数量 for(int i = 1; i <= player[aim].hand_num; ++i){ if(player[aim].hand[i] == 'K') aim_num_kill++; } // cout << "决斗进行:决斗发起方的'杀'的数量:" << num_kill << " 决斗目标'杀'的数量:" << aim_num_kill << endl; if(num_kill >= aim_num_kill){ player[aim].hp--; killer[aim] = x; if(cur_eff(x)) game_over = 1; int winner_get_up = aim_num_kill;//获胜者需要弃牌量 while(1){ for(int i = 1; i <= player[x].hand_num; ++i){ if(winner_get_up == 0) break; if(player[x].hand[i] == 'K'){ winner_get_up--; delete_hand(x, i); } } if(winner_get_up == 0) break; } while(1){ for(int i = 1; i <= player[aim].hand_num; ++i){ if(player[aim].hand[i] == 'K'){ aim_num_kill--; delete_hand(aim, i); } } if(aim_num_kill == 0) break; } // cout << "决斗败者的手牌:" << endl; // for(int i = 1; i <= player[aim].hand_num; ++i) cout << player[aim].hand[i] << ' '; // cout << endl; } else{ player[x].hp--; killer[x] = aim; if(cur_eff(x)) game_over = 1; int winner_get_up = num_kill + 1; while(1){ for(int i = 1; i <= player[aim].hand_num; ++i){ if(winner_get_up == 0) break; if(player[aim].hand[i] == 'K'){ winner_get_up--; delete_hand(aim, i); } } if(winner_get_up == 0) break; } while(1){ for(int i = 1; i <= player[x].hand_num; ++i){ if(player[x].hand[i] == 'K') { num_kill--; delete_hand(x, i); } } if(num_kill == 0) break; } } } void res_F(int x){//决斗 int num_kill = 0;//决斗使用者的'杀'的数量 for(int i = 1; i <= player[x].hand_num; ++i){ if(player[x].hand[i] == 'K') num_kill++; } if(player[x].id == "MP"){ for(int i = 2; i <= n; ++i){ if(cur_player[i] && (maybe_FP[i] || sure_FP[i])){ if(maybe_FP[i]){ player[i].hp--; killer[i] = x; if(cur_eff(x)) game_over = 1; } else{ if(res_J(i, x)) return; else do_F(x, i, num_kill); } return; } } } else if(player[x].id == "ZP"){ for(int i = x + 1; i < n + x; ++i){ int tmp = i; if(tmp > n) tmp -= n; if(cur_player[tmp] && sure_FP[tmp]){ if(res_J(tmp, x)){ } else{ do_F(x, tmp, num_kill); } sure_ZP[x] = 1; maybe_FP[x] = 0; sure_FP[x] = 0; return; } } } else if(player[x].id == "FP"){ if(res_J(1, x)){//反贼只会决斗主公 } else{ do_F(x, 1, num_kill); } sure_FP[x] = 1; maybe_FP[x] = 0; sure_ZP[x] = 0; return; } } int find_aim_K(int x){ // cout << x << "已经出了" << num_use_kill << "张杀了" << endl; if(num_use_kill == 1 && player[x].crossbow == 0) return 0; for(int i = x + 1; i < n + x; ++i){ int tmp = i; if(tmp > n) tmp -= n; if(dis[x][tmp] == 1 && cur_player[tmp]){ if(player[x].id == "MP"){ if(sure_FP[tmp] || maybe_FP[tmp]) return 1; } else if(player[x].id == "ZP"){ if(sure_FP[tmp]) return 1; } else if(player[x].id == "FP"){ if(tmp == 1 || sure_ZP[tmp]) return 1; } } } return 0; } int find_aim_F(int x){ if(player[x].id == "MP"){ for(int i = 2; i <= n; ++i){ if(sure_FP[i] || maybe_FP[i]) return 1; } } else if(player[x].id == "ZP"){ for(int i = x + 1; i < n + x; ++i){ int tmp = i; if(tmp > n) tmp -= n; if(sure_FP[tmp]) return 1; } } else return 1; return 0; } int find_aim_P(int x){ if(player[x].hp < 4) return 1; else return 0; } int get_up_K_D(int x, int flag){//flag=0,丢弃'杀';flag=1,丢弃'闪' for(int i = 1; i <= player[x].hand_num; ++i){ if(flag == 0){ if(player[x].hand[i] == 'K'){ delete_hand(x, i); return 1; } } else if(flag == 1){ if(player[x].hand[i] == 'D'){ delete_hand(x, i); return 1; } } } player[x].hp--; return 0; } void res_N(int x){//南蛮入侵 for(int i = x + 1; i < n + x; ++i){ int tmp = i; if(tmp > n) tmp -= n; if(!cur_player[tmp]) continue; if(player[tmp].id == "MP"){ if(res_J(tmp, x)) { // cout << "主公通过无懈可击规避了南蛮入侵" << endl; continue;//成功无懈可击 } if(get_up_K_D(tmp, 0)){//成功弃牌 // cout << "主公成功弃牌规避了南蛮入侵" << endl; } else{ killer[tmp] = x; if(cur_eff(x)) { game_over = 1; return; } // cout << "主公受到南蛮入侵的伤害" << endl; if(!sure_FP[x] && !sure_ZP[x]) { maybe_FP[x] = 1;//身份不确定,并对主公造成伤害,标记类反贼 } } } else if(player[tmp].id == "ZP"){ if(sure_ZP[tmp]) { if(res_J(tmp, x)) { // cout << tmp << "通过无懈可击规避了南蛮入侵" << endl; continue;//只有确定忠臣身份才会触发无懈可击 } } if(!get_up_K_D(tmp, 0)) { // cout << tmp << "受到了南蛮入侵的伤害" << endl; killer[tmp] = x; if(cur_eff(x)){ game_over = 1; return; } } else{ // cout << tmp << "成功弃牌规避了南蛮入侵" << endl; } } else if(player[tmp].id == "FP"){ if(sure_FP[tmp]) { if(res_J(tmp, x)) { // cout << tmp << "通过无懈可击规避了南蛮入侵" << endl; continue; } } if(!get_up_K_D(tmp, 0)) { // cout << tmp << "受到了南蛮入侵的伤害" << endl; killer[tmp] = x; if(cur_eff(x)){ game_over = 1; return; } } else{ // cout << tmp << "成功弃牌规避了南蛮入侵" << endl; } } } } void res_W(int x){//万箭齐发 for(int i = x + 1; i < n + x; ++i){ int tmp = i; if(tmp > n) tmp -= n; if(!cur_player[tmp]) continue; if(player[tmp].id == "MP"){ if(res_J(tmp, x)) { // cout << "主公通过无懈可击规避了万箭齐发" << endl; continue;//成功无懈可击 } if(get_up_K_D(tmp, 1)){//成功弃牌 // cout << "主公成功弃牌规避了万箭齐发" << endl; } else{ killer[tmp] = x; if(cur_eff(x)){ game_over = 1; return; } // cout << "主公受到万箭齐发的伤害" << endl; if(!sure_FP[x] && !sure_ZP[x]) { maybe_FP[x] = 1;//身份不确定,并对主公造成伤害,标记类反贼 } } } else if(player[tmp].id == "ZP"){ if(sure_ZP[tmp]) { if(res_J(tmp, x)) { // cout << tmp << "通过无懈可击规避了万箭齐发" << endl; continue;//只有确定忠臣身份才会触发无懈可击 } } if(!get_up_K_D(tmp, 1)) { // cout << tmp << "受到了万箭齐发的伤害" << endl; killer[tmp] = x; if(cur_eff(x)){ game_over = 1; return; } } else{ // cout << tmp << "成功弃牌规避了万箭齐发" << endl; } } else if(player[tmp].id == "FP"){ if(sure_FP[tmp]) { if(res_J(tmp, x)) { // cout << tmp << "通过无懈可击规避了万箭齐发" << endl; continue; } } if(!get_up_K_D(tmp, 1)) { // cout << tmp << "受到了万箭齐发的伤害" << endl; killer[tmp] = x; if(cur_eff(x)){ game_over = 1; return; } } else{ // cout << tmp << "成功弃牌规避了万箭齐发" << endl; } } } } int end_round(int x){ int flag = 0; for(int i = 1; i <= player[x].hand_num; ++i){ if(player[x].hand[i] == 'D' || player[x].hand[i] == 'J') flag++; else if(player[x].hand[i] == 'P'){ if(!find_aim_P(x)) flag++; } else if(player[x].hand[i] == 'K') { if(!find_aim_K(x)) flag++; } else if(player[x].hand[i] == 'F'){ if(!find_aim_F(x)) flag++; } } // cout << flag << endl; if(flag == player[x].hand_num) return 1; else return 0; } void Play_cards(int x){ while(1){ if(end_round(x)) { // cout << "无牌可出" << endl; return; } for(int i = 1; i <= player[x].hand_num; ++i){ char cur_card = player[x].hand[i]; if(cur_card == 'D' || cur_card == 'J') { continue; } else if(cur_card == 'Z'){ delete_hand(x, i); player[x].crossbow = 1; break; } else if(cur_card == 'P' && find_aim_P(x)){ // cout << x << "使用了桃子" << endl; delete_hand(x, i); player[x].hp++; break; } else if(cur_card == 'K' && find_aim_K(x)){ // cout << x << "使用了杀" << endl; delete_hand(x, i); res_K(x); num_use_kill++; break; } else if(cur_card == 'F' && find_aim_F(x)){ // cout << x << "使用了决斗" << endl; delete_hand(x, i); res_F(x); break; } else if(cur_card == 'N'){ // cout << x << "使用了南蛮入侵" << endl; delete_hand(x, i); res_N(x); break; } else if(cur_card == 'W'){ // cout << x << "使用了万箭齐发" << endl; delete_hand(x, i); res_W(x); break; } } if(game_over) { // cout << "游戏结束或者出牌方死亡" << endl; return; } } } void settlement(){//结算游戏 for(int i = 1; i <= n; ++i){ if(cur_player[i] == 0) cout << "DEAD" << endl; else{ int num_flag = 0; for(int j = 1; j <= player[i].hand_num; ++j){ if(num_flag == 0) cout << player[i].hand[j]; else cout << ' ' << player[i].hand[j]; num_flag++; } cout << endl; } } } int main(){ init(); cin >> n >> m; for(int i = 1; i <= n; ++i){ cin >> player[i].id; player[i].hand_num = 4; for(int j = 1; j <= 4; ++j){ char c; cin >> c; player[i].hand[j] = c; } player[i].hp = 4; player[i].crossbow = 0; cur_player[i] = 1; } deck_num = m; for(int i = 1; i <= m; ++i){ char tmp; cin >> tmp; if(i == m) last_card = tmp; deck[i] = tmp; } count_dis(); int cur = 1;//当前属于谁的回合 while(1){ if(cur > n) cur -= n; if(!cur_player[cur]) { cur++; continue; } // cout << "现在由" << cur << "号玩家出牌" << endl; num_use_kill = 0; game_over = 0; Draw(cur, 2);//摸牌 // cout << "摸牌后手牌如下:" << endl; // for(int i = 1; i <= player[cur].hand_num; ++i) cout << player[cur].hand[i] << ' '; // cout << endl; Play_cards(cur);//出牌 // cout << cur << "号玩家出牌结束" << endl; // cout << "目前所有玩家手牌如下:" << endl; // for(int i = 1; i <= n; ++i){ // cout << player[i].id << ' '; // for(int j = 1; j <= player[i].hand_num; ++j) cout << player[i].hand[j] << ' '; // cout << endl; // } // cout << "当前所有玩家身份如下:" << endl; // for(int i = 2; i <= n; ++i){ // cout << i << ": "; // if(!sure_FP[i] && !sure_ZP[i] && !maybe_FP[i]) cout << "身份不确定" << endl; // else if(sure_ZP[i] && !sure_FP[i] && !maybe_FP[i]) cout << "忠臣" << endl; // else if(sure_FP[i] && !sure_ZP[i] && !maybe_FP[i]) cout << "反贼" << endl; // else if(maybe_FP[i] && !sure_ZP[i] && !sure_FP[i]) cout << "类反贼" << endl; // } // for(int i = 1; i <= n; ++i){ // cout << i << ": " << player[i].hp << endl; // } if(winner != 0) break;//游戏是否结束 // if(deck_num == 0) { // cout << "牌堆为空,游戏未结束" << endl; // break; // } // cout << cur << "号玩家回合结束" << endl; cur++; } if(winner == 1) cout << "FP" << endl; else if(winner == 2) cout << "MP" << endl; settlement(); return 0; }