8
\$\begingroup\$

I wrote a bot for a Programming Puzzles & Code Gold King of the Hill type of challenge called "Spacewar!". The challenge was written by @El'endiaStarman. The bot is called "Spy".

The controller is hosted here, so take a look for the feel. The API is a bit long, so here's a link.

The bot's logic:

It runs away from the other bot with a 70% chance of firing a missile and hyperspaces when it's close to the sun.

It's not online yet at a seperate bot; so you can copy-paste the code here into the KotH controller's text area at the bottom to test it out.

I sorta just monkey-patched this bot together without an IDE, so the code isn't that great. Seriously, there's even an extra function I didn't use.

The code

function Spy_setup(team) {
  // Typical setup. Nothing to see here. ;)
  var botVars = {};
  botVars["color"] = team;
  return botVars;
}


function Spy_getActions(gameInfo, botVars) {
    var actions = [];
    var us, them, red = {
            rotation: gameInfo.red_rot,
            x: gameInfo.red_x,
            y: gameInfo.red_y,
            alive: gameInfo.blue_alive
        },
        blue = {
            rotation: gameInfo.blue_rot,
            x: gameInfo.blue_x,
            y: gameInfo.blue_y,
            alive: gameInfo.blue_alive
        };
    if (botVars.color == "red") {
        us = red;
        them = blue;
    } else if (botVars.color == "blue") {
        us = blue;
        them = red;
    }

    function distance(x1, y1, x2, y2) {
        return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    }

    // Get our ship's position
    var rotation, x, y, opponentAlive;
    if (botVars.color == "red") {
        rotation = gameInfo.red_rot;
        x = gameInfo.red_x;
        y = gameInfo.red_y;
        opponentAlive = gameInfo.blue_alive;
    } else if (botVars.color == "blue") {
        rotation = gameInfo.blue_rot;
        x = gameInfo.blue_x;
        y = gameInfo.blue_y;
        opponentAlive = gameInfo.red_alive;
    }

    // Calculate our rotation compared to the sun in degrees
    var sunX = gameInfo.sun_x,
        sunY = gameInfo.sun_y,
        angle = Math.atan2(sunY - y, sunX - x) * 180 / Math.PI,
        rotationToSun = (rotation - angle + 360) % 360;

    // Check if we need to hyperspace to avoid the sun
    var rX = x - sunX,
        rY = y - sunY,
        distanceFromSun = Math.sqrt(rX * rX + rY * rY) - gameInfo.sun_r;
    if (distanceFromSun < 30) {
        actions.push("hyperspace");
        console.log("Command Module is Hyperspacing.")
    }
    if (gameInfo[botVars["color"] + "_alive"]) {
        var angle = Math.degrees(Math.atan2(them.y - us.y, them.x - us.x)),
            rotationToOpponent = (us.rotation - angle + 360) % 360;
        if (rotationToOpponent > 90 && rotationToOpponent < 270) {
            actions.push("turn right");
        } else {
            actions.push("turn left");
        };
        actions.push("fire engine");
        if (Math.random() > 0.3) {
            actions.push("fire missile")
        }
    }
}
\$\endgroup\$
12
\$\begingroup\$

Bugs

var us, them, red = {
        rotation: gameInfo.red_rot,
        x: gameInfo.red_x,
        y: gameInfo.red_y,
        alive: gameInfo.blue_alive
    },
    blue = {
        rotation: gameInfo.blue_rot,
        x: gameInfo.blue_x,
        y: gameInfo.blue_y,
        alive: gameInfo.blue_alive
    };

Red and blue are using the same alive variable.

Also...

if (distanceFromSun < 30) {
    actions.push("hyperspace");
    console.log("Command Module is Hyperspacing.")
}
if (gameInfo[botVars["color"] + "_alive"]) {

I don't think dead ships are supposed to hyperspace.

Licensing

When you use code from StackExchange, like from this answer to the PPCG challenge, you should at the very least add a comment referencing the original source.

Duplication

Without looking at the code in detail, I spot this bit of duplication:

var rotation, x, y, opponentAlive;
if (botVars.color == "red") {
    rotation = gameInfo.red_rot;
    x = gameInfo.red_x;
    y = gameInfo.red_y;
    opponentAlive = gameInfo.blue_alive;
} else if (botVars.color == "blue") {
    rotation = gameInfo.blue_rot;
    x = gameInfo.blue_x;
    y = gameInfo.blue_y;
    opponentAlive = gameInfo.red_alive;
}
if (gameInfo[botVars["color"] + "_alive"]) {

You should pick one style and stick with it. I think you could get rid of a lot of the duplication by using the second style:

var rotation, x, y, opponentAlive;
rotation = gameInfo[botVars.color + "_rot"];
x = gameInfo[botVars.color + "_x"];
y = gameInfo[botVars.color + "_y"];

Leaves us with the opponentAlive variable, though.

For that, I'd just go with a function getOppositeColor:

function getOppositeColor(ownColor){
    return ownColor === "blue" ? "red" : "blue";
}

And then we can get opponentAlive via

opponentAlive = gameInfo[getOppositeColor(botVars.color) + "_alive"];

Other weird things in your code are that you explicitly declare a distance function... and then you don't use it. You make objects for red and blue, but you don't use them and then extract values from gameInfo a second time...

You should get the variables once. Then use them. Make a single flow like that.

var actions = [];
var us, them, red = {
        rotation: gameInfo.red_rot,
        x: gameInfo.red_x,
        y: gameInfo.red_y,
        alive: gameInfo.red_alive
    },
    blue = {
        rotation: gameInfo.blue_rot,
        x: gameInfo.blue_x,
        y: gameInfo.blue_y,
        alive: gameInfo.blue_alive
    };
if (botVars.color == "red") {
    us = red;
    them = blue;
} else if (botVars.color == "blue") {
    us = blue;
    them = red;
}

This part, in that regard, is perfectly fine.

var rotation, x, y, opponentAlive;
if (botVars.color == "red") {
    rotation = gameInfo.red_rot;
    x = gameInfo.red_x;
    y = gameInfo.red_y;
    opponentAlive = gameInfo.blue_alive;
} else if (botVars.color == "blue") {
    rotation = gameInfo.blue_rot;
    x = gameInfo.blue_x;
    y = gameInfo.blue_y;
    opponentAlive = gameInfo.red_alive;
}

This entire part can go. It's not needed. You already have all of these variables as us.rotation, us.x, us.y, and them.alive.


    if (rotationToOpponent > 90 && rotationToOpponent < 270) {
        actions.push("turn right");
    } else {
        actions.push("turn left");
    };

Also, you don't need a semicolon to end this if-statement here.

\$\endgroup\$
  • \$\begingroup\$ I'm really bad at JS, thanks for the tips. Some of the code I copied from other bots. I put some of the stuff there to be compatible with other bot's code. \$\endgroup\$ – noɥʇʎԀʎzɐɹƆ Jul 18 '16 at 15:03
  • \$\begingroup\$ Also, in my answer I cited the two other bots I took code from. \$\endgroup\$ – noɥʇʎԀʎzɐɹƆ Jul 18 '16 at 15:09
  • 3
    \$\begingroup\$ You don't have a link to the answer anywhere in this question. \$\endgroup\$ – Pimgd Jul 18 '16 at 16:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.