程设大做业之魔兽世界

【前言】:在学习了一些看上去只是能让程序更好看更清晰的类的知识以后...为了让咱们真的以为类是个好东西,丧心病狂的做业——魔兽出现了...然而...emmmm...ios

  好吧,这篇博客主要就是记录一下本身在打这些题的一些思路和想法...因为这个题里面其实没有什么算法和数据结构的运用,感受这篇博客成了一个教你们学习怎么样完成做业的blog hhh不过这样也挺好。虽然这么说啦,我会把我以为个人程序里本身以为很漂亮的部分重点讲一下,也能够分享一些面对这样一个比较复杂而冗长的代码怎样更好的提升调试效率的一些小方法。算法

  由于直接让你们作魔兽·终极版会直接让你们放弃,因此老师很机智地设置了几个按部就班的版本数组

【魔兽世界一:备战】数据结构

  笔者认为呢,这个题的目的主要在于:1.营造场景 2.让咱们体会一下面向对象和面向过程之间的关系 3.emmm增长一下你们的信心,方便你们入坑(雾)编辑器

  有N个城市,两个指挥部,红方和蓝方。两个指挥部都会制造武士,双方会各自有一个制造武士的顺序,而且每小时制造一个武士,同时制造武士须要代价,基地会有一个初始的值来消耗,而后若是当前顺序能制造就制造,不能制造了就用顺序的下一个,直到全部的武士都不能制造,再宣称中止。ide

  而后魔兽一出现了:它须要让你按时间输出这些制造的武士。函数

  emm你看我上面的措辞:“输出这些制造的武士”hhh并非“制造这些武士并输出...”工具

  为何会想到不去真的制造武士呢,首先是...懒hhh能少一个类就少一个,其次由于在这个题中的武士是没有任何行为的。输出行为能够放在司令部中输出学习

  因此这题中我只设置了一个司令部的类。而后咱们来思索一下这个类里面须要什么呢?通常能够先想想它进行的行为:ui

【行为】1制造一个武士 2中止制造武士

  那么在制造武士的时候须要知道1.当前司令部的生命元 2.当前要制造的武士是谁 3.当前武士的编号 4.如今的时间 5.这个武士须要多少的生命元 6这个武士有多少了

  这里咱们会发现:4和5 其实在乎义上应该设置成全局变量的,由于好比时间应该是每个函数均可以调用到的,而每一个武士须要用的生命元也是一个客观的给出的条件,也应该是容许全部人调用的。

  那么咱们来考虑1236,其中又会发现3也不用考虑啦,由于编号就是时间+1...而后1咱们能够在基地里设置一个整型的HP。而2的话会发现和顺序和上一次用的是谁有关系,因此须要一个记录顺序的数组Order[],还有一个Index来记录上一个是谁,对于6的话呢,咱们能够用一个桶Count[],每次制造了一个武士who以后就能使用:Count[who]++;

  嗯嗯,这样咱们就解决了这个类的成员了!而后就只有一个问题啦,怎样经过Order[]数组和Index来得知下一个是谁呢?想来有不少方法啦...hhh个人代码就是尽可能短一点,而后好懂啦hhh[这也是写代码很好的习惯啦,hhh好比who,Index这种变量]

1 Index++;
2 int who=Order[Index%5],tmp=0;
3 while(HP<Cost[who] && tmp<5)
4     who=Order[++Index%5],tmp++;

  而后就没有难的地方啦!作完以后能够沾沾自喜了(诶,这貌似是一个贬义词Hhh...无论啦) (果真是诱惑入坑的好题...)

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 
 5 using namespace std;
 6 
 7 int Time_Index; 
 8 int Cost[6];
 9 int ord1[5]={3,4,5,2,1},ord2[5]={4,1,2,3,5};
10 char Warrior_Name[6][7]={"\0","dragon","ninja","iceman","lion","wolf"};
11 
12 class Headquarter{
13 public:
14     int Index;
15     int HP;
16     int Count[6];
17     int Order[5];
18     char Name[5];
19     bool STOP;
20     Headquarter(int HP_,char *s,int *ord){
21         Time_Index=-1;
22         Index=-1;
23         HP=HP_;
24         for(int i=1;i<=5;i++) Count[i]=0;
25         for(int i=0;i<5;i++) Order[i]=ord[i];
26         memset(Name,0,sizeof(Name));
27         strcpy(Name,s);
28         STOP=false;
29     }
30     void Build(){
31         Time_Index++;
32         Index++;
33         if(STOP) return;
34         int who=Order[Index%5],tmp=0;
35         while(HP<Cost[who] && tmp<5)
36             who=Order[++Index%5],tmp++;
37         if(HP>=Cost[who]){
38             HP-=Cost[who];
39             Count[who]++;
40             printf("%03d %s %s %d born with strength %d,%d %s in %s headquarter\n",Time_Index,Name,Warrior_Name[who],Time_Index+1,Cost[who],Count[who],Warrior_Name[who],Name);
41         }
42         else{
43             printf("%03d %s headquarter stops making warriors\n",Time_Index,Name);
44             STOP=true;
45         }
46     }
47 };
48 
49 int main(){
50 #ifndef ONLINE_JUDGE
51     freopen("x.in","r",stdin);
52     freopen("x.out","w",stdout);
53 #endif
54     int Kase,W;
55     char s1[4]="red",s2[5]="blue";
56     scanf("%d",&Kase);
57     for(int T=1;T<=Kase;T++){
58         printf("Case:%d\n",T);
59         scanf("%d",&W);
60         for(int i=1;i<=5;i++)
61             scanf("%d",&Cost[i]);
62         Headquarter r(W,s1,ord1),b(W,s2,ord2);
63         while(!r.STOP || !b.STOP){
64             r.Build();
65             b.Build();
66         }
67     }
68     return 0;
69 }
View Code

 

【魔兽世界二:装备】

  魔兽二是魔兽一的一个增强版,这个里面呢,咱们仍是要制造和输出武士的信息,可是这个题目中最重要的就是出现了装备!

  哇,简直是一个新世界啦...由于这样的话,咱们就有新的对象须要出现了!

  在以前的魔兽世界一,武士这个类实际上是没有什么用的,他们只要提供名字和编号就能够了。可是在魔兽世界二里若是咱们接着这样作的话,就会有些麻烦咯,由于须要给武士们发武器了,那么这样就一下诞生了两个对象:武器和武士...

  [固然啦这个题里其实武器也是没有任何做用的,更容易的打法能够删掉武器这个类哦...不过笔者感受要开始为魔兽三作点准备了就写了这个类]

  咱们注意到在魔兽一里武士们是没有任何区别的,只有HP值和Name的不一样。

  可是在这一题中:咱们发现这些武士们开始偷偷分化了!而后就会有不少细节啦,有时候半句话就是一个小细节。

  [这种题最容易错的就是细节,笔者有一个好方法:就是你能够先大概建好整个程序,而后一行一行地去看题目的描述,每看一句就去噼里啪啦敲好QwQ,这样就不会漏掉细节了哦...emmm固然!也能够画图或者画表来让题目中的信息更加的清晰]

   嗯嗯这个题中由于各类武士的不同,因此就能够开始感觉虚函数的好处啦。

  虚函数和多态在笔者看来是一个很实用的东西,它实际上是相似 If 的一个函数,一样的一句话,if 这个函数的主体是x就执行 x 里写的函数,if 是 y 来作就执行 y 里写的函数。可是这个却不是在编译中写好的 if 而是执行的时候才去执行,这样就让代码看上去逻辑感很好,并且也很简洁啦!

  而后笔者以为逻辑这种东西,在写一个比较长比较复杂的程序的时候是很是重要的,在保证必定的可读性(这个须要变量名取得好哦...多用'_'或者首字母大写来给变量名命名会很好)的状况下,若是你的程序逻辑清楚的话,是很容易找到错误的。

  因此我在用virtual的时候通常是先去思考一个通常武士的行动,而后思考是否是有特例的武士不会这么作,那么就设置成virtual,好比看着题目的输出样例,你就能够很清楚的知道有:出生->获得武器->输出本身状况 这样三个广泛的行动,可是每个部分都是有特例的,好比出生的时候有人会得到士气和忠诚这样的属性。获得武器的时候有人会获得两把,输出本身时有的人没有武器要输出....[p.s.]不过出生的时候不同,写在构造函数里不同就好啦,这个就不能virtual了

  而后这个题也就没有困难啦...

【魔兽二:代码】

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<iostream>
  5 
  6 using namespace std;
  7 
  8 int Cost[5],Time_Index;
  9 int ord1[5]={2,3,4,1,0},ord2[5]={3,0,1,2,4};
 10 char Weapon_Name[3][6]={"sword","bomb","arrow"};
 11 char Warrior_Name[5][7]={"dragon","ninja","iceman","lion","wolf"};
 12 char Headquarter_Name[2][5]={"red","blue"};
 13 
 14 class Weapon{
 15     char Name[6];
 16 public:
 17     Weapon(int which){
 18         strcpy(Name,Weapon_Name[which]);
 19     }
 20     void print(){printf("It has a %s",Name);}
 21     void Name_print(){printf("%s",Name);}
 22 };
 23 
 24 class Warrior{
 25 protected:
 26     int HP;
 27     char Name[7];
 28     Weapon *w1,*w2;
 29 public:
 30     Warrior(int HP_,char *s){
 31         memset(Name,0,sizeof(Name));
 32         HP=HP_;
 33         strcpy(Name,s);
 34         w1=w2=NULL;
 35     }
 36     virtual void get_weapon(){
 37         w1=new Weapon((Time_Index+1)%3);
 38     }
 39     void Name_print(){
 40         printf("%s",Name);
 41     }
 42     virtual void Weapon_print(){
 43         w1->print();
 44         printf("\n");
 45     }
 46     ~Warrior(){if(w1) delete w1;if(w2) delete w2;}
 47 };
 48 //0
 49 class Dragon:public Warrior{
 50     double morale;
 51 public:
 52     Dragon(int HP,double m_):Warrior(HP,Warrior_Name[0]){morale=m_;}
 53     virtual void Weapon_print(){
 54         w1->print();
 55         printf(",and it's morale is %.2lf\n",morale);
 56     }
 57 };
 58 //1
 59 class Ninja:public Warrior{
 60 public:
 61     Ninja(int HP):Warrior(HP,Warrior_Name[1]){}
 62     virtual void get_weapon(){
 63         w1=new Weapon((Time_Index+1)%3);
 64         w2=new Weapon((Time_Index+2)%3);
 65     }
 66     virtual void Weapon_print(){
 67         w1->print();
 68         printf(" and a ");
 69         w2->Name_print();
 70         putchar('\n');
 71     }
 72 };
 73 //2
 74 class Iceman:public Warrior{
 75 public:
 76     Iceman(int HP):Warrior(HP,Warrior_Name[2]){}
 77 };
 78 //3
 79 class Lion:public Warrior{
 80     int loyalty;
 81 public:
 82     Lion(int HP,int l_):Warrior(HP,Warrior_Name[3]){loyalty=l_;}
 83     virtual void get_weapon(){}
 84     virtual void Weapon_print(){
 85         printf("It's loyalty is %d\n",loyalty);
 86     }
 87 };
 88 //4
 89 class Wolf:public Warrior{
 90 public:
 91     Wolf(int HP):Warrior(HP,Warrior_Name[4]){}
 92     virtual void get_weapon(){};
 93     virtual void Weapon_print(){};
 94 };
 95 
 96 class Headquarter{
 97 private:
 98     char Name[5];
 99     int HP;
100     int Order[5];
101     int Count[5];
102     int Warrior_Index;
103     Warrior *cur;
104     bool STOP;
105 public:
106     Headquarter(char *s,int HP_,int* O_){
107         memset(Name,0,sizeof(Name));
108         memset(Count,0,sizeof(Count));
109         strcpy(Name,s);
110         HP=HP_;
111         for(int i=0;i<5;i++)
112             Order[i]=O_[i];
113         Warrior_Index=-1;
114         cur=NULL;
115         STOP=0;
116     }
117     void Change_HP(int HP_){
118         HP=HP_;
119         memset(Count,0,sizeof(Count));
120         Warrior_Index=-1;
121         cur=NULL;
122         STOP=0;
123     };
124     void Build_Warrior(){
125         if(STOP) return;
126         Warrior_Index=(Warrior_Index+1)%5;
127         int who=Order[Warrior_Index];
128         int temp=0;
129         while(Cost[who]>HP && temp<5){
130             Warrior_Index=(Warrior_Index+1)%5;
131             who=Order[Warrior_Index];
132             temp++;
133         }
134         if(HP>=Cost[who]){
135             Count[who]++;
136             HP-=Cost[who];
137             switch(who){
138                 case 0: cur=new Dragon(Cost[0],(double)HP/Cost[0]);break;
139                 case 1: cur=new Ninja(Cost[1]);break;
140                 case 2: cur=new Iceman(Cost[2]);break;
141                 case 3: cur=new Lion(Cost[3],HP);break;
142                 case 4: cur=new    Wolf(Cost[4]);break;
143             };
144             cur->get_weapon();
145             printf("%03d %s ",Time_Index,Name);
146             cur->Name_print();
147             printf(" %d born with strength %d,%d ",Time_Index+1,Cost[who],Count[who]);
148             cur->Name_print();
149             printf(" in %s headquarter\n",Name);
150             cur->Weapon_print();
151             delete cur;
152             cur=NULL;
153         }
154         else{
155             printf("%03d %s headquarter stops making warriors\n",Time_Index,Name);
156             STOP=true;
157         }
158     }
159     bool Stop(){return STOP;}
160 };
161 
162 Headquarter r(Headquarter_Name[0],0,ord1),b(Headquarter_Name[1],0,ord2);
163 
164 int main(){
165 #ifndef ONLINE_JUDGE
166     freopen("x.in","r",stdin);
167     freopen("x.out","w",stdout);
168 #endif
169     int Kase,W;
170     scanf("%d",&Kase);
171     for(int T=1;T<=Kase;T++){
172         printf("Case:%d\n",T);
173         scanf("%d",&W);
174         Time_Index=0;
175         r.Change_HP(W);
176         b.Change_HP(W);
177         for(int i=0;i<5;i++)
178             scanf("%d",&Cost[i]);
179         while(!r.Stop() || !b.Stop()){
180             r.Build_Warrior();
181             b.Build_Warrior();
182             Time_Index++;
183         }
184     }
185     return 0;
186 }
View Code

 

【魔兽世界三:开战】

  这个版本里面的魔兽世界呢...

  很重要的两个任务就是让你的武士们能够移动起来,而后两个武士之间会发生互动(打架、抢武器什么的)

  下面就详细讲一下啦...

  先讲一讲关于武士的移动!

【武士的移动】

  这里的移动涉及到的主要是武士和城市这两个单位。

  而这里不一样于以前两道魔兽的地方是:我不只要输出每个移动,而且在我程序构建出来的这个世界中,武士是真的在移动的。

  那么咱们仍是先考虑这个部分的输出:

  由于城市是分普通城市和指挥部的,因此对应的输出也是有两种

  先看看普通城市的输出:(这些都是从提供数据中的out文件里提出来的哦...)

000:10 red iceman 1 marched to city 1 with 117 elements and force 50

  再看到达指挥部的输出:

012:10 red wolf 3 reached blue headquarter with 5 elements and force 150

012:10 blue headquarter was taken

  注意到两种的区别!首先蓝色指挥部的名字"blue headquarter"取代了"city %d",其次,在魔兽世界三中,只要有武士到达对方指挥部,对方的指挥部就会被占领,游戏也就结束,此时就须要咱们输出一行"blue headquarter was taken"

  【Tips1】这里有一个很容易错的地方,那就是当前Case结束输出的时机!若是最后游戏是平局,那么应该是在时间结束的时候也结束输出的。可是若是中途发生了指挥部被占领的状况就应该结束啦,也就是这个时刻以后的都不用输出啦...!而在这个地方还有一个要注意:虽然在司令部被占领以后游戏结束,可是这个时刻的输出仍是要输出完的,好比说红司令部被占领了,可是这个时刻我才刚刚枚举了移动到第0个城市的武士,但是还有不少武士也在这个时刻移动,应该把他们都输出完了才能结束这个Case的输出!

  【Tips2】这里提到一个打程序的小技巧:为了让咱们的代码不会出错,个人建议是在要输出的地方,先写一个print("");而后把题目中提供的要输出的信息填进去。而后,再把题目中提到的特殊的信息给挖空拿掉,再在printf的后面想办法把这些用一些方法给表示出来。这样的话错误率会降到很低很低哦...

  好比说对于一个普通城市的输出,个人代码呢就长这样了...

printf("%03d:10 %s %s %d marched to city %d with %d elements and force %d\n",Time_Index,Headquarter_Name[Direction<0],Name,Born_Number,City_Index,HP,MP);

  hhh不过我一直觉得你们都是这么打的...tips强行凑字数hhh

  而后咱们再来考虑一下有多个武士,最后输出这些移动信息的顺序:

  大的方向呢是从0到n+1的城市方向,而且在同一座城市会先输出红色武士的信息,再输出蓝色武士的信息。【Attention】注意啦!这里的城市是指双方武士移动后所在的城市!而咱们一般会把移动武士和输出武士一块写,那么这个时候请注意啦...对于第 i 城市的输出就要移动的是 i-1 城市的红方武士和 i+1 城市的蓝方武士,具体以下(笔者de出来的第一个bug就是这里写错了QwQ)...

  下面是笔者的代码:嗯里面的City是一个Warrior类的指针的二维数组,第一维的下标是这个城市的编号,而第二维的[0]或[1]分别存的是red和blue方的武士指针。[emmm大家可能以为笔者你....你竟然不把City写成类!好吧...我就是懒hhh由于这题中的City好像没有什么用]

for(int i=0;i<=City_Amount+1;i++){
  if(i>0)
    if(City[i-1][0]!=NULL) City[i-1][0]->Process(); if(i<=City_Amount) if(City[i+1][1]!=NULL) City[i+1][1]->Process();
}

  看完上面这个代码,不少人就放松了警戒(包括当初的笔者我本身...)感受很满意呀...代码思路这么清楚了,能够安心写process去了。这时一个帅气的男生停在了你的面前:STOP!(咳咳,就是笔者我...hhhh)这样打会有一个问题,那就是当我移动个人红色方的武士的时候,他确定会到下一个城市 (由于这里尚未开始打架...) 那么,当我枚举下一个城市里的红色战士的时候,发现:诶,你不是从上个城市过来的么?我原来那个武士呢?算了算了就移动你把...而后不知不觉一轮枚举直接把我红方的武士送进了对面的指挥部...

  唔,那怎么解决呢?笔者的办法是创建一个新城市,让移动后的武士先住在新城市里,等旧城市的全部武士都走完了,再让新城市里的人回来...具体过程呢能够见最后的代码啦...。

  好了,如今终于安心了,能够开始写咱们的Process函数了。

  首先咱们注意到题目中对移动这个操做有三种人:Iceman(边走边掉血),Lion(越走越胆小),Others。

  那么这个Process确定就是一个虚函数了,那咱们分别看一下这三种人。先是Others。

【Others】 我走路走的好好的!

  不过好好的走须要什么呢?

  须要的信息1.我当前的位置 2.我往哪边走,那么这两个信息能够变成两个值在初始化的时候搞定!

  1.int City_Index 表示本身的位置 red初始值是0 ,blue 是 N+1

  2.int Direction 表示本身的方向 red用1 blue用-1

  这样设计的话 City_Index+=Direction; 就让这个武士走完了诶!

  不行不行,你还得照顾一下那些在City里找武士的人呀...因此咱们还得修改外层指向这个武士的指针:

City[City_Index][Direction<0]=NULL;
City_Index+=Direction;
New_City[City_Index][Direction<0]=this;

  这里不少小伙伴就不知道Direction<0是什么了...hhh突然感受本身是科普小天使....

  好比< > ==这种符号都是双目的运算符,它们也是有返回值的,是一个bool类型!若是正确呢那就是1,不正确呢那就是0

  因此若是我把red定为0,blue定为1的话Direction<0就能够知道这个武士是哪一家的了!

  而后上面代码的New_City就是我所设想的新城市啦...

  好了,如今咱们移动了武士本身,还改了城市里的指针,是否是结束啦!嗯嗯,别忘了加上以前的输出哦

 1     virtual void Process(){
 2         City[City_Index][Direction<0]=NULL;
 3         City_Index+=Direction;
 4         New_City[City_Index][Direction<0]=this;
 5         if(City_Index==0){
 6             Red_Lost=true;
 7             printf("%03d:10 blue %s %d reached red headquarter with %d elements and force %d\n",Time_Index,Name,Born_Number,HP,MP);
 8             printf("%03d:10 red headquarter was taken\n",Time_Index);
 9         }
10         else if(City_Index==City_Amount+1){
11             Blue_Lost=true;
12             printf("%03d:10 red %s %d reached blue headquarter with %d elements and force %d\n",Time_Index,Name,Born_Number,HP,MP);
13             printf("%03d:10 blue headquarter was taken\n",Time_Index);
14         }
15         else
16             printf("%03d:10 %s %s %d marched to city %d with %d elements and force %d\n",Time_Index,Headquarter_Name[Direction<0],Name,Born_Number,City_Index,HP,MP);
17     }

  不要看代码这么长,其实主要是输出有点长啦....QwQ,最重要的只有三行而已啦...

  好了,下面讨论一下Iceman

【Iceman】我前进就要掉血!但我仍是要前进!

  就记得移动的时候HP-=HP/10哦...注意啦这个掉血是当前血量的10%,因此不用担忧Iceman行军路上失血过多而死hhh

而后是咱们的Lion

【Lion】我不想走啦!再逼我我就逃跑!

  嗯嗯记得就是把Loyalty-=K就好啦,而后要补一个判断,看看Loyalty是否是<0啦...

  嗯嗯这个里面的话呢个人处理就是逃兵一概杀掉emmm直接让这个逃跑的被上层delete掉就好啦

【武士的战斗】

  武士战斗最重要的两个信息:武士、武器

  而这两个就分别是程序中最重要的两个类。

  这一题中的武器数目从最多2很快提高到了10,同时武器的属于关系也再也不固定,而是能够在不一样的武士之间传递。而对于这样的关系,我认为指针是最好的选择了。由于武器的对象在传递的时候实际上是不会消失的,因此当一个武器从A到B手上时,只用把B中一个空的指针变成A的指针,而后A中指向这个武器的指针定为空就完成了一次武器的交接。(不过笔者还打听到一种比较巧妙的方法哦:这个题里能够不要武器类的,由于武器这个对象其实没有具体的什么值,它的攻击是主人根据主人来的,它惟一具备本身的属性就是耐久度了,而这个咱们用一个数组来当成武器库存耐久度也不是很麻烦,并且这样的话其实传递武器排序武器都是很简单的了...不过笔者仍是讲本身的类的作法吧)

1 class Warrior{
2     int Weapon_Count;//Weapon_Count表示武器的数量
3     Weapon* w[10];  
4 };

  上面解决了武士和武器之间的关系,咱们在这个基础上再来看看打斗中的各类操做应该如何实现

  仍是根据故事的逻辑来看,把战斗按照时间顺序分为战前、战中、和战后三个阶段:(p.s.固然战斗发生的条件是这个城市里有两个武士哈)

 

【战前】

  战前有一件对战斗很重要的事情:那就是wolf会抢夺武器!

  逻辑上:这是一件很独特的事情,能够用virtual Before_Fight()来处理,也能够if (Is_Wolf()) Rob_Weapon(Enermy)来处理

  操做上:在抢夺以前:要知道抢夺发生的条件:

  1,对方不是wolf,这样须要一个判断函数:virtual bool Is_Wolf();而后只有wolf类返回true其余都返回false就能够了

  2.本身的武器数量<10 3.对方的武器数量>0,知道本身能够抢夺以后,还不能立刻抢,这中间还有一个很重要的操做:你要抢编号最小的那一类武器,并且若是抢不完要优先抢使用次数少的。这样的话咱们就要给敌人的武器按照刚才的方法排序,笔者的习惯是用系统函数sort()搭配本身写的cmp来排序,能够把本身的cmp函数发上来供你们参考:

bool cmp(const Weapon *A,const Weapon *B){//这里咱们是想给Warrior中的Weapon *w[]数组排序,因此应该比较两个Weapon*的大小 if(A==NULL) return false;//咱们要让NULL的元素都日后放,而sort中return true;就会把A放在前面,因此这里应该返回false if(B==NULL) return true; if(A->Index!=B->Index) return A->Index<B->Index;//Index是武器的种类的编号(Sword-0,Bomb-1,Arrow-2),编号小的在前面,能够看到这里仍是很好的运用了<的返回值来使得代码精简(若是A的编号<B那么就会return true让A在前面) return A->Can_use>B->Can_use;//Can_use是武器的耐久度,初始值是2,bomb每使用一次会-2,Arrow使用一次会-1,耐久度大的放前面,因此是>号 }

  [ 在上面的cmp函数中,我顺带介绍了本身关于Can_use的这个设计...嗯嗯感受我这样挺漂亮的算,一个好设计hhh,而后同时也科普了一下cmp函数的写法:return true会让A放在B的前面,而后运用<和>号可让本身的代码很精简。]

  而后就是抢夺的过程了,这个就是武器从属权的一个传递,在上面的指针部分也有介绍。若是还有不懂能够看下面的抢夺代码

 1 virtual void Before_fight(Warrior *Enermy){
 2     if(Enermy->Is_Wolf()) return;
 3     if(Weapon_Count<10 && Enermy->Weapon_Count>0){
 4         sort(w,w+10,cmp);
 5         sort(Enermy->w,Enermy->w+10,cmp);
 6         int Min_Index=Enermy->w[0]->Index,Amount=0;
 7         for(int i=0;Enermy->w[i]!=NULL && Enermy->w[i]->Index==Min_Index && Weapon_Count<10 && i<Enermy->Weapon_Count+Amount;i++){
 8             w[Weapon_Count++]=Enermy->w[i],Amount++;
 9             Enermy->Weapon_Count--;
10             Enermy->w[i]=NULL;
11         }
12         printf("%03d:35 %s wolf %d took %d %s from %s %s %d in city %d\n",Time_Index,Headquarter_Name[Direction<0],Born_Number,Amount,Weapon_Name[Min_Index],Headquarter_Name[Direction>0],Enermy->Name,Enermy->Born_Number,City_Index);
13     }
14 }
View Code

 

【战中】

  战斗的过程是两我的互相使用武器的过程。

  首先,仍是须要先给两我的的武器排好序来肯定使用的顺序,而后就相似魔兽世界一二中生产武士的方法来循环这个武器的顺序:

1 int temp=0;
2 while(w[Weapon_Index=(Weapon_Index+1)%10]==NULL && temp<10) temp++;

  上面的代码就是帮助我找到下一个能够用的武器(够精简吧hhh),而后就是使用武器的过程了,这里武器的使用,只和使用者、被使用者、武器类型有关,而与具体的武器对象惟一的关联就是耐久度这个属性(因此才会诞生出不设置武器类的作法),那么咱们在使用武器的时候就须要把这些因素都考虑进去,同时不一样类型的武器是不同的,因此咱们须要用到虚函数来处理。在这个过程当中是可能致使武士死亡的,可是咱们如今不能急着把武士给delete掉,由于整个武士的最顶级指针是最上层的City数组,并且等一会还有敌人来收缴武器,因此咱们能够用一个bool Die来表示一个武士是否死亡,而后延迟delete的时间,在打斗的时候不delete,等战斗发生完了之后回到上层再去删除。

  而后用完了武器就会面临武器可能失效的问题,这个时候要删除这个武器,由于武器的最上层控制者就是武士,因此这个delete的操做也应该是放在武士的函数里执行的。同时记得w[i]=NULLWeapon_Count--的操做。

  战中还有一个很重要的过程就是宣布战中结束,进入战后。有两种状况是很容易判断的:1. 有一方死亡时 2. 双方都没有兵器时

  还有一种状况是比较复杂的,那就是双方的攻击力<5(这时使用Sword将会形成0伤害),而后互相打到地老天荒,这个时候怎么办呢?

  室友想到一种很偷懒的方法,就是执行完1000轮还不结束,我就宣告平局...emmm显然能够造数据卡掉你嘛,,不过最后数据确实没有卡(由于如今尚未看到任何一个TLE的同窗...)hhh怀疑那些运行比我(2ms)慢的(24ms)可能就是用了这种方法?

  个人办法会比较符合逻辑一点,就是我会有一个倒计时Time_Tick,它的初始值是两人的武器数量中大的一个的两倍,那么当倒计时执行完以后,即便是武器数量大的那我的也只可能有sword这件武器了,就进入了白热化阶段,而后你再判断一下双方的攻击力,或者判断一下场面是否是还有变化,这样就能够结束了。

【战后】

  战后首先会有一个叫Dragon的兄弟,若是没死他就会yell一下,记得输出。

  而后战后主要就是死亡以后的收缴兵器。由于兵器的最高控制者就是武士,因此写在武士的函数里(这里提到了不少次最高控制者,由于笔者程序中的指针每每表示的是控制关系,因此每当我想删除一个东西的时候,就须要去考虑谁的指针仍是指着它的,那么我会让这个删除操做发生在哪一个指挥者的函数中)

  而收缴兵器的过程和wolf抢兵器的过程是几乎同样的,只是不仅能够抢一类武器了,去掉那个终止条件就能够了。

那么战斗也就分析完了...

最后来看看怎么让你的程序能够AC吧:

【关于如何从CE->WA】

  啊,这个过程能够说是很痛苦了...不过相信大家能够的hhh

【最后:关于怎样调试代码(WA/RE/TLE->AC)】

  首先呢,笔者本身对这道题大概debug了两天左右...其实感受本身debug已经颇有方法了,只是前面写代码的时候好像太粗糙了

  [其中的情绪变化大约是:[冷静] 这里有错诶?-> [急躁] 怎么还有错?!-> [抓狂] 还有哪有错呀?-> [目光呆滞] 没错了....吧...]

  因此,你们本身敲第一遍代码的时候必定要谨慎!当心!要跟着本身的光标一块儿思考这个位置应该是什么,这样打是否是必定对?

  这个过程必定要谨慎哦...为了你们调试代码的愉悦度!

调试的过程:

 

【关于调试工具】

  emmm 笔者用的是gdb这种原始又实用的东西 hhh而后你们就各自用本身的IDE好了!

  首先你们须要知道基本的【文件操做】来让本身的程序能够读一个比较大的输入文件,也能把输出的东西存到一个文件里面去

1 #ifndef ONLINE_JUDGE
2     freopen("data.in","r",stdin);
3     freopen("my_code.out","w",stdout);
4 #endif

  只要把这个东西加在int main的后面就能够啦(前面须要包含<cstdio>库),其中二、3行是正式的代码啦,而后一、4行可让你的程序在本身本机运行的时候用二、3里面的语句,可是交到openjudge上的时候又不会调用里面的语句,是否是很厉害呢hhhh

  而后你们既然都输出到文件里面了,那就固然也要知道一种能够比较文件是否相同的办法!由于要肉眼比较输出有一点麻烦...【不过我就是这么作的】,若是你要这么作的话,请选一个好看的文本编辑器hhh:肉眼比较一次能够比较一版,就是将两个out调整到相同的位置(这个调整到相同位置也是颇有技巧的,你要灵活的使用鼠标和光标来调整位置hhh),而后反复切换,在来回切换的时候不一样点会很明显,这样你就能够找到了!

  而后言归正传仍是讲一讲【怎么比较文件】

  首先是Linux最熟悉啦:在当前位置打开终端,而后输入:diff -c my_code.out std.out 就能够比较了(其中-c是能够帮你输出错误行号的,感受一看就明白啦...而后my_code.out是本身的输出结果,std是正确的结果  [这个正是我用的hhh])

  而后是Windows下:先敲一下cmd调出命令行,而后cd 后面加你文件存的位置,这个位置怎么找呢?就是你能够打开你文件所在的文件夹,而后单击一下,而后cd + 这个蓝色的东西...+回车 (我真是科普小天使呀hhh)

  而后你就进入到了当前文件夹,而后输入命令:fc my_code.out std.out+回车就能够啦...而后这个不一样可能不少,致使控制台装不下..[hhh我就常常发生这种状况]

  咱们能够fc my_code.out std.out > Difference.txt 这样就能够把比较信息输出到这个txt里面去了,上面Linux也是同样的哦

  而后是根据读者范围友情添加的Mac大神应该怎样作呢?

  Hhh我也不知道啦...不过下面这个博客提供了两种文件比较的工具,能够看一下啦 :https://blog.csdn.net/wowfly98/article/details/52774275

 

【关于数据】

  想要调试好,你须要得到一些比较优秀的数据,course上提供的数据就挺棒的(由于过了那个就能A啦!hhh)

  不过呢course上的数据是多组的,为了方便调试,咱们能够一组一组的拆开来试【by the way 不知道blog怎么上传文件QwQ那就你们本身来吧...hhh个人经验是第一二组数据是很好的数据,后面的九十也都是比较强的,而后中间有一些是很短的数据,价值不高】

  而后对于一组数据咱们也是能够拆的!至于为何要拆呢?请听下面的笔者哭诉节目:

  笔者当时常常会遇到RE。RE是一种比WA更难受的东西,它有时是很良心的:会告诉你卡在哪一行了...有时不会告诉你,它就是卡住了!(太傲娇了吧)

  RE在这种涉及到一堆指针的题目里面是十分常见的,觉得你只要delete了一个空的地址就会报错,而后访问了一个空指针的内容也会RE,因此delete以后必定记得把指针赋值为NULL!记得要访问以前判断是否是NULL!

  而后这里涉及到的指针主要是City和New_City的Warrior指针,还有就是Warrior里面放Weapon的w[]指针数组。City要记得每一个Case以后要清空一下,顺带把指向的战士消除掉,而后w[]数组是很容易出错的一个地方!由于中途我会有武器损耗、武器被抢等等均可能将w[i]中间某一个位置给挖空!这样的话w[]中有指向的范围就不是连续的了!Weapon_Count也只能给你计数了,因此每次我想要一块连续的武器存储必定要记得排序,并且排序的范围必定是[0,10)哦(笔者有n次RE都是这个缘由,由于须要用Weapon的地方太多了,改的时候记得一块儿改完)

  不过也不必定都是这种状况的RE,对于RE咱们有传统方案就是设置断点,在这种时间不少的题中的断点通常长这样:

1 if(Time_Index==7)
2     printf("Stop\n");

  经过不停地修改Index后面的数值就能够知道在哪一个时间段里RE啦,而后再单独进入里面调试。

  固然啦,这个题有一个得天独厚的优点:就是输入数据中是有时间的,因此你只要修改后面的时间也能够打到经过设置断点找到RE的时间点的过程,同时你也能够经过修改时间找到一个里RE比较近的能够运行的时间去观察输出数据中关于时间的输出来方便本身设置断点来检查RE。

  而后关于RE的状况在上面已经讲得比较丰富了...

下面来说讲WA的调试方法。

  魔兽三这样的题实际上是很容易找到WA的问题的,由于咱们是面向对象的程序,并且咱们的输出必定是有一个对象的,那么你在哪个位置WA了,必定是针对某一个对象的储存值出现了问题,而咱们是能够在这个WA的地方以前找到关于这个对象全部的报告的,方法就是control+F而后输入你想找的对象名字 [这个时候又须要你有一个优秀的文本编辑器啦hhh]好比个人界面是这样子的:

 

  好比说打架的结果不一样了,我就去看一下前面汇报的两我的的血量生命值仍是有武器数量什么的...而后就能够手上模拟看看程序在哪儿出问题啦..

  总而言之WA虽然可能的诱因无穷无尽,可是相对于RE也是更容易找到并且找的过程更加的有趣的hhh,固然关于WA的诱因,最重要的一部分就是题里面的细节

  那我就列举一些我印象深入的害人的细节吧:

  1.题面描述里:这里在40分钟和50分钟之间混入了一个10分钟输出...但事实上最后输出是须要在10分的时刻输出的(详细见上面描述行军的部分)

  2.Dragon没有战死就会欢呼

  3.Ninja使用炸弹本身不会掉血

  4.使用炸弹可能把本身炸死而敌人不死,这时候敌人也会收缴你的武器

  5.当指挥部被占领后游戏结束,可是仍是要输出这个时刻全部武士的移动报告

  6.Wolf不会抢Wolf的武器;Wolf只会抢一种武器;若是武器是用cnt[3]存的话,Wolf要当心一块儿抢光使得本身的武器多于10把的状况。

  若是是和笔者同样用的数组存储武器的话,要注意下面这个程序段中的for循环中的终止条件应该写成:i<Enermy->Weapon_Count+Amount

  而不能写成i<Enermy->Weapon_Count,由于每当我抢一件武器,个人Weapon_Count都会-1,可是我抢的武器确实从头抢起的,因此若是我写成了<Weapon_Count的话就会使得最后几件武器抢不到了,因此这个终止条件应该是抢武器以前的武器数量,也就是Weapon_Count+Amount了。

1 sort(w,w+10,cmp);
2 sort(Enermy->w,Enermy->w+10,cmp);
3 int Min_Index=Enermy->w[0]->Index,Amount=0;
4 for(int i=0;Enermy->w[i]!=NULL && Enermy->w[i]->Index==Min_Index && Weapon_Count<10 && i<Enermy->Weapon_Count+Amount;i++){
5     w[Weapon_Count++]=Enermy->w[i],Amount++;
6     Enermy->Weapon_Count--;
7     Enermy->w[i]=NULL;
8 }

  7.输入的时间的单位是分钟;若是双方司令部都中止生产了而时间尚未到,也得接着输出(不一样于魔兽一二)

  8.这个题中的指挥部生产士兵,若是下一个不能生产了就不会再生产,而不须要去找下一个能产的(不一样于一二)

  9.这个题中也会分发武器,可是不须要输出分发武器的信息;这一题中Lion出生也会发兵器(不一样于魔兽二)。

  10.使用swith case的时候必定记得break!

  [上面都是笔者的痛苦教训,但愿大家能够省些力气哦...]

 【魔兽世界三:代码】

[Please Do Not Copy! Thanks!] 
相关文章
相关标签/搜索
本站公众号
   欢迎关注本站公众号,获取更多信息