POJ2729 Robocode(离散化与模拟-----提醒曾经爱玩游戏的自己没做出这个

题目链接 :http://poj.org/problem?id=2729

题目很长,有不少也是废话。类似小时候玩的坦克大战。每个坦克速度为10,炮弹速度为20.子弹出界就消失,坦克出不了界限。相向的子弹碰撞不会消失(区别与小时候的游戏,炮弹可以抵消)。 

坦克可以90转向...不少条件题目中仔细读可以知道。

在这里需要注意的是,由于炮弹速度和坦克移动的速度不一致,导致对于一个时间单位,坦克与子弹在坐标上的处理挺困难。因为如果子弹在最左小角,向右边发射,坦克刚好在子弹右边一个单位,而坦克正好向左边运动,那么它们的碰撞点将会在一个距离单位的中间偏右2/3处,碰撞时间为1/3个单位时间;还有。如果坦克不动,则碰撞时间为1/2;因此我们取二者最大公约数1/6为时间单位。这样处理适合碰撞时间和地点。

因此,120的长度将扩大为720,相当于原来的每一格变成了6小格。坦克每6个时间单位走6格,即原来的一个时间单位走一格。

  1 #include <iostream>
  2 #include <fstream>
  3 #include <string>
  4 #include <vector>
  5 using namespace std;
  6 
  7 struct Spirit // 坦克和子弹都从这个类派生
  8 {
  9     int x, y; // 位置
 10     int face; // 前进方向
 11 };
 12 struct Bullet : public Spirit // 子弹类
 13 {
 14 
 15 };
 16 struct Tank : public Spirit // 坦克类
 17 {
 18     string name; // 坦克名称
 19     bool move; // 标记坦克是移动还是静止
 20     Bullet CreateBullet(); // 坦克发射一枚子弹
 21 };
 22 Bullet Tank::CreateBullet() // 坦克发射一枚子弹,刚发射的时候子弹的位置和前进方向和坦克是一样的
 23 {
 24     Bullet b;
 25     b.x = x;
 26     b.y = y;
 27     b.face = face;
 28     return b;
 29 }
 30 
 31 struct Command // 命令类
 32 {
 33     int time; // 执行时刻
 34     string name; // 相应的坦克
 35     string type; // 命令类型
 36     int angle; // 如果是转向,标记转了多少度
 37 };
 38 
 39 class Robocode // 解题类
 40 {
 41 protected:
 42     const int h; // 地图高度(离散化之后)
 43     const int w; // 地图宽度(离散化之后)
 44     int n; // 坦克数量
 45     int m; // 指令数量
 46     vector<Tank> tanks; // 坦克集合向量
 47     vector<Bullet> bullets; // 子弹集合向量
 48     vector<Command> commands; // 命令集合向量
 49     int** tankmap; // tankmap[i][j]表示第i行第j列的坦克在对应的向量中的下标,如果是-1则表示第i行第j列没有坦克
 50     int** bulletmap; // bulletmap[i][j]表示第i行第j列有没有子弹,如是是1表示第i行第j列有子弹,如果是-1则表示第i行第j列没有子弹
 51     // void InitBullet();
 52     void Explode(); // 检查子弹会不会击中坦克,以及击中后的处理
 53     void ExcuteCmd(const Command& cmd); // 执行命令cmd
 54     void UpdateBullet(); // 更新子弹集合在某一时刻的位置信息
 55     void UpdateTank(); // 更新坦克集合在某一时刻的位置信息
 56 public:
 57     Robocode(int n, int m, const vector<Tank>& tanks, const vector<Command>& commands); // 构造方法
 58     ~Robocode(); // 析构方法
 59     void Run(); // 模拟过程
 60     void Output() const; //输出结果
 61 };
 62 
 63 Robocode::Robocode(int n, int m, const vector<Tank>& tanks, const vector<Command>& commands) 
 64     :h(12 * 6 + 1), w(12 * 6 + 1) // 注意高度和宽度做离散化处理,要乘上6(想想为什么)
 65 {
 66     this->n = n;
 67     this->m = m;
 68     this->tanks.reserve(n);
 69     this->commands.reserve(m);
 70     tankmap = new int*[h];
 71     for (int i = 0; i < h; i++)
 72     {
 73         tankmap[i] = new int[w];
 74     }
 75     bulletmap = new int*[h];
 76     for (int i = 0; i < h; i++)
 77     {
 78         bulletmap[i] = new int[w];
 79     }
 80     this->tanks.assign(tanks.begin(), tanks.end());
 81     this->commands.assign(commands.begin(), commands.end());
 82     for (int i = 0; i < h; i++)
 83     {
 84         for (int j = 0; j < w; j++)
 85         {
 86             tankmap[i][j] = -1;
 87         }
 88     }
 89     for (int i = 0; i < h; i++)
 90     {
 91         for (int j = 0; j < w; j++)
 92         {
 93             bulletmap[i][j] = -1;
 94         }
 95     }
 96     // 对坦克的位置信息进行离散化处理
 97     for (unsigned int i = 0; i < this->tanks.size(); i++)
 98     {
 99         this->tanks[i].x = (this->tanks[i].x / 10) * 6;
100         this->tanks[i].y = (this->tanks[i].y / 10) * 6;
101         this->tanks[i].move = false;
102         tankmap[this->tanks[i].x][this->tanks[i].y] = i;
103     }
104     // 对时间进行离散化处理
105     for (unsigned int i = 0; i < this->commands.size(); i++)
106     {
107         this->commands[i].time *= 6;
108     }
109 }
110 Robocode::~Robocode()
111 {
112     for (int i = 0; i < h; i++)
113     {
114         delete[] tankmap[i];
115     }
116     delete[] tankmap;
117     for (int i = 0; i < h; i++)
118     {
119         delete[] bulletmap[i];
120     }
121     delete[] bulletmap;
122 }
123 //void Robocode::InitBullet()
124 //{
125 //    for (int i = 0; i < h; i++)
126 //    {
127 //        for (int j = 0; j < w; j++)
128 //        {
129 //            bulletmap[i][j] = -1;
130 //        }
131 //    }
132 //    for (unsigned int i = 0; i < bullets.size(); i++)
133 //    {
134 //        bulletmap[bullets[i].x][bullets[i].y] = 1;
135 //    }
136 //}
137 
138 // 判断有没有出现子弹打中坦克的情况,如果出现,进行处理
139 void Robocode::Explode()
140 {
141     for (int i = 0; i < h; i++)
142     {
143         for (int j = 0; j < w; j++)
144         {
145             if (bulletmap[i][j] > -1 && tankmap[i][j] > -1) //离散化后的第i行第j列发生了子弹和坦克碰撞
146             {
147                 for (unsigned int k = 0; k < bullets.size();) // 遍历子弹,注意for语句的表达式3空缺,不可直接写k++
148                 {
149                     if (bullets[k].x == i && bullets[k].y == j) // 注意这里如果多个子弹和一辆坦克碰撞,都统统消失
150                     {
151                         bullets.erase(bullets.begin() + k); // 删除对应的子弹
152                     }
153                     else
154                     {
155                         k++;
156                     }
157                 }
158                 bulletmap[i][j] = -1;  // 标记离散化后的第i行第j列已经没有子弹
159                 for (unsigned int k = 0; k < tanks.size();) // 遍历坦克,注意for语句的表达式3空缺,不可直接写k++
160                 {
161                     if (tanks[k].x == i && tanks[k].y == j) // 注意这里如果多辆坦克和一个子弹碰撞,都统统消失
162                     {
163                         tanks.erase(tanks.begin() + k); // 删除对应的坦克
164                     }
165                     else
166                     {
167                         k++;
168                     }
169                 }
170                 tankmap[i][j] = -1; // 标记离散化后的第i行第j列已经没有坦克
171             }
172         }
173     }
174 }
175 
176 // 执行命令cmd
177 void Robocode::ExcuteCmd(const Command& cmd)
178 {
179     for (unsigned int i = 0; i < tanks.size(); i++)
180     {
181         if (cmd.name == tanks[i].name)
182         {
183             if (cmd.type == "MOVE") // 坦克移动,设置相应标志即可
184             {
185                 tanks[i].move = true;
186             }
187             else if (cmd.type == "STOP") // 坦克停止,设置相应标志即可
188             {
189                 tanks[i].move = false;
190             }
191             else if (cmd.type == "TURN") // 坦克转向处理,注意取模
192             {
193                 tanks[i].face = (tanks[i].face + cmd.angle + 360) % 360;
194             }
195             else if (cmd.type == "SHOOT") // 大炮开兮轰他娘(张宗昌)
196             {
197                 Bullet b = tanks[i].CreateBullet(); // 坦克产生子弹
198                 bullets.push_back(b); // 更新子弹向量
199                 bulletmap[b.x][b.y] = bullets.size() - 1; // 标记对应的行列位置有子弹,设置子弹的下标
200             }
201         }
202     }
203 }
204 
205 // 更新离散化后的某个时刻的子弹的位置信息
206 void Robocode::UpdateBullet()
207 {
208     for (unsigned int i = 0; i < bullets.size(); )
209     {
210         // 反正子弹在消失以前总是飞的,所以上一时刻子弹i出现的位置和这一时刻子弹i出现的位置必定不一样,先把原先位置标记没有子弹
211         bulletmap[bullets[i].x][bullets[i].y] = -1; 
212         switch (bullets[i].face) // 根据子弹的前进方向判断子弹在这一时刻的位置
213         {
214         case 0:
215             bullets[i].x += 2; // 注意离散化后,子弹每次移动2个单位
216             if (bullets[i].x > w - 1) // 子弹向右飞出了区域,应从战场消失
217             {
218                 bullets.erase(bullets.begin() + i);
219             }
220             else
221             {
222                 bulletmap[bullets[i].x][bullets[i].y] = i; // 子弹向右到了下一个位置,更新相应的信息
223                 i++;
224             }
225             break;
226         case 90:
227             bullets[i].y += 2; // 注意离散化后,子弹每次移动2个单位
228             if (bullets[i].y > h  - 1) // 子弹向下飞出了区域,应从战场消失
229             {
230                 bullets.erase(bullets.begin() + i);
231             }
232             else
233             {
234                 bulletmap[bullets[i].x][bullets[i].y] = i; // 子弹向下到了下一个位置,更新相应的信息
235                 i++;
236             }
237             break;
238         case 180:
239             bullets[i].x -= 2; // 注意离散化后,子弹每次移动2个单位
240             if (bullets[i].x < 0) // 子弹向左飞出了区域,应从战场消失
241             {
242                 bullets.erase(bullets.begin() + i);
243             }
244             else
245             {
246                 bulletmap[bullets[i].x][bullets[i].y] = i; // 子弹向左到了下一个位置,更新相应的信息
247                 i++;
248             }
249             break;
250         case 270:
251             bullets[i].y -= 2; // 注意离散化后,子弹每次移动2个单位
252             if (bullets[i].y < 0) // 子弹向上飞出了区域,应从战场消失
253             {
254                 bullets.erase(bullets.begin() + i);
255             }
256             else
257             {
258                 bulletmap[bullets[i].x][bullets[i].y] = i; // 子弹向上到了下一个位置,更新相应的信息
259                 i++;
260             }
261             break;
262         }
263     }
264     //InitBullet();
265 }
266 
267 // 更新某一时刻的坦克的位置信息
268 void Robocode::UpdateTank()
269 {
270     for (unsigned int i = 0; i < tanks.size(); i++)
271     {
272         if (tanks[i].move) // 只处理在移动的坦克,有的坦克是静止的,不用处理
273         {
274             tankmap[tanks[i].x][tanks[i].y] = -1; // 移动的坦克肯定不在原先的位置了
275             switch (tanks[i].face) // 根据坦克的前进方向判断坦克在这一时刻的位置
276             {
277             case 0: // 向右前进
278                 tanks[i].x += 1; // 注意离散化后,坦克每次移动1个单位
279                 if (tanks[i].x > w - 1) // 如果到达最右边的边界
280                 {
281                     tanks[i].x = w - 1; // 不能穿越也不能消失,在右边界原地不动
282                 }
283                 break;
284             case 90: // 向下前进
285                 tanks[i].y += 1; // 注意离散化后,坦克每次移动1个单位
286                 if (tanks[i].y > h - 1) // 如果到达最下边的边界
287                 {
288                     tanks[i].y = h - 1; // 不能穿越也不能消失,在下边界原地不动
289                 }
290                 break;
291             case 180:
292                 tanks[i].x -= 1; // 注意离散化后,坦克每次移动1个单位
293                 if (tanks[i].x < 0) // 如果到达最左边的边界
294                 {
295                     tanks[i].x = 0; // 不能穿越也不能消失,在左边界原地不动
296                 }
297                 break;
298             case 270:
299                 tanks[i].y -= 1; // 注意离散化后,坦克每次移动1个单位
300                 if (tanks[i].y < 0) // 如果到达最上边的边界
301                 {
302                     tanks[i].y = 0; // 不能穿越也不能消失,在上边界原地不动
303                 }
304                 break;
305             }
306             tankmap[tanks[i].x][tanks[i].y] = i; // 在新位置标记坦克在坦克向量中的下标
307         }
308     }
309 }
310 void Robocode::Run()
311 {
312     unsigned int cmdidx = 0;
313     int time = 0;
314     bullets.clear();
315     for (int i = 0; i < h; i++)
316     {
317         for (int j = 0; j < w; j++)
318         {
319             bulletmap[i][j] = -1;
320         }
321     }
322     while (true)
323     {
324         //InitBullet();
325         Explode(); // 先处理这一时刻有没有子弹击中坦克的情况,why?
326 
327         //遍历命令向量,如果某个向量的执行时刻到了,就执行
328         while (cmdidx < commands.size() && commands[cmdidx].time == time) 
329         {
330             ExcuteCmd(commands[cmdidx]);
331             cmdidx++;
332         }
333         
334         UpdateBullet(); // 更新子弹位置信息
335         UpdateTank(); // 更新坦克位置信息
336         //Explode();
337         if (cmdidx >= commands.size()) //命令全部执行完了
338         {
339             if (bullets.size() > 0) // 让子弹再飞一会(姜文《让子弹飞》)
340             {
341 
342             }
343             else // 如果命令全部执行完了,子弹也飞完了,说明游戏结束
344             {
345                 break;
346             }
347         }
348         time++; // 时间单位计数器加1
349     }
350 }
351 
352 void Robocode::Output() const
353 {
354     if (tanks.size() == 1)
355     {
356         cout << tanks[0].name << "\n";
357     }
358     else
359     {
360         cout << "NO WINNER!\n";
361     }
362 }
363 
364 int main()
365 {
366     //ifstream cin("Text.txt");
367     int n = 0;
368     int m = 0;
369     cin >> n >> m;
370     while (n > 0 && m > 0)
371     {
372         vector<Tank> tanks;
373         vector<Command> commands;
374         for (int i = 0; i < n; i++)
375         {
376             Tank t;
377             cin >> t.name >> t.x >> t.y >> t.face;
378             tanks.push_back(t);
379         }
380         for (int i = 0; i < m; i++)
381         {
382             Command c;
383             cin >> c.time >> c.name >> c.type;
384             if (c.type == "TURN")
385             {
386                 cin >> c.angle;
387             }
388             commands.push_back(c);
389         }
390         Robocode obj(n, m, tanks, commands);
391         obj.Run();
392         obj.Output();
393         cin >> n >> m;
394     }
395     return 0;
396 }
View Code

 

posted @ 2019-07-01 19:54  回忆酿的甜  阅读(476)  评论(0编辑  收藏  举报
Live2D