Rocket Bots KOTH

Rocket Bots

The year is 3024. People have become too scarce a resource to risk in war, so combat has shifted to the robots. Your task is to construct a bot like no other, who's rockets will rain destruction down on your foes and shoot down all incoming threats.

Gameplay

Bots

Gameplay takes place on a 10x15 grid. Your bot is located off the bottom edge, and has three slots at spots 6,7 and 8 of the grid. Your opponent is located at the top of the grid, with three slots directly opposite yours.

Rockets

From any of these slots, you can fire a rocket, assuming the slot has not been destroyed. A rocket consists of a list of directions that is given to it when created, and once fired these directions cannot be changed. Each turn, the rocket will consume the top of the list, and move in that direction. Rockets move simultaneously. If two rockets end in the same tile, they will both explode. If a rocket runs out of commands, it will explode. If a rocket runs out of fuel, after 100 moves, it will explode. When a rocket explodes, it will remain in that tile for 5 turns, causing any other rockets that move there to explode as well.

Note: Because of the simultaneous movement, two rockets can pass each other without exploding, as long as they do not both end a turn in the same tile.

Goal

The goal of each match is to destroy your opponents slots while keeping yours alive. A rocket can be fired from any live slot you have, and is given a path designated by you before it is fired. You fire a rocket every second turn, meaning rockets will move twice before you can fire another one. A duel lasts for 200 turns, or until one bots slots are all destroyed.

Scoring

At the end of the match, you get one point for each live slot you have, and one point for each opponents slot you destroyed. This means it is a zero-sum game, and 6 points will be awarded each match.

A round robin will be run so that each bot faces each other bot once. If any bots use RNGs, then each matchup will be 1000 duels instead.

Implementation

Code for the competition can be found here: https://github.com/Cain93/RocketBots

Each submission should extend the Bot class. You must override the fireRocket method. This method receives a grid array of Rockets, Rocket[][], that represents the gameboard. You are always located at the bottom of the grid, with slots at spots [-1][6], [-1][7], [-1][8]. On the grid, unoccupied spots will be represented with null. If a rocket exists in a tile, you can identify who it belongs to by accessing the dis field. "^" is your rocket, and "v" is your opponents.

You must return a LinkedList of Integers that gives the instructions for your rocket. To move up, use 0. To move up and right, use 1, just right, use 2, etc all the way to 7 for up and left. The rocket will move in the order you push Integers. For example, the following code will make the rocket move upwards a few turns, zig-zag a few turns and then detonate.

LinkedList<Integer> moves = new LinkedList<Integer>();

moves.push(0);
moves.push(0);
moves.push(0);
moves.push(1);
moves.push(7);
moves.push(1);
moves.push(7);


To change which slot to fire the rocket from, change the curSlot field. 0 is your leftmost slot, and 2 is your rightmost. To check if a slot is destroyed, use getSlot(int slotNumber).

If a rocket ends a turn on a slot, that slot will be destroyed. You do not need to manually detonate the rocket.

Note: Rockets spawn at the location of the slot fired from, but will move once before collisions are evaluated. So if you fire a rocket from slot 0, and the first move is right (2), then you will destroy your own middle slot. However, up and right (1) is a safe move.

If you want to name your bot, override the name() method.

Bots will be re-built for each duel, so any static variables will be reset.

Good Luck!

May your rockets fly true and your opponents be nothing but smoldering scraps of metal.

Hint:

Purposefully detonating rockets to create explosions is an easier way to defend than trying to shoot down opponents rockets.

Example Bot

package bots;

import mechanics.*;

public class SimpleBot extends Bot {

public String name(){
return "Simple";
}

for(int i = 0; i < 12; i++){
l.push(0);
}
return l;
}

}


Scores

Scores from 6-24

Simple: 900
Zigzagoon: 3654
Wall-E: 3606
Tortoise: 2248
3 Shot: 2334
HatTrickBot: 4287
Sniper: 2973
SideShooter: 2491
Terminator: 4835
StraightShot: 3378
Defender: 4570
MoreDakka: 4324

• Fixed so order does not matter, if any bots use RNG's then I will increase the running to 1000 times per matchup
– Cain
Jun 22 '15 at 22:41
• Is there a way to check if an opponent slot is destroyed? getSlot(int) is only for our slots, right? Jun 23 '15 at 7:47
• @Cain It could be interesting, to be able to not launch any rocket to a destroyed slot :3 Jun 24 '15 at 5:50
• @Manu it's not a bug, you're looking to the board from your side, so the left slots are relative Jun 24 '15 at 11:30
• I'm so sorry, fixed that bug already, I just forgot to push it!
– Cain
Jun 24 '15 at 15:30

Zigzagoon

The outer slots go (slightly) wide, then head forward and come back in toward the enemy slots. The middle slot shoots a zigzag pattern up the middle.

Every other round (3 turns), it goes into defense mode and just explodes some rockets near my own slots. Attack mode rockets then go around them. Nothing too fancy, just something to get the contest up and running.

package bots;import java.util.*;import mechanics.*;

public class Zigzagoon extends Bot{
String[] evenMoves = {"7000000001","0170710170","1000000007"};
String[] oddMoves = {"0","00","0"};
boolean even = true;
public String name(){return "Zigzagoon";}

curSlot = (curSlot+1)%3;
if(curSlot<1)even=!even;
String[] moves = even?evenMoves:oddMoves;
for(int i=0;i<moves[curSlot].length();i++)
command.push(moves[curSlot].charAt(i)-'0');
return command;
}
}

• Fixed, most of the difference came from which whether even started as true or false. Bots now rebuild before each match.
– Cain
Jun 22 '15 at 22:42
• Ah, that makes sense. I didn't even think of variables not resetting. Thanks :) Jun 23 '15 at 0:42

Terminator

I'm proud to present Terminator !!!

Each rocket move far left/right from the middle and return on a enemy slot. Every two turns, a defense rocket is launched straight and explode near slot to protect it.

package bots;

import mechanics.Bot;
import mechanics.Rocket;

public class Terminator extends Bot {

int n = 0;
String[] moves = {"000", "0111107777", "00", "0077700111", "00", "0777701111"};

public String name() {
return "Terminator";
}

@Override
curSlot = (n+1) % 3;

n++;

return commands;
}

for (int i = 0; i < commands.length(); i++) {
}

}

}


HatTrickBot

I had DoubleTapBot for CodeBot 3, who was hitting twice on a turn, here comes HatTrickBot : Hitting all the 3 spots at the same time !

It is always possible to prevent a rocket to hit if you know where it will fall. But I don't think there's many bot that will be able to protect their slots against a 3 rocket attack.

By the way, yes, it's horrible to see such elseif with repeated switch. I could have created a var to switch on with unique values for each combination of the status of slots and the turnConter. But it would be harder to read (I would have to keep the meaning of the values in a comment... boring !) :)

package bots;
import mechanics.*;
/*
* HatTrickBot always tries to destroy all the enemy slots at once
* In order to achieve this, each slot needs extrem concentration and coordination
* It explain why they need some turns to re-synchronized the rockets after one of them dies.
*/
public class HatTrickBot extends Bot
{
// Default moves are at [0]
// moves at [1] are used when there's only 2 slots remaining
// moves  [2-4] are here for when there's only 1 slot remaining
// it panicks, and can't establish how to fire to do a hat trick.
// So he will just spamm every ennemy position, one at a time
String[] rightSlot = {  "770002000020",
"0000000001",
"0000000000",
"0000000001",
"0000000011"};
String[] midSlot   = {  "0000000000",
"11000060000",
"0000000000",
"0000000010",
"0000000700"};
String[] leftSlot  = {  "11000060007",
"777702000020",
"0000000000",
"0000007000",
"0000077000"};
int turnCounter=-1;
public String name(){return "HatTrickBot";}
{
turnCounter=(turnCounter+1)%3;
String[][] moves = {rightSlot,midSlot,leftSlot};
boolean slotL=getSlot(0),slotM=getSlot(1),slotR=getSlot(2);
int movePoint=0;
if(slotL&&slotM&&slotR)
{
switch(turnCounter)
{
case 0: curSlot=0;
break;
case 1: curSlot=2;
break;
case 2: curSlot=1;
break;
default:break;
}
movePoint=0;

}
else if(!slotM&&slotL&&slotR)
{
switch(turnCounter)
{
case 0: curSlot=0;
movePoint=0;
break;
case 1: curSlot=2;
movePoint=0;
break;
case 2: curSlot=0;
movePoint=1;
break;
default:break;
}
}
else if(!slotL&&slotM&&slotR)
{
switch(turnCounter)
{
case 0: curSlot=0;
movePoint=0;
break;
case 1: curSlot=1;
movePoint=1;
break;
case 2: curSlot=0;
movePoint=1;
break;
default:break;
}
}
else if(!slotR&&slotM&&slotL)
{

switch(turnCounter)
{
case 0: curSlot=2;
movePoint=1;
break;
case 1: curSlot=1;
movePoint=1;
break;
case 2: curSlot=1;
movePoint=0;
break;
default:break;
}
}
else
{
if(slotR)curSlot=0;
if(slotM)curSlot=1;
if(slotL)curSlot=2;
movePoint = 2+turnCounter;
}
for(int i=0;i<moves[curSlot][movePoint].length();i++)
ll.push(Integer.parseInt(moves[curSlot][movePoint].charAt(i)+""));
return ll;
}
}

• Rockets only fire every other turn, so this doesn't make a full Hat Trick hit. Still extremely effective though
– Cain
Jun 23 '15 at 19:12
• @Cain Ho, sad that it's every 2 turns :/. Anyway, I'll see the result of the first round then modify to do a real HatTrick if I think it can improve it :) Jun 23 '15 at 19:17
• Rockets move twice between every time fireRocket() is called. So right now, they are all offset from each other by a turn still. You can use the test file in the controller to see a visual representation of the match.
– Cain
Jun 23 '15 at 19:17
• @Cain I was at work when I wrote those bots, so I based them only on the specs :) Jun 23 '15 at 19:39
• Wow, I'm impressed you managed to write that without any testing then, congrats. I updated the specs to make it more clear
– Cain
Jun 23 '15 at 19:55

Defender

Defender uses a new type of defense: The rockets are patrolling in front of the slots. This gives a huge advantage, since rockets live for 100 turns instead of 5 turns (like explosions).

package bots;

import mechanics.*;

public class Defender extends Bot {
int turn = 0;

@Override
public String name() {
return "Defender";
}

@Override
for (int i = 0; i < 3; i++) {
if ((grid[0][6+i] == null || grid[0][6+i].getDis().equals("v")) && (grid[1][6+i] == null || grid[1][6+i].getDis().equals("v")) && getSlot(i)) {
curSlot = i;
command.push(0);
for (int j = 0; j < 50; j++) {
command.push(0);
command.push(4);
}
break;
}
}

if (command.isEmpty()) {
if ((grid[0][9] == null || grid[0][9].getDis().equals("v")) && (grid[0][10] == null || grid[0][10].getDis().equals("v")) && (grid[1][10] == null || grid[1][10].getDis().equals("v")) && getSlot(2)) {
curSlot = 2;
command.push(1);
command.push(1);
command.push(4);
for (int i = 0; i < 50; i++) {
command.push(6);
command.push(2);
}
} else if ((grid[0][5] == null || grid[0][5].getDis().equals("v")) && (grid[0][4] == null || grid[0][4].getDis().equals("v")) && (grid[1][4] == null || grid[1][4].getDis().equals("v")) && getSlot(0)) {
curSlot = 0;
command.push(7);
command.push(7);
command.push(4);
for (int i = 0; i < 50; i++) {
command.push(2);
command.push(6);
}
}

}

if (command.isEmpty()) {
if (turn % 2 == 0 && getSlot(0)){
curSlot = 0;
command.push(7);
command.push(7);
for (int i = 0; i < 7; i++) {
command.push(0);
}
command.push(2);
for (int i = 0; i < 2; i++) {
if (Math.random() < 0.2) command.push(2);
}
command.push(1);
} else {
curSlot = 2;
command.push(1);
command.push(1);
for (int i = 0; i < 7; i++) {
command.push(0);
}
command.push(6);
for (int i = 0; i < 2; i++) {
if (Math.random() < 0.5) command.push(6);
}
command.push(7);
}
}

turn++;
return command;
}
}

• Wow +1 . Awesome bot. But as you say, fails to play good when the bot is on the other side. Jun 24 '15 at 11:57
• Pretty flawless play, congratualtions
– Cain
Jul 1 '15 at 18:34

Tortoise

If I protect all my bases, I have 3 points. Bases can only be attacked from 5 locations if I get the grid well. Rocket lasts 5 turn on the field...

This bot uses all of this to match its goal : surviving with at least 50% of the points in the pocket. It shoots 3 rockets, then cover itself

package bots;

public class Tortoise extends Bot
{
int turnCounter=-1;
boolean attacked=false;
int[] moves={7,0,0,0,1};
public String name(){return "Tortoise";}
{
turnCounter++;
if(!attacked)
{
curSlot=turnCounter;
for(int i=0;i<11;i++)
rocket.push(0);
if(turnCounter==2)
attacked=true;
return rocket;
}
turnCounter%=5;
switch(turnCounter)
{
case 0:
case 1:curSlot=0;break;
case 2:curSlot=1;break;
case 3:
case 4:curSlot=2;break;
default:break;
}
rocket.push(moves[turnCounter]);
return rocket;
}
}

• Rockets only fire every other turn, so you can really only maintain 2 and a half walls
– Cain
Jun 23 '15 at 19:14
• @Cain Oh, So i'll modify it to have a real shelter :) Jun 23 '15 at 19:17

SideShooter

First shoots via the first ( rightmost ) turret in one of two different ways. Then, it shoots via the last ( leftmost ) turret in one of two different ways. Then it makes a "wall" with the second ( middle ) turret by exploding rockets in front of each turret. This process is repeated.

If the game lasts for more than 30 turns, SideShooter grows bored and changes in a small way. Instead of making a "wall" with the second ( middle ) turret, it shoots straight. The rest of the turrets behave the same way.

import java.util.LinkedList;

public class SideShooter extends Bot {

int[] launcher = new int[]{1, 3, 2, 2, 2};
String[] right = {"1100000077", "100000007"};
String[] left  = {"7700000011", "700000001"};
int position = -1;
int turns = 0;

public String name(){
return "SideShooter";
}

if(getSlot(0) || getSlot(1) || getSlot(2))
do{
position = (position + 1) % 5;
curSlot = launcher[position] - 1;
}while(!getSlot(curSlot));

if(position == 0)
{
String shoot = left[((int) (Math.random() * left.length))];
for(int i=0; i < shoot.length(); i++)
directions.push(shoot.charAt(i)-'0');
}else if(position == 1)
{
String shoot = right[((int) (Math.random() * right.length))];
for(int i=0; i < shoot.length(); i++)
directions.push(shoot.charAt(i)-'0');
}else
{
if(turns < 30)
{
if(position == 2 )
directions.push(0);
else if(position == 3)
directions.push(1);
else if(position == 4)
directions.push(7);
}else
for(int i=0; i < 10; i++)
directions.push(0);
}
turns ++;
return directions;
}

}

• the do...while statement do an infinite loop... Jun 23 '15 at 12:32
• @guy777 , No it isn't. It loops until it find a not-broken turret. Jun 23 '15 at 12:33
• ok ! the two first time i launch the code with all bots, SideShooter and other bot (i don't know which) can't finish the game !!! Jun 23 '15 at 12:38
• Some games are unfinishable. The controller should have a turn limit. Jun 23 '15 at 12:43
• @CoolGuy I voted to approve his edit. Make sure to review/test it yourself. Jun 23 '15 at 16:12

Sniper

Sniper first blocks its two sides and then starts shooting straight.

import java.util.LinkedList;

public class Sniper extends Bot {

int[] launcher = new int[]{1, 3, 1, 2, 3};
String[] moves = {"7", "1", "0000000000", "0000000000", "0000000000"};
int position = -1, move = 0;

public String name(){
return "Sniper";
}

if(getSlot(0) || getSlot(1) || getSlot(2))
do{
position = (position + 1) % launcher.length;
curSlot = launcher[position] - 1;
}while(!getSlot(curSlot));

for(int i=0; i < moves[move].length(); i++)
directions.push(moves[move].charAt(i)-'0');

move = (move + 1) % moves.length;

return directions;
}

}

• See the comments on SideShooter, same issue here.
– Cain
Jun 23 '15 at 17:29

Three Shot

We got some weird shots flying. No true defense, but the pattern is such that it will be hard to get a shot past this bizarre hail of missiles. (or that is the idea. it most likely will not work.)

package bots;import java.util.*;import mechanics.*;

public class ThreeShot extends Bot{
public String name(){state = 0;return "3 Shot";}
private int state;

if(state < 2){
state++;
return fireLeft();
}
if(state < 4){
state++;
return fireCenter();
}
state=(state+1)%6;
return fireRight();
}
curSlot = 1;
while(command.size()<90){
command.push(1);
command.push(7);
command.push(6);
command.push(1);
}
return command;
}
curSlot = 2;
command.push(1);
for(int i=0;i<8;i++){
command.push(0);
}
command.push(7);
return command;
}
curSlot = 0;
command.push(7);
for(int i=0;i<8;i++){
command.push(6);
command.push(1);
}
command.push(1);
return command;
}
}


Note

MoreDakka

MoreDakka shoots in five directions without a stop (until turrets gets wrecked by other missiles).

import java.util.LinkedList;

public class MoreDakka extends Bot
{
String[] moves={"70000000001", "0000000000", "0000000000", "0000000000", "1000000007"};
int[] launcher = new int[]{0, 0, 1, 2, 2};
int position = -1;

public String name(){
return "MoreDakka";
}

{

if(getSlot(0) || getSlot(1) || getSlot(2))
do{
position = (position + 1) % launcher.length;
curSlot = launcher[position];
}while(!getSlot(curSlot));

for(int i=0; i < moves[position].length(); i++)
directions.push(moves[position].charAt(i)-'0');

return directions;
}
}


StraightShot

Just fire right at them.

package bots;import java.util.*;import mechanics.*;

public class StraightShot extends Bot{
public String name(){return "StraightShot";}

curSlot = (curSlot+1)%3;
for(int i=0;i<100;i++)
command.push(0);
return command;
}
}

• In case you weren't aware, this is basically the same as WaveBot, one of the example bots included with the controller. Jun 23 '15 at 17:59
• @Geobits I had no idea that example bots existed. Jun 23 '15 at 18:16
• My bad for not putting the Sample Bots somewhere easier to see. I'm just gonna delete WaveBot and let this entry stand
– Cain
Jun 23 '15 at 19:15

Here's my own entry

WallE

Shoots some offset rockets, and builds walls on his edges and center. After 100 turns, starts targeting the middle slot.

package bots;

import java.util.Random;

import mechanics.*;

public class WallE extends Bot {

int turn = 2;

public String name(){
return "Wall-E";
}

turn++;
curSlot = 1;
switch(turn%4){
case 0:
//Check the right wall
if(getSlot(2)){
curSlot = 2;
moves.push(1);
return moves;
}
case 1:
//Check the left wall
if(getSlot(0)){
curSlot = 0;
moves.push(7);
return moves;
}
case 2:
//Check the center wall
if(getSlot(1)){
curSlot = 1;
moves.push(0);
return moves;
}
break;
default:
//Fire a sneaky rocket
Random rand = new Random();
int direction = rand.nextInt(2);
int back = 0;
if(direction == 0 && getSlot(2)){ direction = 1; back = 7; curSlot = 2;}
else{ direction = 7; back = 1; curSlot = 0; }
moves.push(0);
moves.push(direction);
moves.push(direction);
for(int i = 0; i < 5; i++){
moves.push(0);
}

//Go for the center after turn 100
if(turn > 104){
moves.pop();
moves.push(back);
}
moves.push(back);
moves.push(back);

}

return moves;

}

}