Let's have a tank war!
Partially inspired by Destroy Them With Lazers
Objective
Your task is to control a tank. Move around and shoot other tanks and obstacles in the 2D battlefield. The last tank standing will be the winner!
Map format
Your tank will be on a 2D field based on an n
by n
grid of unit squares. I will decide what n
is based on the number of submissions. Each square can contain only one of:
- A tank
- A tree
- A rock
- A wall
- Nothing
All obstacles and tanks completely fill their spaces, and they block all shots that hit them from damaging things further down.
Here is an example of a field with #
=tank; T
=tree; R
=rock; W
=wall; .
=nothing with n
=10
.....#....
..T....R..
WWW...WWWW
W......T..
T...R...Ww
W...W.....
W....W...T
WWWWWW...R
W.........
WWWWWWRT..
Coordinates are in the format x, y
where x
increases left to right and y
increases bottom to top. The bottom left space has the coordinate 0, 0
. Each tank may move to any empty space and shoot in any direction.
Map Dynamics
Your tank doesn't just have to shoot other tanks! If it shoots something on the map, things can happen.
- If a wall is shot at, it will be destroyed after some number of shots, ranging from 1 to 4
- If a tree is shot at, it will be destroyed immediately
- If a rock is shot at, the shot will pass over it and damage the next thing it hits
Once something is destroyed, it is no longer on the map (it will be replaced with nothing). If a shot destroys an obstacle, it will be blocked and will not damage anything further along its path.
Tank dynamics
Each tank starts with life
=100. Each shot at a tank will reduce 20-30 life
based on distance. This can be calculated with delta_life=-30+(shot_distance*10/diagonal_map_length)
(where diagonal_map_length
is (n-1)*sqrt(2)
). Additionally, each tank regenerates 1 life
per turn.
Turns
Some number of rounds will be run (I will decide once I have submissions). At the beginning of every round, a map will be generated randomly, and tanks will be placed on it in random empty locations. During every round, each tank will be given a turn, in any arbitrary order. After every tank has been given a turn, they will be given turns again in the same order. The round continues until there is only one tank left. That tank will be the winner, and they will receive 1 point. The game will then go on to the next round.
Once all the rounds have been run, I will post the scores on this question.
During a tank's turn, it may do one of the following
- Move up to 3 spaces in a single direction, either horizontally or vertically. If the tank is blocked by an obstacle or another tank, it will be moved as far as possible without going through the obstacle or tank.
- Shoot in some direction, represented by a floating point angle in degrees. The x-axis of your tank's local space (horizontally left to right, aka east or
TurnAction.Direction.EAST
) is 0deg, and angles increase counterclockwise. Shots are inaccurate, and the actual angle of the shot may be 5 degrees greater or less than the angle you choose. - Do nothing.
Turns are not limited in time, but this doesn't mean you can intentionally waste time to hang everything up.
Submissions/Protocol
Each program submitted will control one tank on the field. The control program is in Java, so your programs need to be in Java for now (I will probably write a wrapper for other languages at some point, or you could write your own).
Your programs will implement the Tank
interface, which has the following methods:
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();
}
The Battlefield
class contains a 2D array of objects (Battlefield.FIELD_SIZE
by Battlefield.FIELD_SIZE
) which represents things on the battlefield. Battlefield.getObjectTypeAt(...)
will give a FieldObjectType
for the object at the specified coordinates (one of FieldObjectType.ROCK
, FieldObjectType.TREE
, FieldObjectType.TANK
, FieldObjectType.WALL
, or FieldObjectType.NOTHING
). If you try to get an object out of range of the map (coordinates <0 or >=Battlefield.FIELD_SIZE
) then an IllegalArgumentException
will be thrown.
MapPoint
is a class for specifying points on the map. Use MapPoint.getX()
and MapPoint.getY()
to access the coordinates.
EDIT: Some utility methods have been added: MapPoint.distanceTo(MapPoint)
, MapPoint.angleBetween(MapPoint)
, Battlefield.find(FieldObjectType)
, and TurnAction.createShootActionRadians(double)
as suggested by Wasmoo.
More info can be found in the javadocs, see section below.
All (public API) classes are under the package zove.ppcg.tankwar
.
Control Program
The full source and javadocs of the control program and tank API can be found on my GitHub repo: https://github.com/Hungary-Dude/TankWarControl
Feel free to send pull requests and/or comment if you see a bug or want an improvement.
I have written two sample tank programs, RandomMoveTank
and RandomShootTank
(the name says it all).
To run your tank, add your fully qualified (package name + class name) tank class to tanks.list
(one class per line), edit settings as necessary in zove.ppcg.tankwar.Control
(turn delay, whether or not to show a GUI representation of the field, etc), and run zove.ppcg.tankwar.Control
. Make sure there are at least 2 tanks on the list, or results are undefined. (Use the sample tanks if necessary).
Your programs will be run on my machine under this control program. I'll include a link to the source once I write it. Feel free to suggest edits to the source.
Rules
- Your submissions must follow the guidelines above
- Your programs may not access the filesystem, network, or attempt to attack my machine in any way
- Your programs may not attempt to exploit my control program to cheat
- No trolling (such as intentionally making your program waste time to hang everything up)
- You may have more than one submission
- Try to be creative with submissions!
- I reserve the right to allow or not allow programs arbitrarily
Good luck!
UPDATE: After fixing the wall teleportation bug and implementing regeneration, I ran the current submissions for 100 rounds with Battlefield.FIELD_SIZE = 30
UPDATE 2: I added the new submission, RunTank, after fooling with Groovy for a bit...
Updated results:
+-----------------+----+
| RandomMoveTank | 0 |
| RandomShootTank | 0 |
| Bouncing Tank | 4 |
| Richard-A Tank | 9 |
| Shoot Closest | 19 |
| HunterKiller 2 | 22 |
| RunTank | 23 |
| Dodge Tank | 24 |
+-----------------+----+
Currently tanks regenerate 1 life per turn. Should that be increased?
MapPoint
'sx
andy
floats
? Shouldn't they beints
? \$\endgroup\$