猪国杀 写后感


——或许也是一篇题解

原题链接:P2482 [SDOI2010] 猪国杀

在开始进行这项百年工程之前,请确保你仔细阅读了题目并对它有足够的热情.
那么我再强调一下本题中容易忘记的小点,最后解释一下我的代码实现.

Part 0 : 大体思路 :

  1. 显然用结构体存储每只猪(每位玩家)的状态,手牌部分最直观的显然是链表,但鉴于本题数据规模极小,方便起见直接使用数组会减少很大的编写难度.
  2. 遍历每一位玩家的方法则当然是链表更优,便于死亡后的维护.
  3. 距离是逆时针的单向距离
  4. 牌堆空时每次抽取最后一张牌(大概只对#1有影响)
  5. 由于操作多,情况多且很多情况重复出现,本题最适合的写法应是每个功能至少封装到一个函数中,便于后期debug(不会有人能一遍过这道题吧).
    debug部分对于C++来说显然可以巧妙运用预处理指令,便于debug的开关.
    例如我的debug部分开关如下 :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    // Using this system to debug : 
    // The switchs in debugging :
    #define DEBUG // The master switch.
    #ifdef DEBUG // You can close all the switches by closing this switch.
    // Three part switches :
    #define DEBUG1 // Using this to check all the processes while your program is running.It can track every events and states in the whole game.
    // Mainly basic cards.
    #define DEBUG2 // Using this to check ifsomething is wrong in running a big test point.
    // mainly silk bag cards.
    #define DEBUG3 // Using this to check if there is something wrong in the card 'J'.
    // Using the part switches to control your debug sentences.
    #ifdef DEBUG1 // The first part of this problem.
    #define STATE // Using this to print the state once in a round.
    #define PAUSE // Using this to make youe program pause after a round.
    #define GET_CARDS // Using this to make you know when a pig getting some cards.But it can't tell you what does it got.
    #define WHITCH_GOT // Using this to follow the game easily.
    #define AFTER_GOT // Using this to check all zhe cards after a getting. It will cover the switch "WHICH_GOT" .
    #define USE_CARD // Using this to check your program in traversalling all the cards.
    #define DE_BLOOD // Using this to tell you when a pig losses its blood.
    #define DEL_CARD // Using this to make you know when a card is used and then you can guess what is happened or what is wrong.It is a important par in debugging.
    #define DEL_TOT // Using this to make sure if there is something wrong in your delete.
    #define DEAD // Using this to make you know when a pig dies.So you can find if there is something wrong in judging the vectory.
    #define FINAL_PRINT // Using this to check the final state.
    #define STRANGE // Using this to check some strange RE.
    #endif

    #ifdef DEBUG2 // The second part of this problem.
    #define BATTLE // Using this to check if the card 'F' is working properly.Using this to check if your peogram stucks in an endless loop.
    #define DEL_CARD // Using this to make you know when a card is used and then you can guess what is happened or what is wrong.It is a important par in debugging.
    #endif

    #ifdef DEBUG3 // The third part of this roblem.Mainly 'J'.
    #define CAMP // Using this to check if there is some strange camp in the game.
    #define INVU // Using this to give a warning when a juegment of 'J' starts.
    #define NOW_CAMP // Using this to check the progress in a 'J'.
    #endif
    #endif

以上是我对我debug”系统”的声明和解释,通过这个系统我可以便利地选择我要监视的内容,详细地了解程序运行中的所有步骤,并发现程序运行中的问题.可以说没有这个debug,我将几乎不可能做出这道题.

  1. 但是最主要的debug工具是题面,当程序出现问题时你应当首先回顾题面,保证对题面的正确理解.(做这道题的最主要因素是耐心)

Part 1 : 无锦囊牌 :

这是本题中最简单的部分,操作只涉及杀,闪,桃和诸葛连弩
注意事项有 :

  1. 注意跳身份条件,判断清跳身份的判断位置,例如”杀”的使用者一定会亮明身份,而不是在”杀”造成伤害之后.
  2. 找清楚”表敌意”的对象,注意只有主公会主动攻击”类反猪”,可以写一个”if_enemy(int from,int to)”函数来判断,方便修改.(例如我代码中的if_enemy).
  3. 检查每一个循环的开始和终止条件,防止陷入死循环.
  4. 装备”诸葛连弩”后会激活之前的”杀”,(细节1).

至此,你就可以拿到10分了(doge),但是主题代码部分已经基本完成,那么稍加修补,向着更高分迈进:

Part 2 : 有锦囊牌,但是没有无懈可击 :

这是本题中细节较多的一部分.(或许我卡在这里的时间比无懈可击都长因为我是蒟蒻)
注意事项有 :

  1. “决斗”的对象分为以下几种情况 :
    1. 当使用者是反贼时,他一定会对主公决斗,并在此时亮明身份,如果主公死亡,那么游戏立即结束停止他的出牌回合,下同.
    2. 当使用者是忠臣时,他的攻击对象是逆时针方向的第一个反贼,如果反贼死亡且场上没有反贼,那么游戏立即结束,停止他的出牌回合,下同.,如果反贼死亡且游戏未结束,那么击杀者获得三张牌的奖励.
    3. 当使用者是主公是,他的攻击对象是逆时针方向的第一个反贼或者”类反猪”,注意主公若误杀忠臣则弃掉所有手牌(包括装备).
    4. 决斗发起者可能会死亡(doge),此时立即终止出牌(在遍历手牌的循环里加个判断就行).
    5. 决斗发起者一定会亮明身份.
  2. “南蛮入侵”或”万箭齐发”的情况 :
    1. 当使用者下家死亡时,有可能此时使用者新的下家是敌人,那么使用者有可能可以使用手牌中之前的”杀”(细节2)
    2. 这是唯二会出现”类反猪”的部分.
    3. 这两张牌的发起者并不会亮明身份(但很可能会因为主公的猜忌变成类反猪).

由细节1和细节2可知,最简明易行的处理办法就是在自己回合中每次使用除”桃”之外的牌之后重新遍历整个手牌,(我从75 pts -> 100 pts 只添加了这一个东西),还是那句话,数据极小,本题最大的数据可能是#1,其他测试点跑几回合就能结束(便于debug),而且即使#1都到不了10ms.

至此30pts,细节较多,这里只是一部分,其余建议仔细阅读题面.

Part 3 : 有无懈可击 :

这是本题难点与细节所在,也是讨论区询问最多的部分.
注意事项有 :

  1. 无懈可击的使用时间是其他锦囊牌生效之前,而”杀”,”闪”等是其他锦囊牌生效之后的对应措施,所以无懈可击的生效时间应当是刚刚打出这张锦囊牌之后,对于”决斗”进行一次全场的判定,对于”南蛮入侵”和”万箭齐发”应当是在本次判定人回应之前.
  2. 无懈可击的适用对象应当已经表明身份且阵营与当使用无懈可击者相同,否则不会为他使用无懈可击(即使是未表明身份的自己).
  3. 无懈可击也是挑身份的一种途径,使用无懈可击者一定会亮明身份.
  4. 之前没有使用无懈可击的人在有人使用之后也可能会使用,判断时应多扫几圈(数据小),当扫完一圈且无人使用无懈可击时才能退出判断.
  5. 无懈可击对于南蛮入侵和万箭齐发的影响是跳过当前结算者,并未消除这张牌对后续所有人的影响.
  6. 因此一个人可以用无懈可击无懈掉自己的牌.
  7. 无懈可击的判定起点应当是使用锦囊牌的猪(根据题面),但是由于存在多扫几轮的机制,其实判定起点是使用者还是使用者下家应当不会对结果造成本质影响(如果不对就踹我)

至此你大致可以AC这道题了(当然要再注意细节),这道题应该是SDOI2010防AK用的题吧,我并不觉得有人能用省选赛场上的那几个小时敲完这道题并且注意到那么多样例里看不出来的细节.

最后放一下我提交时的代码,其中包含我的整个debug系统,所有的函数声明以及相应的注释(大多数英文来自机翻,不通顺见谅),代码的最后本来有几个样例(但是篇幅问题被我删除了)和我debug的日志(日志还在),记录着我从0分改到100分的经历,本文的很多内容是根据这篇日志回想起来的.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
#include<bits/stdc++.h>
namespace Pozhu{
using namespace std;
#define N 15
#define M 2022
#define RE return 0

// Using this system to debug :
// The switchs in debugging :
#define DEBUG // The master switch.
#ifdef DEBUG // You can close all the switches by closing this switch.
// Three part switches :
#define DEBUG1 // Using this to check all the processes while your program is running.It can track every events and states in the whole game.
// Mainly basic cards.
#define DEBUG2 // Using this to check ifsomething is wrong in running a big test point.
// mainly silk bag cards.
#define DEBUG3 // Using this to check if there is something wrong in the card 'J'.
// Using the part switches to control your debug sentences.
#ifdef DEBUG1 // The first part of this problem.
#define STATE // Using this to print the state once in a round.
#define PAUSE // Using this to make youe program pause after a round.
#define GET_CARDS // Using this to make you know when a pig getting some cards.But it can't tell you what does it got.
#define WHITCH_GOT // Using this to follow the game easily.
#define AFTER_GOT // Using this to check all zhe cards after a getting. It will cover the switch "WHICH_GOT" .
#define USE_CARD // Using this to check your program in traversalling all the cards.
#define DE_BLOOD // Using this to tell you when a pig losses its blood.
#define DEL_CARD // Using this to make you know when a card is used and then you can guess what is happened or what is wrong.It is a important par in debugging.
#define DEL_TOT // Using this to make sure if there is something wrong in your delete.
#define DEAD // Using this to make you know when a pig dies.So you can find if there is something wrong in judging the vectory.
#define FINAL_PRINT // Using this to check the final state.
#define STRANGE // Using this to check some strange RE.
#endif

#ifdef DEBUG2 // The second part of this problem.
#define BATTLE // Using this to check if the card 'F' is working properly.Using this to check if your peogram stucks in an endless loop.
#define DEL_CARD // Using this to make you know when a card is used and then you can guess what is happened or what is wrong.It is a important par in debugging.
#endif

#ifdef DEBUG3 // The third part of this roblem.Mainly 'J'.
#define CAMP // Using this to check if there is some strange camp in the game.
#define INVU // Using this to give a warning when a juegment of 'J' starts.
#define NOW_CAMP // Using this to check the progress in a 'J'.
#endif
#endif

struct Pig{
bool if_dead;
int blood;
int jump; // 0 -> Havn't jumped; 1 -> MP camp; 2-> FP camp; 3 -> Like a FP;
int id; // identity : 1 -> MP camp; 2-> FP camp;

int tot_cards; // The total number of cards.
bool arms; // Brother pig crossbow (Zhuge crossbow)
char cards[M]; // One pig's hand cards.

int last_pig; // The first counterclockwise pig .
int nxt_pig; // The first clockwise pig.
}p[N];

int n,m;
queue < char > cards_leap;
int tot_fp;
int kill_times;
bool used_card;
int invulnerable_from;// Using this to record from who can use the card 'J'.

// Functional index :

char read(); // The input function. It can return the first useful character in input stream.
void init(); // Initialize your program.
void work(); // Mock the game. The main body section of this program.
void print(); // Output the game results.
void de_bug(); // Using this function to output the state.
void dead(int ); // Change a pig's state from alive to dead.
void get_card(int ); // The pig will get a card from the cards_leap.
void kill(int ,int ); // The "from" pig using a kill to the "to" pig.
void check_del_card(); // A useless debug function. Using this to check if there is something wrong in the function "del_card".
void battle(int ,int ); // Two pigs' battle.
void clear_cards(int ); // If MP killed a ZP, MP will lose all its cards.
bool invulnerable(int );
void pig_intrusion(int ); // The implementation of the card 'N' depends on this function.
bool de_blood(int ,int ); // The pig "to" loses its ont point of blood because of the pig "from".
bool if_enemy(int ,int ); // Using this to judge if the pig "from" should show hostility to the pig "to".
int find_card(int ,char ); // Using this to find if the pig "x" has the card "aim". If have, return its position in pig"x"'s cards,else return value 0.
void get_cards(int ,int ); // Using this to make the pig "x" get more than one card in a time.
void del_card(int ,int& ); // The card of ther pig "x" in this position is used.
void use_card(int ,int& ); // Using this to realize the card's function.
void thousands_arrows(int ); // The implementation of the card 'W' depends on this function.
bool invulnerable(int ,int );
bool pig_intrusion(int ,int ); // A step in the function "pig_intrusion(int )". The pig "to" must use a card 'K' ,or lose blood.
bool thousands_arrows(int ,int); // A step in the function "thousands_arrows(int )". The pig "to" must use a card 'D' ,or lose blood.

int main()
{
init();
work();
// check_del_card();
print();
RE;
}

inline char read()
{
char ch = getchar();
while(ch < 'A' || ch > 'Z') ch = getchar();
return ch;
}

inline void init()
{
scanf("%d%d",&n,&m);
char a;
for(int i = 1;i<=n;i++)
{
a = read();
if(a == 'F') p[i].id = 2,tot_fp++;
else p[i].id = 1;
read();
p[i].blood = 4;
p[i].tot_cards = 4;
p[i].last_pig = i - 1;
p[i].nxt_pig = i + 1;
for(int j = 1;j<=4;j++)
p[i].cards[j] = read();
}
p[1].jump = 1;
p[1].last_pig = n;
p[n].nxt_pig = 1;
for(int i = 1;i<=m;i++)
cards_leap.push(read());
}

inline void work()
{
int now = 1;
#ifdef STATE
int x = 0;
#endif
while(!p[1].if_dead && tot_fp)
{
#ifdef STATE
// Using this to print the state once in a round.
if(now == 1) {
cerr << "-------- From now debug -------- " << endl;
x ++;
}
de_bug();
cerr << "Round : " << x << endl;
cerr << "Player : " << now << endl;
#ifdef PAUSE
// Using this to make youe program pause after a round.
if(now == 1)system("pause");
#endif
cerr << "------------ Events ------------" << endl;
// Then others debugging sentences will list the events under here.
#endif
kill_times = 0;
get_cards(now,2);
activation :
used_card = 0;
for(int i = 1;i <= p[now].tot_cards ;i ++)
{
#ifdef STRANGE
cerr << "NXT : " << i << ' ' << p[i].nxt_pig << endl;
#endif
int ori_nxt = p[now].nxt_pig;
if(p[now].if_dead) break;
use_card(now,i);
#ifdef STRANGE
cerr << "Will goto" << endl;
cerr << ori_nxt << endl;
#endif
if(used_card) goto activation;
#ifdef STRANGE
cerr << "After goto" << endl;
#endif
}
now = p[now].nxt_pig;
}
}

inline void get_card(int x)
{
p[x].tot_cards ++;
p[x].cards[p[x].tot_cards] = cards_leap.front();
if(cards_leap.size() > 1) cards_leap.pop();
return;
}

inline void get_cards(int x,int sum)
{
#ifdef GET_CARDS
// Using this to make you know when a pig getting some cards.But it can't tell you what does it got.
cerr << "A pig gets some cards : " << x << ' ' << sum << endl;
#endif
// for(int i = 1;i<=sum;i++)
while(sum--)
get_card(x);
#if (defined AFTER_GOT)
cerr << "All the cards after getting : " << endl;
for(int i = 1;i<=p[x].tot_cards;i++)
cerr << p[x].cards[i] << ' ' ;
cerr << endl;
#elif (defined WHITCH_GOT)
int i = p[x].tot_cards - sum;
for(int j = 1;j<=sum;j++,i--)
cerr << p[x].cards[i] << ' ' ;
cerr << endl;
#endif
return;
}

inline void use_card(int x,int& k)
{
#ifdef USE_CARD
// Using this to check your program in traversalling all the cards.
cerr << "use_card " << x << ' ' << k << endl;
#endif
if(p[x].if_dead) return;
switch(p[x].cards[k])
{
case 'P':{
if(p[x].blood < 4){
del_card(x,k);
p[x].blood++;
}
break;
}

case 'K':{
if(!p[x].arms && kill_times ) break;
if(if_enemy(x,p[x].nxt_pig))
{
kill_times++;
del_card(x,k);
used_card = 1;
kill(x,p[x].nxt_pig);
}
break;
}

case 'D':{
break;
}

case 'F':{
if(p[x].id == 2)
{
invulnerable_from = x;
del_card(x,k);
used_card = 1;
p[x].jump = 2;
if(!invulnerable(1)) battle(x,1);
}
else {
int to = p[x].nxt_pig;
#ifdef BATTLE
// Using this to check if the card 'F' is working properly.
// Using this to check if your peogram stucks in an endless loop.
cerr << "Try to using a battle" << endl;
#endif
if(x == 1)
while(to != x && p[to].jump <= 1) to = p[to].nxt_pig /*, cerr << " 1" <<endl*/;
else
while(to != x && (p[x].id == p[to].jump || p[to].jump == 0)) to = p[to].nxt_pig/*, cerr << " 2" <<endl*/;
if(to == x) break;
#ifdef BATTLE
cerr << "Managed to usin ga battle" << endl;
#endif
invulnerable_from = x;
del_card(x,k);
used_card = 1;
if(x != 1) p[x].jump = 3 - p[to].jump;
if(p[to].jump != 3){if(!invulnerable(p[to].jump)) battle(x,to);}
else battle(x,to);

}

break;
}

case 'Z':{
del_card(x,k);
if(p[x].arms) break;
k++;
p[x].arms = 1;
used_card = 1;

if(if_enemy(x,p[x].nxt_pig))
{
int xx = find_card(x,'K');
while(xx)
{
if(xx <= k) k--;
del_card(x,xx);
kill(x,p[x].nxt_pig);
xx = find_card(x,'K');
}
}
k--;
break;
}

case 'N':{
// cout<<"pig_intrusion"<<endl;
del_card(x,k);
used_card = 1;
pig_intrusion(x);
break;
}

case 'W':{
del_card(x,k);
used_card = 1;
thousands_arrows(x);
break;
}

case 'J':{
break;
}

default:{
break;
}

}
return;
}


inline void kill(int from,int to)
{
if(from != 1) p[from].jump = 3 - p[to].jump;
int i = find_card(to,'D');
if(i)
{
del_card(to,i);
return;
}
de_blood(from,to);
return;
}

inline void battle(int from,int to)
{
#ifdef BATTLE
cerr << "In a battle from : " << from << "to " << to << endl;
#endif
int now = to;
if(from != 1) p[from].jump = 3 - p[to].jump;
if(from == 1 && p[to].id == 1)
{
de_blood(1,to);
#ifdef BATTLE
cerr << "out of the battle" << endl;
#endif
return;
}
while(1)
{
bool flag = 1;
int i = find_card(now,'K');
if(i)
{
del_card(now,i);
flag = 0;
now = now == from ? to : from;
continue;
}
now = now == from ? to : from;
if(flag)
{
de_blood(now,now == from ? to : from);
break;
}
}
#ifdef BATTLE
cerr << "out of the battle" << endl;
#endif
return;
}

inline void pig_intrusion(int from)
{
invulnerable_from = from;
for(int x = p[from].nxt_pig;x!=from;x = p[x].nxt_pig)
if(!pig_intrusion(from,x)) continue;
return;
}

inline bool pig_intrusion(int from,int to)
{
if(p[to].jump && invulnerable(p[to].jump)) return false;
int i = find_card(to,'K');
if(i)
{
del_card(to,i);
return true;
}
if(de_blood(from,to) && (!p[from].jump) && (to == 1))
p[from].jump = 3;
return true;
}

inline void thousands_arrows(int from)
{
invulnerable_from = from;
for(int x = p[from].nxt_pig;x!=from;x = p[x].nxt_pig)
if(!thousands_arrows(from,x)) continue;
return;
}

inline bool thousands_arrows(int from,int to)
{
if(p[to].jump && invulnerable(p[to].jump)) return false;
int i = find_card(to,'D');
if(i)
{
del_card(to,i);
return true;
}
if(de_blood(from,to) && (!p[from].jump) && (to == 1))
p[from].jump = 3;
return true;
}

inline bool invulnerable(int x,int camp)
{
if(p[x].id != camp) return false;
int have = find_card(x,'J');
if(!have) return false;
#if (defined INVU) && (!defined DEL_CARD)
cerr << "The pig : " << x << " use the card 'J' " << endl;
#endif
p[x].jump = camp;
del_card(x,have);
return true;
}

inline bool invulnerable(int camp)
{ //camp -> If you use the invulnerable , you will help the camp.
int original_camp = camp;
#ifdef INVU
cerr << "In invulnerable ! : " << endl;
cerr << "original_camp : " << original_camp << endl;
#endif
while(1)
{
#ifdef CAMP
if(camp != 1 && camp != 2) cerr << "Wrong camp!!!!!!!!!!!!" << endl;
#endif
int now = invulnerable_from;
#ifdef NOW_CAMP
cerr << "now : " << now << " camp : " << camp << endl;
#endif
bool pd_stop = 1;
bool pd = invulnerable(now,camp);
if(pd) camp = 3 - camp,pd_stop = 0;
now = p[now].nxt_pig;
while(now != invulnerable_from){
#ifdef NOW_CAMP
cerr << "now : " << now << " camp : " << camp << endl;
#endif
pd = invulnerable(now,camp);
if(pd) camp = 3 - camp,pd_stop = 0;
now = p[now].nxt_pig;
}
if(pd_stop) {
#ifdef INVU
cerr << "Out of invulnerable" << endl;
#endif
return camp != original_camp ? true : false;
}
}

}


inline bool if_enemy(int from,int to)
{
// (p[p[from].nxt_pig].jump == 3 - p[from].id)
// || (from == 1 && p[p[from].nxt_pig].jump == 3)
int jump = p[to].jump;
if(!jump) return false;
if(from == 1 && jump >= 2) return true;
if(p[from].id == 1 && jump == 2) return true;
if(p[from].id == 2 && jump == 1) return true;
return false;
}

inline bool de_blood(int from,int x) // return true -> x be killed false -> x is alive .But the returned value is useless.
{
#ifdef DE_BLOOD
// Using this to tell you when a pig losses its blood.
cerr << endl;
cerr << "A pig de_blood : " << endl;
cerr << "From : " << from << " To : " << x << endl;
cerr << endl;
#endif
p[x].blood --;
if(!p[x].blood)
{
int i = find_card(x,'P');
if(i)
{
del_card(x,i);
p[x].blood++;
return false;
}
else{
dead(x);
if(p[x].id == 2)
get_cards(from,3);
if(p[x].id == 1 && from == 1)
clear_cards(1);
return true;
}
}
return true;
}

inline void clear_cards(int x)
{
p[x].tot_cards = 0;
memset(p[x].cards,0,sizeof(p[x].cards));
p[x].arms = false;
return;
}

inline void del_card(int x,int& k)
{
#ifdef DEL_CARD
// Using this to make you know when a card is used and then you can guess what is happened or what is wrong.It is a important par in debugging.
cerr << "The pig " << x << " used the card : " << k << ' ' << p[x].cards[k] << endl;
#ifdef DEL_TOT
cerr << "Now cards : " << p[x].tot_cards << endl;
#endif
#endif
for(int i = k;i < p[x].tot_cards;i++)
swap(p[x].cards[i],p[x].cards[i+1]);
p[x].tot_cards--;
k--;
#ifdef DEL_TOT
cerr << "Cards after delete : " << p[x].tot_cards << endl;
#endif
return;
}

inline int find_card(int x,char aim)
{
for(int i = 1;i<=p[x].tot_cards;i++)
if(p[x].cards[i] == aim) return i;
return 0;
}

inline void dead(int x)
{
#ifdef DEAD
// Using this to make you know when a pig dies.So you can find if there is something wrong in judging the vectory.
cerr << "A pig dead : " << x << endl;
#endif
p[x].if_dead = 1;
p[p[x].last_pig].nxt_pig = p[x].nxt_pig;
p[p[x].nxt_pig].last_pig = p[x].last_pig;
if(p[x].id == 2) tot_fp--;
if( (x == 1) || (!tot_fp) ) print(),exit(0);
return;
}

inline void print()
{
if(p[1].if_dead) printf("FP\n");
else printf("MP\n");
for(int i = 1;i<=n;i++)
{
if(p[i].if_dead) {
printf("DEAD\n");
continue;
}
if(p[i].tot_cards == 0){
printf("\n");
continue;
}
cout<<p[i].cards[1];
for(int j = 2;j<=p[i].tot_cards;j++){
cout<<' '<<p[i].cards[j];
}
printf("\n");
}
#ifdef FINAL_PRINT
de_bug();
#endif
}

inline void de_bug()
{
cerr << endl;
// Using this function to output the state.
for(int x = 1;x<=n;x++)
{
if(x > 1)
cerr << "-------- Another player -------- " << endl;
else
cerr << "------- The first player ------- " << endl;
cerr << "P : " << x << endl;
cerr << "blood : " << p[x].blood << endl;
cerr << "id : " << p[x].id << endl;
cerr << "jump : " << p[x].jump << endl;
cerr << "tot_cards : " << p[x].tot_cards << endl;
cerr << "cards : " << endl;
#ifdef STRANGE
cerr << "last : " << p[x].last_pig << endl;
cerr << "nxt : " << p[x].nxt_pig << endl;
#endif
for(int j = 1;j<=p[x].tot_cards;j++)
cerr << p[x].cards[j] << ' ';
cerr << endl;
cerr << endl;
}
cerr << endl;
}

inline void check_del_card()
{
int x = 4;
for(int i = 1;i<=4;i++) {
del_card(1,x);
for(int j = 1;j<=p[1].tot_cards;j++) cout<<p[1].cards[j] << ' ';
cout<<endl;
}
}

}

signed main()
{
return Pozhu :: main();
}
/*
Debug logs :
6.3 : Finished cards and functions without the card 'J'(with no chink in one's armour).
And leaved a lot of problems to save.
0 pts

6.4 : Added the function : if_enemy(int ,int );
0 pts

6.5 : Found out something wrong in judging showing rebellion.
Found out something wrong in using the cards.
Modified the above two problems.
#3 Fall into a endless loop.
Maybe there is something wrong in silk bag cards.
15 pts

6.6 : Found out a '=' -> '-' in using card -> "battle"(The problem above).
20 pts
Found out something wrong in "battle" and dodified it : "break" -> "continue".
Fount a woring point in battle.
25 pts
If you don't close the debug switches , you will TLE!Because too much is output to the standard error output stream.
30 pts
Notes have been added to the program.
Finished the body of card 'J' but it is now right.
Found something wrong after a pig is dead.
Found something wrong in using_card('F')
Fixed the two problems above.
30 pts

6.7 : Found that pig's death can activate the previous card.
Fixed this problem by using "goto activation" .
Fixed something wrong in invulnerable.(About when to start and stop.)
Fixed somehting paradoxically in the camp (invulnerable) .
Foung something wrong in jump to FP because of invulnerable.
Fixed.
60 pts
RE in #1 #2
Found something wrong in activation ("now" -> "i").Fixed.
75 pts
Found something wrong in using the cards.Fixed.
AC 100 pts
The centennial project is over.
*/

全文完

by Pozhu
2022.6.7