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 }
----------------------------------------------------------------------------------------------------------------转载请说明出处----------------------------------------------------------------------------------------------------------------------
你要做一个不动声色的大人了。不准情绪化,不准偷偷想念,不准回头看。去过自己另外的生活。你要听话,不是所有的鱼都会生活在同一片海里。
————————村上春树