让我们进行一场坦克大战!
部分受到激光摧毁他们的启发
目的
您的任务是控制坦克。四处移动并射击2D战场中的其他坦克和障碍物。最后的坦克站将是赢家!
地图格式
您的战车将位于2D字段,该字段基于单位正方形的n
by n
网格。我将n
根据提交的数量决定什么。每个方块只能包含以下一项:
- 一辆战车
- 一颗树
- 一块石头
- 一堵墙
- 没有
所有的障碍物和坦克完全填满了它们的空间,它们阻挡了所有击中它们的镜头,从而不会进一步破坏物体。
这是带有#
= tank 的字段的示例;T
= tree; R
= rock; W
= wall; .
=没有n
= 10
.....#....
..T....R..
WWW...WWWW
W......T..
T...R...Ww
W...W.....
W....W...T
WWWWWW...R
W.........
WWWWWWRT..
坐标格式x, y
,其中x
从左向右增加,并y
增加下到上。左下角的坐标为0, 0
。每个坦克可以移动到任何空白处并向任何方向射击。
地图动力学
您的战车不仅仅需要射击其他战车!如果它在地图上拍摄了东西,则可能会发生。
- 如果击中墙壁,则经过几次射击(从1到4不等),它将被摧毁
- 如果射中一棵树,它将立即被摧毁
- 如果向岩石开枪,则枪击将越过它并损坏其撞击的下一件事
一旦某物被破坏,它就不再在地图上(它将被替换为空)。如果击球摧毁障碍物,它将被阻挡并且不会进一步破坏其前进路线。
坦克动力学
每个坦克以life
= 100 开头。坦克每次射击会life
根据距离减少20-30 。可以使用delta_life=-30+(shot_distance*10/diagonal_map_length)
(其中diagonal_map_length
是(n-1)*sqrt(2)
)进行计算。此外,每个坦克life
每回合可再生1 次。
转弯
将进行一些回合(一旦提交,我将决定)。在每个回合开始时,将随机生成一张地图,并将坦克放置在随机的空白位置。在每一回合中,每个战车都会以任意顺序转过一圈。在将每个战车转过一圈之后,将以相同的顺序再次进行转弯。这一回合一直持续到只剩下一辆坦克为止。该坦克将是赢家,他们将获得1分。然后,游戏将继续进行下一轮比赛。
完成所有回合后,我将在此问题上发布分数。
在战车转弯期间,它可能会执行以下任一操作
- 在一个方向上水平或垂直移动最多3个空间。如果水箱被障碍物或其他水箱阻塞,则它将在不穿过障碍物或水箱的情况下尽可能地移动。
- 朝某个方向拍摄,以度为单位的浮点角度表示。坦克局部空间的x轴(水平从左到右,又称东或
TurnAction.Direction.EAST
)为0度,并且角度沿逆时针方向增大。射击不准确,并且射击的实际角度可能比您选择的角度大5度或小5度。 - 没做什么。
转弯没有时间限制,但这并不意味着您可以故意浪费时间挂起所有东西。
提交/协议
提交的每个程序将在现场控制一个坦克。控制程序是用Java编写的,因此您的程序现在需要用Java(我可能会在某个时候为其他语言编写包装器,或者您可以编写自己的包装器)。
您的程序将实现Tank
接口,该接口具有以下方法:
public interface Tank {
// Called when the tank is placed on the battlefield.
public void onSpawn(Battlefield field, MapPoint position);
// Called to get an action for the tank on each turn.
public TurnAction onTurn(Battlefield field, MapPoint position, float health);
// Called with feedback after a turn is executed.
// newPosition and hit will be populated if applicable.
public void turnFeedback(MapPoint newPosition, FieldObjectType hit);
// Called when the tank is destroyed, either by another tank,
// or because the tank won. The won parameter indicates this.
public void onDestroyed(Battlefield field, boolean won);
// Return a unique name for your tank here.
public String getName();
}
的Battlefield
类包含对象(的2D阵列Battlefield.FIELD_SIZE
由Battlefield.FIELD_SIZE
)代表在战场上的东西。Battlefield.getObjectTypeAt(...)
将给出FieldObjectType
在指定坐标的对象(之一FieldObjectType.ROCK
,FieldObjectType.TREE
,FieldObjectType.TANK
,FieldObjectType.WALL
,或FieldObjectType.NOTHING
)。如果您尝试使某个对象超出地图范围(坐标<0或> = Battlefield.FIELD_SIZE
),IllegalArgumentException
则将引发。
MapPoint
是用于在地图上指定点的类。使用MapPoint.getX()
和MapPoint.getY()
访问坐标。
编辑:已添加一些实用方法:MapPoint.distanceTo(MapPoint)
,MapPoint.angleBetween(MapPoint)
,Battlefield.find(FieldObjectType)
,和TurnAction.createShootActionRadians(double)
所建议Wasmoo。
可以在javadocs中找到更多信息,请参阅下面的部分。
所有(公共API)类都在package中zove.ppcg.tankwar
。
控制程序
可以在我的GitHub存储库中找到控制程序和tank API的完整源代码和javadocs:https://github.com/Hungary-Dude/TankWarControl
如果发现错误或需要改进,请随时发送拉取请求和/或评论。
我已经编写了两个示例坦克程序,RandomMoveTank
并且RandomShootTank
(名称说明了一切)。
要运行您的储罐,请将您的标准(包名称+类名)储罐类添加到tanks.list
(每行一个类),并根据需要编辑设置zove.ppcg.tankwar.Control
(转弯延迟,是否显示该字段的GUI表示等),然后跑zove.ppcg.tankwar.Control
。确保列表上至少有2个储罐,否则结果不确定。(如有必要,请使用样品罐)。
您的程序将在此控制程序下在我的计算机上运行。编写源代码后,我将包括指向该源代码的链接。随时建议对源进行编辑。
规则
- 您的提交必须遵循上述准则
- 您的程序可能无法访问文件系统,网络或试图以任何方式攻击我的计算机
- 您的程序可能不会尝试利用我的控制程序来作弊
- 无需拖延(例如故意使程序浪费时间挂断所有内容)
- 您可能有多个提交
- 尝试通过提交来发挥创意!
- 我保留任意允许或不允许程序的权利
祝好运!
更新:修复了墙面传送错误并实施了再生之后,我将当前提交的内容进行了100轮回合Battlefield.FIELD_SIZE = 30
更新2:在与Groovy弄混了一点之后,我添加了新提交的RunTank ...
更新结果:
+-----------------+----+
| RandomMoveTank | 0 |
| RandomShootTank | 0 |
| Bouncing Tank | 4 |
| Richard-A Tank | 9 |
| Shoot Closest | 19 |
| HunterKiller 2 | 22 |
| RunTank | 23 |
| Dodge Tank | 24 |
+-----------------+----+
目前,坦克每回合可回复1点生命。应该增加吗?
MapPoint
的x
和y
floats
?不是ints
吗?