[Sdoi2010]猪国杀
概述
《猪国杀》是一种多猪牌类回合制游戏,一共有三种角色:主猪,忠猪,反猪。
每局游戏主猪有且只有一只,忠猪和反猪可以有多只,每只猪扮演一种角色。
游戏目的
主猪(MP):自己存活的情况下消灭所有的反猪。
忠猪(ZP):不惜一切保护主猪,胜利条件与主猪相同。
反猪(AP):杀死主猪。
游戏过程
游戏开始时候,每个玩家手里都会有 4 张牌,且体力上限和初始体力都是 4 。
开始游戏时,从主猪开始,按照逆时针方向(数据中就是按照编号从 1, 2, 3...n, 1... 的顺序)依次行动。
每个玩家自己的回合可以分为 4 个阶段
摸牌阶段
从牌堆顶部摸两张牌,依次放到手牌的最右边。
出牌阶段
你可以使用 0 张到任意张牌,每次使用牌的时候都使用最靠左的能够使用的牌。
当然,要满足如下规则
如果没有猪哥连弩,每个出牌阶段只能使用一次“杀”来攻击。
任何牌被使用后被弃置(武器是装备上)。
被弃置的牌以后都不能再用,即与游戏无关。
各种牌介绍
每张手牌用一个字母表示,字母代表牌的种类。
基本牌
『桃(P)』
在自己的回合内,如果自己的体力值不等于体力上限,那么使用一个桃可以为自己补充一点体力;否则不能使用桃。
桃只能对自己使用。
在自己的回合外,如果自己的血变为 0 或者更低,那么也可以使用。
『杀(K)』
在自己的回合内,对攻击范围内除自己以外的一名角色使用。
如果没有被『闪』抵消,则造成 1 点伤害。
无论有无武器,杀的攻击范围都是 1。
『闪(D)』
当你受到杀的攻击时,可以弃置一张闪来抵消杀的效果。
锦囊牌
『决斗(F)』
出牌阶段,对除自己以外任意一名角色使用,由目标角色先开始,自己和目标角色轮流弃置一张杀,首先没有杀可弃的一方受到1点伤害,另一方视为此伤害的来源。
『南猪入侵(N)』
出牌阶段,对除你以外所有角色使用,按逆时针顺序从使用者下家开始依次结算,除非弃置一张杀,否则受到1点伤害。
『万箭齐发(W)』
和南猪入侵类似,不过要弃置的不是杀而是闪。
『无懈可击(J)』
在目标锦囊生效前抵消其效果。
每次有一张锦囊即将生效时,从使用这张锦囊的猪开始,按照逆时针顺序,依次得到使用无懈可击的机会。
效果
用于决斗时,决斗无效并弃置。
用于南猪入侵或万箭齐发时,当结算到某个角色时才能使用,当前角色不需弃置牌并且不会受到伤害(仅对一个角色产生效果)。
用于无懈可击时,成为目标的无懈可击被无效。
装备牌
『猪哥连弩(Z)』
武器,攻击范围 1,出牌阶段你可以使用任意张杀。
同一时刻最多只能装一个武器。
如果先前已经有了一把武器,那么之后再装武器的话,会弃置以前的武器来装现在的武器。
特殊事件及概念解释
伤害来源
杀、南猪入侵、万箭齐发的伤害来源均是使用该牌的猪。
决斗的伤害来源如上。
距离
两只猪的距离定义为沿着逆时针方向间隔的猪数 +1。即初始时 1 和 2 的距离为 1 ,但是 2 和 1 的距离就是 n - 1 。
注意一个角色的死亡会导致一些猪距离的改变。
玩家死亡
如果该玩家的体力降到 0 或者更低,并且自己手中没有足够的桃使得自己的体力值回到 1,那么就死亡了,死亡后所有的牌(装备区,手牌区)被弃置、
奖励与惩罚
反猪死亡时,最后一个伤害来源处(即使是反猪)立即摸三张牌。
忠猪死亡时,如果最后一个伤害来源是主猪,那么主猪所有装备牌、手牌被弃置。
注意,一旦达成胜利条件,游戏立刻结束,因此即使会摸 3 张牌或者还有牌可以用也不用执行了。
现在,我们已经知道每只猪的角色、手牌,还有牌堆初始情况,并且假设每个角色会按照如下的行为准则进行游戏,你需要做的就是告诉小猪 iPig 最后的结果。
几种行为
献殷勤
使用无懈可击挡下南猪入侵、万箭齐发、决斗。
使用无懈可击抵消表敌意。
表敌意
对某个角色使用杀、决斗。
使用无懈可击抵消献殷勤。
跳忠
即通过行动表示自己是忠猪。
跳忠行动就是对主猪或对某只已经跳忠的猪献殷勤,或者对某只已经跳反的猪表敌意。
跳反
即通过行动表示自己是反猪。
跳反行动就是对主猪或对某只已经跳忠的猪表敌意,或者对某只已经跳反的猪献殷勤。
忠猪不会跳反,反猪也不会跳忠。
不管是忠猪还是反猪,能够跳必然跳。
行动准则
共性
每个角色如果手里有桃且生命值未满,那么必然吃掉。
有南猪入侵、万箭齐发、必然使用。
有装备必然装上。
受到杀时,有闪必然弃置。
响应南猪入侵或者万箭齐发时候,有杀/闪必然弃置。
不会对未表明身份的猪献殷勤(包括自己)。
特性
主猪
主猪会认为没有跳身份,且用南猪入侵/万箭齐发对自己造成伤害的猪是“类反猪”(没伤害到不算,注意“类反猪”并没有表明身份),如果之后跳了,那么主猪会重新认识这只猪。
对于每种表敌意的方式,对逆时针方向能够执行到的第一只“类反猪”或者已跳反猪表;如果没有,那么就不表敌意。
决斗时会不遗余力弃置杀。
如果能对已经跳忠的猪或自己献殷勤,那么一定献。
如果能够对已经跳反的猪表敌意,那么一定表。
忠猪
对于每种表敌意的方式,对逆时针方向能够执行到的第一只已经跳反的猪表;如果没有,那么就不表敌意。
决斗时,如果对方是主猪,那么不会弃置杀,否则,会不遗余力弃置杀。
如果有机会对主猪或者已经跳忠的猪献殷勤,那么一定献。
反猪
对于每种表敌意的方式,如果有机会则对主猪表,否则,对逆时针方向能够执行到的第一只已经跳忠的猪表;如果没有,那么就不表敌意。
决斗时会不遗余力弃置杀。
如果有机会对已经跳反的猪献殷勤,那么一定献。
限于 iPig 只会用 P++ 语言写 A + B,他请你用 Pigcal(Pascal)、P(C) 或 P++(C++) 语言来帮他预测最后的结果。
solution:
没什么说的,恶心大模拟,一堆坑点,码力太弱.......
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 int top,thief,n,m,Left,king=1,zpre[11],znxt[11],dis[11][11];; 7 char Card_heap[2005]; 8 bool like[11],dislike[11],simi_dislike[11]; 9 bool End; 10 bool nanmanruqin(int) ; 11 bool wanjianqifa(int) ; 12 bool Kill(int,int) ; 13 bool Lets_fight(int,int) ; 14 char cread() { 15 char ch=getchar(); 16 while(ch==32||ch==10||ch==13) ch=getchar(); 17 return ch; 18 } 19 class PIG { 20 private: 21 int pre[2005],nxt[2005],tail; 22 public: 23 char Card[2005],identity[5]; 24 int id,kill,protect,peach,fight,AOEkill,AOEprotect,wuxiekeji,wuqi,life; 25 bool equip,dead; 26 void add(char ch) { 27 if(ch=='P') ++peach; 28 if(ch=='K') ++kill; 29 if(ch=='D') ++protect; 30 if(ch=='F') ++fight; 31 if(ch=='N') ++AOEkill; 32 if(ch=='W') ++AOEprotect; 33 if(ch=='J') ++wuxiekeji; 34 if(ch=='Z') ++wuqi; 35 } 36 void write() { 37 for(int j=nxt[0]; j<=tail; j=nxt[j]) { 38 if(nxt[j]>tail) cout<<Card[j]; 39 else cout<<Card[j]<<" "; 40 } 41 } 42 void reduce(char ch) { 43 if(ch=='P') --peach; 44 if(ch=='K') --kill; 45 if(ch=='D') --protect; 46 if(ch=='F') --fight; 47 if(ch=='N') --AOEkill; 48 if(ch=='W') --AOEprotect; 49 if(ch=='J') --wuxiekeji; 50 if(ch=='Z') --wuqi; 51 for(int i=nxt[0]; i<=tail; i=nxt[i]) { 52 if(Card[i]==ch) { 53 pre[nxt[i]]=pre[i],nxt[pre[i]]=nxt[i]; 54 break; 55 } 56 } 57 } 58 void init(int e) { 59 scanf("%s",identity); 60 equip=false,life=4,id=e; 61 kill=protect=peach=AOEkill=AOEprotect=wuxiekeji=wuqi=0; 62 for(int i=1; i<=4; ++i) Card[++tail]=cread(),add(Card[tail]); 63 for(int i=0; i<=2000; ++i) pre[i]=i-1,nxt[i]=i+1; 64 } 65 void take_card(int num) { 66 int i; 67 for(i=1; i<=num&&top<m; ++i) Card[++tail]=Card_heap[++top],add(Card[tail])/*,cout<<Card[tail]<<" "*/; 68 if(i<=num) for( ; i<=num; ++i) Card[++tail]=Card_heap[top],add(Card[tail])/*,cout<<Card[tail]<<" "*/; 69 } 70 void punish() { 71 nxt[0]=tail+1; 72 pre[tail+1]=0; 73 equip=kill=protect=peach=AOEkill=AOEprotect=wuxiekeji=wuqi=0; 74 } 75 bool eat_peach() { 76 if(life==4||!peach) return false; 77 ++life,reduce('P'); 78 return true; 79 } 80 void Equip() { 81 if(!wuqi) return ; 82 reduce('Z'),equip=true; 83 } 84 bool action() { 85 bool used_kill=false; 86 while(true) { 87 bool if_action=false; 88 for(int i=nxt[0]; i<=tail; i=nxt[i]) { 89 if(life<=0) {if_action=false; break;} 90 if(Card[i]=='N') { 91 reduce(Card[i]); 92 bool now=nanmanruqin(id); 93 if(now) return true; 94 if_action=true; 95 break; 96 } 97 if(Card[i]=='W') { 98 reduce(Card[i]); 99 bool now=wanjianqifa(id); 100 if(now) return true; 101 if_action=true; 102 break; 103 } 104 if(Card[i]=='P') { 105 eat_peach(); 106 continue; 107 } 108 if(Card[i]=='Z') { 109 Equip(); 110 if_action=true; 111 break; 112 } 113 if(Card[i]=='K') { 114 if(!used_kill||equip) { 115 bool now=false; 116 if(identity[0]=='M'&&(dislike[znxt[id]]||simi_dislike[znxt[id]])) { 117 now=Kill(id,znxt[id]); 118 if(now) return true; 119 used_kill=if_action=true; 120 break; 121 } 122 if(identity[0]=='Z'&&dislike[znxt[id]]) { 123 now=Kill(id,znxt[id]); 124 if(now) return true; 125 used_kill=if_action=true; 126 break; 127 } 128 if(identity[0]=='F'&&(like[znxt[id]]||znxt[id]==1)) { 129 now=Kill(id,znxt[id]); 130 if(now) return true; 131 used_kill=if_action=true; 132 break; 133 } 134 } 135 continue; 136 } 137 if(Card[i]=='F') { 138 if(identity[0]=='M') { 139 int ji=0; 140 for(int i=znxt[id]; i!=id; i=znxt[i]) { 141 if(dislike[i]||simi_dislike[i]) { 142 ji=i; 143 break; 144 } 145 } 146 if(ji!=0) { 147 bool now=Lets_fight(id,ji); 148 if(now) return true; 149 if_action=true; 150 break; 151 } 152 continue; 153 } 154 if(identity[0]=='Z') { 155 int ji=0; 156 for(int i=znxt[id]; i!=id; i=znxt[i]) if(dislike[i]) { 157 ji=i; 158 break; 159 } 160 if(ji!=0) { 161 bool now=Lets_fight(id,ji); 162 if(now) return true; 163 if_action=true; 164 break; 165 } 166 continue; 167 } 168 if(identity[0]=='F') { 169 bool now=Lets_fight(id,1); 170 if(now) return true; 171 if_action=true; 172 break; 173 } 174 } 175 } 176 if(if_action) continue; 177 else break; 178 } 179 return false; 180 } 181 } pig[11]; 182 183 184 void divide_dis() { 185 memset(dis,0x5f,sizeof(dis)); 186 int ji=0; 187 for(register int i=1,now=0; i<=n; i=znxt[i],now=0) { 188 if(i==1&&!ji) ++ji; 189 if(i==1&&ji) break; 190 for(register int j=znxt[i]; j<=n; ++j) dis[i][j]=++now,dis[j][i]=Left-now; 191 } 192 } 193 int If_end() { 194 if(!king) return 1; 195 if(!thief) return 2; 196 return 0; 197 } 198 bool Be_killed(int who,int who_kill) { 199 if(pig[who].life>0) return false; 200 --Left,pig[who].dead=true; 201 if(pig[who].identity[0]=='M') --king; 202 if(pig[who].identity[0]=='F') --thief; 203 if(If_end()) { 204 End=true; 205 return true; 206 } 207 if(pig[who].identity[0]=='F') pig[who_kill].take_card(3); 208 if(pig[who].identity[0]=='Z'&&pig[who_kill].identity[0]=='M') pig[who_kill].punish(); 209 zpre[znxt[who]]=zpre[who],znxt[zpre[who]]=znxt[who]; 210 divide_dis(); 211 return false; 212 } 213 void Start_init() { 214 scanf("%d%d",&n,&m); 215 Left=n; 216 for(int i=1; i<=n; ++i) { 217 pig[i].init(i); 218 if(pig[i].identity[0]=='F') ++thief; 219 } 220 for(int i=1; i<=n; ++i) zpre[i]=i-1,znxt[i]=i+1; 221 znxt[n]=1,zpre[1]=n; 222 divide_dis(); 223 for(int i=1; i<=m; ++i) Card_heap[i]=cread(); 224 } 225 bool love(int fr,int to) { 226 if(pig[fr].identity[0]=='Z'&&(pig[to].id==1||like[to])) return true; 227 if(pig[fr].id==1&&(like[to]||pig[to].id==1)) return true; 228 if(pig[fr].identity[0]=='F'&&dislike[to]) return true; 229 return false; 230 } 231 bool hate(int fr,int to) { 232 if(pig[fr].identity[0]=='F'&&(pig[to].id==1||like[to])) return true; 233 if(pig[fr].id==1&&dislike[to]) return true; 234 if(pig[fr].identity[0]=='Z'&&dislike[to]) return true; 235 return false; 236 } 237 void make(int fr) { 238 if(pig[fr].identity[0]=='Z') like[fr]=true,dislike[fr]=false,simi_dislike[fr]=false; 239 if(pig[fr].identity[0]=='F') like[fr]=false,dislike[fr]=true,simi_dislike[fr]=false; 240 } 241 bool wuxie(int now,int to,bool sta) { // 1 被攻击 0 已经被无懈 242 if(!like[to]&&!dislike[to]&&pig[to].id!=1) return 0; 243 for(int i=now,bo=0; i!=now||bo==0; i=znxt[i]) { 244 bo=1; 245 if(!pig[i].wuxiekeji) continue; 246 if(love(i,to)&&sta) {make(i);pig[i].reduce('J');return wuxie(znxt[i],i,0)^1;} 247 if(hate(i,to)&&!sta) {make(i);pig[i].reduce('J');return wuxie(znxt[i],i,0)^1;} 248 } 249 return 0; 250 } 251 int main() { 252 Start_init(); 253 for(int i=1,ji=1; !End; i=znxt[i],++ji) { 254 pig[i].take_card(2); 255 pig[i].action(); 256 } 257 if(If_end()==1) printf("FP\n"); 258 else printf("MP\n"); 259 for(int i=1; i<=n; ++i,printf("\n")) { 260 if(pig[i].dead) printf("DEAD"); 261 else pig[i].write(); 262 } 263 return 0; 264 } 265 266 bool nanmanruqin(int who_use) { 267 for(int i=znxt[who_use]; i!=who_use; i=znxt[i]) { 268 if(wuxie(who_use,i,true)) continue; 269 if(!pig[i].kill) { 270 --pig[i].life; 271 if(!pig[i].life) { 272 if(!pig[i].eat_peach()) 273 if(Be_killed(i,who_use))return true; 274 } 275 if(i==1) simi_dislike[who_use]=true; 276 } 277 if(pig[i].kill) pig[i].reduce('K'); 278 } 279 return false; 280 } 281 bool wanjianqifa(int who_use) { 282 for(int i=znxt[who_use]; i!=who_use; i=znxt[i]) { 283 if(wuxie(who_use,i,true)) continue; 284 if(!pig[i].protect) { 285 --pig[i].life; 286 if(!pig[i].life) { 287 if(!pig[i].eat_peach()) { 288 if(Be_killed(i,who_use))return true; 289 } 290 } 291 if(i==1) simi_dislike[who_use]=true; 292 } else pig[i].reduce('D'); 293 } 294 return false; 295 } 296 bool Kill(int fr,int to) { 297 pig[fr].reduce('K'); 298 if(!pig[to].protect) { 299 --pig[to].life; 300 if(!pig[to].life) { 301 if(!pig[to].eat_peach()) { 302 bool now=Be_killed(to,fr); 303 if(now) { 304 End=true; 305 return true; 306 } 307 } 308 } 309 } else pig[to].reduce('D'); 310 if(pig[to].identity[0]=='M'||like[to]) dislike[fr]=true; 311 if(dislike[to]) like[fr]=true; 312 return false; 313 } 314 bool Lets_fight(int fr,int to) { 315 if(pig[to].id==1||like[to]) dislike[fr]=true; 316 if(dislike[to]) like[fr]=true; 317 pig[fr].reduce('F'); 318 if(wuxie(fr,to,true)) return false; 319 if((fr==1&&pig[to].identity[0]=='Z')) { 320 --pig[to].life; 321 if(!pig[to].life) if(!pig[to].eat_peach()) Be_killed(to,fr); 322 return false; 323 } 324 int now=1; 325 while(true) { 326 int dd=now?to:fr; 327 if(pig[dd].kill) { 328 pig[dd].reduce('K'); 329 now^=1; 330 continue; 331 } 332 if(!pig[dd].kill) { 333 --pig[dd].life; 334 if(!pig[dd].life) { 335 if(pig[dd].eat_peach()) break; 336 else { 337 bool ss=Be_killed(dd,dd==fr?to:fr); 338 if(ss) return true; 339 } 340 } 341 break; 342 } 343 now^=1; 344 } 345 return false; 346 }