前言
hello,大家好,这期文章带大家刷一个略微复杂的题目,准备好了吗?让我们开始喽。
1. 题目描述
Robocode是一个帮助你学Java的教学游戏。它是玩家编写的程序,控制坦克在战场上互相攻击。这个游戏的思想看似简单,但编写一个获胜坦克的程序还需要很多的努力。本题不要求编写一个智能坦克的程序,只要设计一个简化的Robocode 游戏引擎即可。
本题设定整个战场是120x120(像素)。每辆坦克只能沿水平和垂直方向在固定的路径上移动(在战场中的水平和垂直方向路径每10个像素1格,总共有13条垂直路径和13条水平路径坦克可以行走,如图2-1所示)。本题忽略坦克的形状和大小,对于一辆坦克,用(x,y)(x,yE[0,120])表示它的坐标位置,用α(αE{0,90,180,270})表示坦克面对的方向(α=0、90、180或270,分别表示坦克面向右、上、左或下)。坦克以10像素/秒的恒定速度行驶,不能跑到边界之外(当坦克冲到战场的边界上的时候,就会停止移动,保持当前所面对的方向)。坦克可以向它所面对的方向射击,无论它是在行进还是停止。射击时炮弹以20像素/秒的恒定速度射出,炮弹的大小也被忽略。炮弹在路径上遇到一辆坦克时,就会发生爆炸。如果一发以上的炮弹几乎在同一时刻命中坦克,在同一个地方发生爆炸是可能的。被击中的坦克将被销毁,并从战场上被立即移走。爆炸的炮弹或飞出边界的炮弹也将被移走。
输入
有若干个测试用例。对所有的测试用例,战场和路径都是一样的。每个测试用例者先量,M表示控制坦克移动的指令的0。和的N行给出每辆坦克的初始信息(在时间为0),格式如下:
Name x y a
一辆坦克的Name由不超过10个字母组成。x、y和a是整数,其中x,yE{0,10,20,120},aE{0,90,180,270},每个项之间用一个空格分开。
接下来的M行给出指令,格式如下:
Time Name Content
每个项之间用一个空格分开。按Time的升序给出所有的指令(0≤Time≤30),Time是一个正整数,表示指令发出的时间戳。Name表示接收指令的坦克。Content的类型如下:
·MOVE:当接收到这条指令时,坦克开始朝它所面向的方向移动。如果坦克已经在运动,那么这条指令无效。
·STOP:当接收到这条指令时,坦克停止移动。如果坦克已经停下,那么这条指令无效。
·TURN angle:当接收到这条指令时,坦克改变它面对的方向,从α改为((a+angle+360)mod 360),无论其是否在移动中。本题确定((α+angle+360)mod 360)e{0,90,180,270}。TURN指令不会影响坦克的移动状态。
·SHOOT:当接收到这条指令时,坦克向它所面对的方向发射一枚炮弹。
坦克一旦接收到指令,就采取相应的行动。例如,如果一辆坦克位置为(0,0),α=90,在Time 1接收到指令MOVE,它就开始移动,在Time2到达位置(0,1)。要注意的是,坦克可以在一秒内接收多条指令,一条接一条地根据指令采取相应的行动。例如,如果坦克位置为(0,0),α=90,接收到的指令序列为"TURN 90;SHOOT;TURN-90",它就转到方向a=180,发射一枚炮弹,然后再转回来。如果坦克接收到"MOVE;STOP"指令序列,它仍然待在原来的位置。
请注意一些要点:
·如果一辆坦克被击中爆炸,在那一刻,它对所有收到的指令都不会采取任何行动。当然,所有发送到已经摧毁的坦克的指令也被略去。
·虽然指令在确定的时间点发出,但是坦克和炮弹的运动和爆炸发生在连续时间段内。
·输入数据保证不会有两辆坦克在路上相撞,因此你的程序不必考虑这种情况。
·所有的输入内容都是合法的。
以N=M=0的测试用例终止输人,程序不用处理这一情况。
输出
对每个测试用例,在一行中输出赢家的名字。赢家是最后生存下来的坦克。如果在最后没有坦克了,或者有多于一辆坦克生存下来,则在一行中输出"NO WINNER!"。
2. 题目分析
这是一道时序模拟题,指令发出的时间范围为30秒,考虑到最后一条指令执行后可能会有变化,则可以一直模拟到45秒后。
如果位于(0,0)位置的坦克朝向(0,1)位置开炮,而位于(0,1)位置的坦克朝向(0,0)位置驶来,那么会在中间 13的位置处被击中,同时也可能在 12时间出现事故。于是解题要将时间和地图都扩大6倍,即等价于原来的图每 16秒考虑一次。
坦克和炮弹的属性有4个:位置、方向、行进(或停止)状态、移走(或未移走)状态。
我们从0时刻出发,依次处理每条指令。若当前指令的发出时间为t2,上条指令的发出时间为t1,则先依序模拟t1、2时刻的战况,然后根据指令设定受令坦克的状态:
·若为“MOVE"指令,则受令坦克进入行进状态;
·若为“STOP"指令,则受令坦克进入停止状态;
若为"SHOOT”指令且受令坦克未移走,则新增一发炮弹,除设行进状态外,其他属性如同受令坦克;
·若为"TURN angle"指令,则受令坦克的方向调整为
处理完所有指令后,再模拟15秒的战况,以处理最后指令的后继影响。
最后,统计生存下来的坦克数:若所有坦克移走,或有一辆以上的坦克未移走,则没有赢家,否则则为未移走的那辆坦克。
3. 代码实现
#include<iostream>
#include<map>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<string>
using namespace std;
const int DirX[4] = { 10, 0, -10, 0 };
const int DirY[4] = { 0, 10, 0, -10 };
#define mp make_pair;
int N, M, Shoot;
int x[1050], y[1050], d[1050];
bool run[1050], die[1050];
string symbol[1050];
map<string, int>Name;
void Init()
{
Name.clear();
for (int i = 1; i <= N; i++)
{
cin >> symbol[i] >> x[i] >> y[i] >> d[i];
x[i] *= 6;
y[i] *= 6;
d[i] /= 90;
run[i] = false;
die[i] = false;
Name[symbol[i]] = i;
}
Shoot = N;
}
bool In(int x, int y)
{
if (x >= 0 && x <= 6 * 120 && y >= 0 && y <= 6 * 120)
return true;
else
return false;
}
void RunAll()
{
for (int i = 1; i <= N; i++)
{
if (run[i] && !die[i])
{
if (In(x[i] + DirX[d[i]], y[i] + DirY[d[i]]))
{
x[i] += DirX[d[i]];
y[i] += DirY[d[i]];
}
else
run[i] = false;
}
}
for (int i = N + 1; i <= Shoot; i++)
{
if (!die[i])
{
if (In(x[i] + DirX[d[i]] * 2, y[i] + DirY[d[i]] * 2))
{
x[i] += DirX[d[i]] * 2;
y[i] += DirY[d[i]] * 2;
}
else
die[i] = true;
}
}
for (int i = 1; i <= N; i++)
{
if (die[i])
continue;
for (int j = N + 1; j <= Shoot; j++)
if (!die[j])
{
if (x[i] == x[j] && y[i] == y[j])
{
die[j] = true;
die[i] = true;
}
}
}
}
void Slove()
{
int now = 0;
for (int i = 1; i <= M; i++)
{
int t;
string sym, s;
int th;
cin >> t >> sym >> s;
t *= 6;
while (t > now)
{
RunAll();
now++;
}
int symId = Name[sym];
if (s == "MOVE")
{
run[symId] = true;
}
else if (s == "STOP")
{
run[symId] = false;
}
else if (s == "SHOOT")
{
if (!die[symId])
{
Shoot++;
run[Shoot] = true;
die[Shoot] = false;
d[Shoot] = d[symId];
x[Shoot] = x[symId];
y[Shoot] = y[symId];
}
}
else
{
cin >> th;
th /= 90;
d[symId] = (d[symId] + (th % 4) + 4) % 4;
}
}
for (int i = 1; i <= 15 * 6; i++)
RunAll();
int cnt = 0;
for (int i = 1; i <= N; i++)
if (!die[i])
cnt++;
if (cnt != 1)
cout << "NO WINNER!" << endl;
else
{
for (int i = 1; i <= N;i++)
if (!die[i])
cout << symbol[i] << endl;
}
}
int main()
{
while (cin >> N >> M && (N || M))
{
Init();
Slove();
}
}
后记
好的,这期文章就分享到这里了,希望对大家有所帮助。下期再见。