Rey de la colina - Spacewar!

64

Si alguna vez has jugado Spacewar! , sabes que fue un juego divertido. Si no lo ha hecho, sepa esto: fue (y es) uno de los primeros y más importantes juegos de computadora. ¡Y sigue siendo divertido! El clon en el que crecí es este , que es, aparentemente y desafortunadamente, solo para Windows. ¡Entonces lo recreé!

El KotH está alojado aquí: PPCG - Spacewar! Rey de la colina . Te animo a que juegues como humano contra al menos otro bot para tener una idea de cómo funciona el juego.

El juego

  • Un cuadro es de 30 milisegundos (por lo tanto, alrededor de 33 cuadros por segundo).
  • El campo tiene 800 píxeles de ancho y 600 píxeles de alto.
  • El campo es toroidal, lo que significa que las naves espaciales y los misiles que se mueven fuera del campo reaparecen en el lado opuesto.
  • Hay dos naves espaciales, roja y azul.
    • El rojo se posiciona en x = 50 y aleatorio y entre 50, (altura del campo - 50) píxeles.
    • El azul se posiciona en x = (ancho del campo - 50) y aleatorio y entre 50, (altura del campo - 50) píxeles.
    • Ambas caras x = (ancho del campo) / 2.
  • Los controles disponibles son:
    • Gire a la izquierda - 5 grados por cuadro en sentido antihorario.
    • Gire a la derecha: 5 grados por cuadro en sentido horario.
    • Misil de fuego: viaja a 10 píxeles adicionales por cuadro, además de la velocidad de la nave, en la dirección en que apuntaba la nave.
    • Camión de bomberos: acelera la nave espacial a 0,30 píxeles por cuadro en la dirección en que apunta la nave espacial.
    • Salto en el hiperespacio: se teletransporta a algunas coordenadas aleatorias en el campo, con un 25% de posibilidades de explotar. Estas coordenadas aleatorias pueden estar encima del sol.
  • La velocidad máxima para los barcos es de 15 píxeles por cuadro bajo la potencia del motor y 40 píxeles por cuadro cuando aumenta la gravedad.
    • Al viajar a más de 15 píxeles por cuadro, el empuje del motor solo puede cambiar de dirección o reducir la velocidad.
  • En cuanto a los misiles:
    • Los misiles viajan en línea recta.
    • Los misiles pueden dispararse a una velocidad máxima de 1 por 0.1 segundos.
    • Los misiles tienen una vida útil de 2.25 segundos.
    • Los barcos tienen un máximo de 20 misiles cada uno.
    • Los misiles son partículas puntuales internamente.
  • Hay un sol en el centro que es extremadamente peligroso para su barco. El más mínimo contacto es fatal. Este sol también destruye misiles.
  • El sol tiene gravedad. La aceleración resultante es 5000 / (distancia ^ 2) píxeles / cuadro ^ 2, donde la distancia es en píxeles. Las naves espaciales y los misiles se ven afectados.
  • Ambas naves tienen tres zonas de ataque: la nariz, el ala izquierda y el ala derecha.
    • Un golpe en la nariz es la muerte instantánea.
    • Un golpe en cualquier ala reduce la velocidad de giro de la nave espacial y la aceleración del motor a la mitad.
    • Si se destruyen ambas alas, la nave espacial no se puede maniobrar y solo puede disparar misiles.
  • Los barcos pueden chocar entre sí.
    • Un impacto nariz-nariz es fatal para ambas naves.
    • Un impacto en el ala de la nariz destruye el ala.
    • Un impacto ala-ala destruye ambas alas.
  • Las naves muertas son sólidas y congeladas hasta que explotan 1 segundo después.
  • Después de que al menos una nave haya muerto, el campo se reinicia 3 segundos después. Hasta entonces, el sol y los misiles restantes siguen siendo peligrosos.

El juego original también tiene asteroides mortales e indestructibles, pero no los incluiré.

Las normas

  • Su bot debe estar escrito en JavaScript.
  • Su bot debe limitar su decisión a unos 10 milisegundos. Si noto un retraso constante debido a su bot , lo descalificaré y se lo haré saber para que pueda solucionarlo.
  • Los bots tendrán acceso a lo siguiente:
    • Ancho de campo y altura de campo
    • Posición del sol y radio
    • La posición, rotación, velocidad, forma, stock de misiles y estado dentro del hiperespacio de ambas naves
    • La posición y la velocidad de todos los misiles.
  • Cuando se le solicite, su bot debe devolver una lista de cadenas.
    • Estas cadenas deben ser uno de los siguientes: turn left, turn right, fire engine, fire missile, hyperspace. Cualquier otra cadena será ignorada.
    • Si hay duplicados, solo se anotará el primero.
    • hyperspace tiene prioridad sobre todos los demás.
    • turn lefty turn rightal mismo tiempo no tendrá efecto.
    • fire engine no tendrá efecto si la nave solo tiene la nariz o está muerta.
    • fire missile no tendrá efecto si un misil fue disparado demasiado recientemente.
  • En un cambio de lo habitual, su bot puede explotar el comportamiento de otros bots. Quiero alentar un metajuego.
    • Los bots no pueden emular a otros bots. (Es decir, no leer la mente).
    • Los bots no pueden establecer ninguna variable utilizada por el juego y el código de física. (Es decir, sin trampas).

Detalles de implementación del bot

Almacenaré su bot en su propio archivo JavaScript que se incluye automáticamente, con el nombre del archivo bot_<name>.js. Por lo tanto, no ponga espacios o caracteres que interfieran con esto o con el nombramiento de una función en JavaScript. Esto se debe a que debe definir las siguientes funciones: <name>_setup(team)y <name>_getActions(gameInfo, botVars). Más abajo en la página, existen áreas de texto para el robot de usuario , que puede editar para probar su código.

<name>_setup(team)

Esta función es para que usted defina las variables que desea persistir. teamserá cualquiera "red"o "blue". Esta función debe devolver un objeto. Defina variables así:

var vars = {};
vars['example'] = "example";
return vars;

Este varsobjeto se pasará a la otra función:

<name>_getActions(gameInfo, botVars)

botVarses el objeto devuelto por <name>_setup(team). gameInfoes un objeto que contiene las siguientes variables:

redScore
blueScore
timeLeft

fieldWidth
fieldHeight

sun_x
sun_y
sun_r //sun's radius

gravityStrength //acceleration in pixels/frame^2 at 1 pixel away from the sun's center
engineThrust    //acceleration in pixels/frame^2

speedLimit //maximum speed under engine power
maxSpeed   //maximum speed from gravity boosts

red_x
red_y
red_rot          //rotation in degrees
red_xv           //x velocity
red_yv           //y velocity
red_shape        //one of "full ship", "left wing", "right wing", "nose only"
red_missileStock //the number of missiles red has left
red_inHyperspace //true if red is in hyperspace
red_exploded     //until red explodes, it is still solid and hazardous
red_alive
// likewise for blue //

numMissiles
missiles //this is a list of objects, each with the following variables
  x
  y
  xv
  yv

Su bot tiene acceso completo a estos. Estoy bastante seguro de que puede escribirles y no afectar las variables originales, pero no lo haga de todos modos. Una nota sobre las rotaciones: las naves apuntan en la dirección + y, hacia abajo, por lo que cualquier cosa que desee alinear con la nave debe compensarse 90 grados. Además, la rotación positiva es en sentido horario.

Esta función debe devolver una lista de cadenas, que representa las acciones de su bot. Por ejemplo, ["turn right","thrust"]. Más detalles sobre esto están en la sección de Reglas .

Detalles adicionales

También puede hacer uso de lo siguiente:

LineIntersection(L1, L2)

L1 y L2 son matrices de dos elementos de matrices de dos elementos. Es decir, L1 := [[x1,y1],[x2,y2]]y L2 := [[u1,v1],[u2,v2]]. Esta función calcula la intersección de dos líneas y devuelve la siguiente: [[x,y], [a,b]]. [x,y]son las coordenadas del punto de intersección y [a,b]son un par de relaciones que expresan qué tan lejos está el punto de intersección a lo largo de cada línea. Al igual que en, a = 0.25significaría que el punto de intersección es una cuarta parte del camino de [x1,y1]a [x2,y2], y lo mismo para b. Si no hay intersección, se devuelve una matriz vacía.

window["shipShapes"]

var shipShapes = {
    'full ship': [[-8,16],[0,-8],[8,16]],
    'left wing': [[-8,16],[0,-8],[4,4],[0,8],[0,16]],
    'right wing':[[-4,4],[0,-8],[8,16],[0,16],[0,8]],
    'nose only': [[-4,4],[0,-8],[4,4],[0,8]]
};

Estas son las coordenadas de los polígonos de los barcos. Para facilitar la obtención de las coordenadas actuales, también puede usar ...

getShipCoords(<color>)

getShipCoords("red")devolverá las coordenadas actuales de los vértices de la nave de Rojo, y de la misma manera para getShipCoords("blue")Azul. Estas coordenadas están en una lista de este modo: [[x1,y1],[x2,y2],[x3,y3],...]. Los polígonos están implícitamente cerrados, por lo que hay una línea entre el primer y el último par de coordenadas.

No puede acceder ni alterar ninguna otra variable o función en uso por el juego / sitio web. Y definitivamente no nombres tus funciones de la misma manera. No preveo que esto sea un problema, pero si su bot rompe el código del juego, esa es una posibilidad. No hay registro ni captura de excepciones.

Victorioso

  • Cada emparejamiento de bots se jugará al menos 10 veces, en ambos sentidos. (Entonces, al menos 20 juegos en total).
  • Trata de tener la mayor proporción de victorias / derrotas en general . Si su bot funciona muy bien contra otro bot, pero pierde contra los otros tres, eso no es tan bueno como ganar contra dos y perder contra dos (como regla general).
  • Para cada bot, se calcularán las razones (victorias + 1) / (pérdidas + 1), luego se calculará la media y la desviación estándar de estas relaciones. Una media más alta tendrá prioridad, y en caso de que las medias estén dentro de 1 unidad entre sí, la varianza más baja tendrá prioridad.
  • La puntuación comenzará en una semana a partir de hoy o después de tres días sin nuevas presentaciones. Esto es para que no tenga que repetir ningún emparejamiento de bots.

Sobre todo, ¡diviértete!


Clasificación (2016-01-08 05:15):

#   Name                       Mean      StdDev
1.  Helios                     13.625    6.852
2.  EdgeCase                    8.335    8.155
3.  OpponentDodger              8.415    8.186
4.  OrbitBot                    5.110    6.294
5.  SunAvoider                  5.276    6.772
6.  DangitBobby                 3.320    4.423
7.  SprayAndPray                3.118    4.642
8.  Engineer                    3.903    6.315
9.  RighthandedSpasms           1.805    2.477
10. AttackAndComeBack           2.521    2.921
11. PanicAttack                 2.622    3.102
12. FullSpeedAhead              2.058    3.295
13. UhhIDKWhatToCallThisBot     2.555    3.406
14. MissilesPlusScore           0.159    0.228
15. Hyper                       0.236    0.332
16. RandUmmm                    0.988    1.329
17. Kamikaze                    0.781    1.793

Nota: Esto está sujeto a cambios a medida que corro más juegos. Además, el orden de los rangos 9-13 me molesta, por lo que puedo ajustar el método de puntuación para que coincida mejor con la intuición de cómo deben clasificarse.

(Las medias y las desviaciones estándar se redondearon a tres dígitos decimales. Además, Hyperdebería ser HYPERpero eso estropea el resaltado.: P)

El'endia Starman
fuente
¿Algún puntaje? ...
ev3commander
¿Registra excepciones capturadas?
TheNumberOne
1
Debe especificar que llamar LineIntersectiona segmentos que no se cruzan devuelve una matriz vacía.
LegionMammal978
1
Creo que lo hice!
ev3commander
3
@CrazyPython: disputaría los dos primeros considerando que básicamente copié un juego, pero el tercero es exactamente lo que quería. ¡Gracias! : D
El'endia Starman

Respuestas:

12

Helios

Este bot es el centro del universo, o al menos él cree que lo es. Lo primero que hace es corregir un error grave y colocarse en el centro del sistema de coordenadas. Luego gira cualquier cosa a su alrededor.

No le gusta el otro sol (falso), por lo tanto, trata de mantenerse alejado de él. Tampoco le gustan otros bots, por lo tanto, les dispara si está en una buena posición de disparo.

function Helios_setup(team) {
    var botVars = {};
    botVars.myPrefix = team + "_";
    botVars.enemyPrefix = team == "red" ? "blue_" : "red_";
    return botVars;
}

function Helios_getActions(gameInfo, botVars) {
    var actions = [];
    var halfPi = Math.PI / 2;
    var engageAngle = Math.PI / 8;

    var field = {};
    field.width = gameInfo.fieldWidth;
    field.height = gameInfo.fieldHeight;
    field.halfWidth = field.width / 2;
    field.halfHeight = field.height / 2;
    field.posOffsetX = field.width * 3 / 2 - gameInfo[botVars.myPrefix + "x"];
    field.posOffsetY = field.height * 3 / 2 - gameInfo[botVars.myPrefix + "y"];
    field.posAngle = (450 - gameInfo[botVars.myPrefix + "rot"]) % 360 * Math.PI / 180;
    field.posSin = Math.sin(-field.posAngle);
    field.posCos = Math.cos(-field.posAngle);
    field.movOffsetXV = -gameInfo[botVars.myPrefix + "xv"];
    field.movOffsetYV = gameInfo[botVars.myPrefix + "yv"];
    field.movAngle = Math.atan2(-field.movOffsetYV, -field.movOffsetXV);
    field.movSin = Math.sin(-field.movAngle);
    field.movCos = Math.cos(-field.movAngle);

    function zeroIfUndefined(v) {
        return v === undefined ? 0 : v;
    }

    function sqr(x) {
        return x * x
    }

    function getEntity(source, prefix) {
        var tmpX = (field.posOffsetX + zeroIfUndefined(source[prefix + "x"])) % field.width - field.halfWidth;
        var tmpY = field.halfHeight - (field.posOffsetY + zeroIfUndefined(source[prefix + "y"])) % field.height;
        var tmpXV = zeroIfUndefined(source[prefix + "xv"]);
        var tmpYV = -zeroIfUndefined(source[prefix + "yv"]);
        var e = {};
        e.posX = tmpX * field.posCos - tmpY * field.posSin;
        e.posY = tmpX * field.posSin + tmpY * field.posCos;
        e.posR = Math.sqrt(sqr(e.posX) + sqr(e.posY));
        e.posPhi = Math.atan2(e.posY, e.posX);
        e.posXV = tmpXV * field.posCos - tmpYV * field.posSin;
        e.posYV = tmpXV * field.posSin + tmpYV * field.posCos;
        e.posV = Math.sqrt(sqr(e.posXV) + sqr(e.posYV));
        e.movX = tmpX * field.movCos - tmpY * field.movSin;
        e.movY = tmpX * field.movSin + tmpY * field.movCos;
        e.movR = Math.sqrt(sqr(e.movX) + sqr(e.movY));
        e.movPhi = Math.atan2(e.movY, e.movX);
        e.movXV = (tmpXV + field.movOffsetXV) * field.movCos - (tmpYV + field.movOffsetYV) * field.movSin;
        e.movYV = (tmpXV + field.movOffsetXV) * field.movSin + (tmpYV + field.movOffsetYV) * field.movCos;
        return e;
    }

    function getShip(prefix) {
        var ship = getEntity(gameInfo, prefix);
        ship.missileStock = gameInfo[prefix + "missileStock"];
        ship.inHyperspace = gameInfo[prefix + "inHyperspace"];
        ship.exploded = gameInfo[prefix + "exploded"];
        ship.alive = gameInfo[prefix + "alive"];
        return ship;
    }

    var myShip = getShip(botVars.myPrefix);
    myShip.movAngle = (field.posAngle - field.movAngle + 3 * Math.PI) % (2 * Math.PI) - Math.PI;
    var enemyShip = getShip(botVars.enemyPrefix);
    var sun = getEntity(gameInfo, "sun_");

    enemyShip.intersectionLine = [[enemyShip.movX - enemyShip.movXV * 30, enemyShip.movY - enemyShip.movYV * 30],
            [enemyShip.movX + enemyShip.movXV * 30, enemyShip.movY + enemyShip.movYV * 30]];

    var intersection = LineIntersection([[0, 0], [Math.cos(myShip.movAngle) * 10 * 30, Math.sin(myShip.movAngle) * 10 * 30]],
            enemyShip.intersectionLine);
    if (intersection.length == 2) {
        myShip.intersection = Math.abs(intersection[1][0] / 2 + 0.5 - intersection[1][1]);
    }
    intersection = LineIntersection([[0, 0], [Math.cos(myShip.movAngle - 0.001) * 10 * 30, Math.sin(myShip.movAngle - 0.001) * 10 * 30]],
            enemyShip.intersectionLine);
    if (intersection.length == 2) {
        myShip.intersectionLeft = Math.abs(intersection[1][0] / 2 + 0.5 - intersection[1][1]);
    }
    intersection = LineIntersection([[0, 0], [Math.cos(myShip.movAngle + 0.001) * 10 * 30, Math.sin(myShip.movAngle + 0.001) * 10 * 30]],
            enemyShip.intersectionLine);
    if (intersection.length == 2) {
        myShip.intersectionRight = Math.abs(intersection[1][0] / 2 + 0.5 - intersection[1][1]);
    }

    function danger() {
        var tmp1 = sqr(sun.movXV) + sqr(sun.movYV);
        var tmp2 = tmp1 == 0 ? 0 : Math.max(0, Math.min(1, ((-sun.movX) * sun.movXV + (-sun.movY) * sun.movYV) / tmp1));
        var dis = Math.sqrt(sqr(sun.movX + tmp2 * sun.movXV) + sqr(sun.movY + tmp2 * sun.movYV));
        if (dis < 30) {
            return true;
        }
        var shipLine1 = [[-16, 8], [-16, -8]];
        var shipLine2 = [[-16, 8], [8, 0]];
        var shipLine3 = [[-16, -8], [8, 0]];
        if (gameInfo.missiles !== undefined) {
            for (var i = 0; i < gameInfo.missiles.length; i++) {
                var missile = getEntity(gameInfo.missiles[i], "");
                var missileLine = [[missile.movX + missile.movXV * 0.5, missile.movY + missile.movYV * 0.5],
                        [missile.movX + missile.movXV * 3, missile.movY + missile.movYV * 3]];
                if (LineIntersection(shipLine1, missileLine).length == 2 ||
                        LineIntersection(shipLine2, missileLine).length == 2 ||
                        LineIntersection(shipLine3, missileLine).length == 2) {
                  return true;
                }
            }
        }
        return false;
    }

    function fire() {
        return enemyShip.alive && !enemyShip.inHyperspace && myShip.intersection !== undefined &&
            myShip.intersection < 0.1 + myShip.missileStock / 200;
    }

    function evadeSun() {
        if ((sun.movPhi >= 0 && myShip.movAngle < 0) || (sun.movPhi <= 0 && myShip.movAngle > 0)) {
            actions.push("fire engine");
        }
        if (sun.movPhi > 0) {
            if (Math.abs(myShip.movAngle) < halfPi) {
                actions.push("turn right");
            } else {
                actions.push("turn left");
            }
        } else {
            if (Math.abs(myShip.movAngle) < halfPi) {
                actions.push("turn left");
            } else {
                actions.push("turn right");
            }
        }
    }

    function aim() {
        if (myShip.intersection !== undefined && myShip.intersectionLeft !== undefined && myShip.intersectionLeft < myShip.intersection) {
            actions.push("turn left");
        } else if (myShip.intersection !== undefined && myShip.intersectionRight !== undefined && myShip.intersectionRight < myShip.intersection) {
            actions.push("turn right");
        } else {
            if (enemyShip.posPhi > 0) {
                actions.push("turn left");
            } else {
                actions.push("turn right");
            }
        }
        if (myShip.posV < 2 || (enemyShip.alive && (enemyShip.movXV >= 0 || myShip.missileStock == 0))) {
            actions.push("fire engine");
        }
    }

    function brake() {
        if (myShip.movAngle > 0) {
            actions.push("turn left");
        } else {
            actions.push("turn right");
        }
        if (Math.abs(myShip.movAngle) > Math.PI * 3 / 4) {
            actions.push("fire engine");
        }
    }

    function engage() {
        if (enemyShip.missileStock > 0) {
            if ((enemyShip.posPhi > 0 && enemyShip.posPhi < engageAngle) || enemyShip.posPhi < -engageAngle) {
                actions.push("turn right");
            } else {
                actions.push("turn left");
            }
        } else {
            if (enemyShip.posPhi > 0) {
                actions.push("turn left");
            } else {
                actions.push("turn right");
            }
        }
        actions.push("fire engine");
    }

    if (myShip.alive && !myShip.inHyperspace) {
        if (danger()) {
            actions.push("hyperspace");
        }
        if (fire()) {
            actions.push("fire missile");
        }
        if (enemyShip.exploded || enemyShip.inHyperspace || sun.movR < 150 || (sun.movR < 300 && Math.abs(sun.movPhi) < Math.PI)) {
            evadeSun();
        } else if (enemyShip.posR < 300 || myShip.intersection !== undefined) {
            aim();
        } else if (myShip.posV > 10) {
            brake();
        } else {
            engage();
        }
    }

    return actions;
}
Sleafar
fuente
1
Creo que este es uno de mis bots favoritos hasta ahora. ¡Es sorprendentemente bueno!
El'endia Starman
@ El'endiaStarman Hice algunas actualizaciones al bot.
Sleafar
¡Tu actualización ya está en vivo!
El'endia Starman
Esto funciona muy bien contra OrbitBot :)
TheNumberOne
1
@Soaku Creo que la principal diferencia entre este bot y la mayoría de los demás es que este bot apunta a su oponente antes de disparar.
Sleafar
9

SunAvoider

Este solo trata de mantenerse alejado del sol. Lo hace bastante bien ... hasta que destruye una o ambas alas, por lo general, es solo cuestión de tiempo antes de que caiga.

function SunAvoider_setup(team) {
    var botVars = {};

    botVars["color"] = team;

    return botVars;
}

function SunAvoider_getActions(gameInfo, botVars) {
    var actions = [];

    if (gameInfo[botVars["color"]+"_alive"]) {
        var shipx = gameInfo[botVars["color"]+"_x"];
        var shipy = gameInfo[botVars["color"]+"_y"];
        var sunx = gameInfo["sun_x"];
        var suny = gameInfo["sun_y"];
        var dx = shipx - sunx;
        var dy = shipy - suny;
        var dis = Math.sqrt(dx*dx+dy*dy);
        var fireEngineChance = (dis-100)/(gameInfo["fieldHeight"]/2);

        if (Math.random() > fireEngineChance){ actions.push("fire engine") }

        var ang1 = gameInfo[botVars["color"]+"_rot"]+90;
        var ang2 = Math.degrees( Math.atan2(dy, dx) );
        var angDiff = ang2 - ang1;
        if (angDiff < -180) { //http://stackoverflow.com/a/7869457/1473772
            angDiff += 360;
        } else if (angDiff > 180) {
            angDiff -= 360;
        }

        if (angDiff >= 0) {
            actions.push("turn left");
        } else if (angDiff < 0) {
            actions.push("turn right");
        }
    }

    return actions;
}
El'endia Starman
fuente
9

Caso extremo

¡Vuela a toda velocidad lejos del sol hacia el borde del mapa! Cuando se encuentra apuntando hacia el sol, comenzará a disparar mientras se aleja para volver al borde. También ingresa al hiperespacio cuando está a punto de golpear el sol.

function EdgeCase_setup(team) {
  var botVars = {};
  botVars["color"] = team;
  return botVars;
}

function EdgeCase_getActions(gameInfo, botVars) {
  var actions = [];

  // 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");
  else {

    // Turn away from the sun
    if(rotationToSun > 90 && rotationToSun < 270) {
      actions.push("turn right");
    }
    else actions.push("turn left");

    // Fire engines if we're pointing away from the sun
    if(rotationToSun > 180) {
      actions.push("fire engine");
    }

    // If we shoot while our opponent's dead we can only kill ourself
    else if(opponentAlive) actions.push("fire missile");
  }

  return actions;
}
usuario81655
fuente
¡Este bot ya está en vivo! Además, este fue sorprendentemente fácil de sobrevivir. Probablemente tiene que ver con cómo no envía spam a misiles en todas partes, como algunos de los otros. : P
El'endia Starman
7

OrbitBot

Actualmente no tiene objetivos ni evita colisiones . Intenta orbitar el sol.

Editar: ahora entra en el hiperespacio cuando el impacto es inminente.

function OrbitBot_setup(team) {
  var botVars = {};

  botVars.color = team;
  return botVars;
}


function OrbitBot_getActions(gameInfo, botVars) {
  var actions = [];

  function getVar(name) {
    return gameInfo[botVars.color + "_" + name];
  }

  function getEnemyVar(name) {
    var eColor;
    if (botVars.color == 'blue') {
        eColor = 'red';
    } else {
        eColor = 'blue';
    }
    return gameInfo[eColor + "_" + name];
  }

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

  function toroidDistance(x1, y1, x2, y2) {
    dx = Math.abs(x1 - x2);
        while (dx > gameInfo.fieldWidth) {
        dx -= gameInfo.fieldWidth;
    }
    dx = Math.min(dx, gameInfo.fieldWidth - dx);
    dy = Math.abs(y1 - y2);
        while (dx > gameInfo.fieldHeight) {
        dx -= gameInfo.fieldHeight;
    }
    dy = Math.min(dy, gameInfo.fieldHeight - dy);
    return Math.sqrt(dx*dx+dy*dy);
  }

  function angleDistance(theta1, theta2) {
    var d = theta1 - theta2;
    while (d < 0 || d > Math.PI) {
      if (d < 0) {
        d += Math.PI * 2;
      }
      if (d > Math.PI * 2) {
        d -= Math.PI * 2;
      } else if (d > Math.PI) {
        d = Math.PI * 2 - d;
      }
    }
    return d;
  }

  function toRad(degrees) {
    return degrees / 180 * Math.PI;
  }

  function cap(x, y, limit) {
    var r = x*x+y*y;
    if (r < limit * limit) {
        r = Math.sqrt(r);
        x = x * r / limit;
      y = y * r / limit;
    }
    return [x,y];
  }

  var shape = getVar('shape');

  if (shape != 'nose only') {
    var broken = shape != 'full ship';
    var sunX = gameInfo.sun_x,
      sunY = gameInfo.sun_y,
      sunG = gameInfo.gravityStrength;

    function desirability(x, y, vx, vy) {     //Borrowed from a useless bot.
      var lowest = distance(x, y, sunX, sunY) - 5;
      var missiles = gameInfo.missiles;
      for (var i = 0; i < missiles.length; i++) {
        var mx = missiles[i].x + missiles[i].xv / 2;
        var my = missiles[i].y + missiles[i].yv / 2;
        lowest = Math.min(lowest, toroidDistance(x, y, mx, my) - distance(0, 0, missiles[i].xv, missiles[i].yv));
      }
      return lowest - 16;
    }

    var x = getVar("x"),
      y = getVar("y"),
      vx = getVar("xv"),
      vy = getVar("yv");

    function desirabilityByAcceleration(ax, ay) {//Borrowed from a useless bot.
        var x1 = x,
            y1 = y,
          vx1 = vx,
          vy1 = vy;
      var speed = distance(0,0,vx1,vy1);
      var limit = Math.max(gameInfo.speedLimit, speed);

      vx1 += ax;
      vy1 += ay;
      var temp = cap(vx1, vy1, limit);
      vx1 = temp[0];
      vy1 = temp[1];


      var dx = x1 - sunX;
      var dy = y1 - sunY;
      var dis = Math.sqrt(dx*dx+dy*dy);
      if (dis > 5){
        var force = sunG / (dis * dis);
      } else {
        var force = sunG /5;
      }
      vx1 -= force*dx/dis;
      vy1 -= force*dy/dis;

      var temp = cap(vx1, vy1, 40);
      vx1 = temp[0];
      vy1 = temp[1];

      x1 += vx1;
      y1 += vy1;

      return desirability(x1, y1, vx1, vy1);
    }

    var r = distance(sunX, sunY, x, y);
    var theta = Math.atan((y - sunY) / (x - sunX));

    var sunA = sunG/r/r,
            sunAx = -Math.cos(theta) * sunA,
        sunAy = -Math.sin(theta) * sunA;

    var dv = Math.sqrt(sunG / r);
    var dvx = -dv * Math.sin(theta);
    var dvy = dv * Math.cos(theta);
    if (distance(-dvx, -dvy, vx, vy) < distance(dvx, dvy, vx, vy)) {
      dvx = -dvx;
      dvy = -dvy;
    }

    var dax = dvx - vx;
    var day = dvy - vy;

    var dAngle = Math.atan(day / dax);
    if (dax < 0) {
        dAngle += Math.PI;
    }
    var cAngle = toRad(getVar('rot') - 90);
    var dLeft = angleDistance(cAngle - toRad(broken ? 2.5 : 5), dAngle);
    var dRight = angleDistance(cAngle + toRad(broken ? 2.5 : 5), dAngle);
    var dNeither = angleDistance(cAngle, dAngle);
    if (dLeft < dRight && dLeft < dNeither) {
      actions.push('turn left');
    } else if (dRight < dLeft && dRight < dNeither) {
      actions.push('turn right');
    }

    var cax = Math.cos(cAngle) * (broken ? .15 : .3);
    var cay = Math.sin(cAngle) * (broken ? .15 : .3);

    var ax = 0;
    var ay = 0;

    if (distance(cax, cay, dax, day) < distance(0, 0, dax, day)) {
      actions.push('fire engine');
      ax = cax;
      ay = cay;
    }

    if (desirabilityByAcceleration(ax, ay) <= 16) {
        actions.push('hyperspace');
    }

  }

  return actions;
}
El numero uno
fuente
Su bot ha sido agregado.
Conor O'Brien
¡Tu actualización ya está en vivo!
El'endia Starman
5

Espasmos diestros

El nombre es bastante descriptivo. Elige turn rightcon 0.5 probabilidad, fire enginecon 0.5 probabilidad y fire missilecon 0.8 probabilidad. Sorprendentemente difícil, principalmente porque es realmente impredecible.

function RighthandedSpasms_setup(team) {
    var botVars = {};

    botVars["color"] = team;

    return botVars;
}

function RighthandedSpasms_getActions(gameInfo, botVars) {
    var actions = [];

    if (gameInfo[botVars["color"]+"_alive"]) {
        if (Math.random() > 0.5) { actions.push("turn right") }
        if (Math.random() > 0.5) { actions.push("fire engine") }
        if (Math.random() > 0.8) { actions.push("fire missile") }
    }

    return actions;
}
El'endia Starman
fuente
5

RandUmmm

Este desafío necesitaba un bot aleatorio. ¿Puntos de bonificación por golfiness?

function RandUmmm_setup(t){
    function P(n,t,r,o,e,f,g){for(o=[e=1<<(f=n.length)];e;)for(t=e.toString(2),r=g=t.length,o[--e]=[];r;)~-t[--r]||o[e].push(n[r+f-g]);return o}var q=P(["fire missile","turn right","fire engine","turn left"]);q.pop();
    return {color:t,m:function(){return q[Math.random()*q.length|0]}};
}

function RandUmmm_getActions(g,b){
    return b.m();
}
Conor O'Brien
fuente
¡Bueno! (Por cierto, mi bot ganó 13-7. No por mucho, considerando que perdí 9-1 una vez, pero eso es un montón de puntos en total. ¡20 puntos en 90 segundos!)
ev3commander
@ BlockCoder1392 es un bot aleatorio;)
Conor O'Brien
4

Ingeniero

Le gusta usar el hiperespacio cuando está en peligro. Para ver su verdadero poder, abra la consola de su navegador y escriba overideHyperspace = 0;. Si olvida el punto y coma, obtendrá ASI para Navidad.

function Engineer_setup(t){
    return{c:t,C:"red0blue".split(0)[+(t=="red")]};
}

function Engineer_getActions(gameInfo,botVars){
    var actions = [];

    function d(x1,y1,x2,y2){return Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))}
    function hS(g){return d(g.sun_x,g.sun_y,g[botVars.c+"_x"],g[botVars.c+"_y"])<50}
    function enemyDist(g){return d(g[botVars.c+"_x"],g[botVars.c+"_y"],g[botVars.C+"_x"],g[botVars.C+"_y"]);}

    function hSm(g){
        // get closest missile
        var r = (g.missiles||[{x:10000,y:10000}]).reduce(function(p,c){return Math.min(d(c.x,c.y,g[botVars.c+"_x"],g[botVars.c+"_y"]),p)},Infinity);
        return r<18;
    }
    function dF(g){
        var a = Math.degrees(Math.atan2(g[botVars.C+"_y"]-g[botVars.c+"_y"],g[botVars.C+"_x"]-g[botVars.c+"_x"]));
        var tP = (g[botVars.c+"_rot"]+360-a)%360;
        return [a,tP];
    }
    function lOr(g){
        var tP = dF(g)[1];
        return 90<tP&&tP<270?"turn left":"turn right";
    }
    function thrust(g){
        return Math.abs(dF(g)-g[botVars.c+"_rot"]);
    }

    // are we too close to the sun or a missile?
    if(hS(gameInfo)||hSm(gameInfo))actions.push("hyperspace");

    // should we fire?
    if(enemyDist(gameInfo)<200)actions.push("fire missile");

    // direction function
    actions.push(lOr(gameInfo,botVars));

    if(Math.random()<.7)actions.push("fire engine");
    return actions;
}
Conor O'Brien
fuente
3

Rociar y rezar

function SprayAndPray_setup(team) {
    var botVars = {};
    botVars["color"] = team;
    return botVars;
}

function SprayAndPray_getActions(gameInfo, botVars) {
    var actions = [];

    if (gameInfo[botVars["color"]+"_alive"]) {
        actions.push("turn left");
        if (Math.random() > 0.5) { actions.push("fire engine")};
       actions.push("fire missile");
    }

    return actions;
}

Dispara salvajemente en todas las direcciones. ¡No es muy efectivo!

Jack Brounstein
fuente
¡Este bot ya está en vivo!
El'endia Starman
3

Kamikaze

No es muy competitivo, ¡pero pensé que sería divertido! Simplemente vuela directamente hacia su oponente mientras dispara.

function Kamikaze_setup(team) {
  var botVars = {};
  botVars["color"] = team;
  return botVars;
}

function Kamikaze_getActions(gameInfo, botVars) {
  var actions = [];

  // Get our ship's position
  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;
  }

  // Turn towards our opponent's position
  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 left");
  }
  else actions.push("turn right");

  actions.push("fire missile", "fire engine");

  return actions;
}
usuario81655
fuente
Su bot ha sido agregado!
Conor O'Brien
Terrible contra el oponente Dodger ... Atado con PanicAttack ...
noɥʇʎԀʎzɐɹƆ
2

UhhIDKWhatToCallThisBot

Solo cosas al azar.

function UhhIDKWhatToCallThisBot_setup(team) {
var botVars = {};
 botVars['t'] = 0;
botVars["color"] = team;
     return botVars;

}

function UhhIDKWhatToCallThisBot_getActions(gameInfo, botVars) {
    var actions = [];
    //when i need it: "turn left",
    //Use missiles sparingly!
    var WCID = [
    "fire engine",
     "turn right",
    "fire engine",
    "fire missile",
    "turn right",
    "fire engine"]

    if (gameInfo[botVars["color"]+"_alive"]) {
        botVars['t']++;
        actions.push(WCID[botVars[t]%(WCID.length)]);
    }
     return actions;
}
ev3commander
fuente
¿Qué pasa con el golfismo críptico?
noɥʇʎԀʎzɐɹƆ
2

Oponente Dodger

LEJOS DE MI OPONENTE!

function OpponentDodger_setup(t){b={};b["c"]=t;b['o']=(t=="red")?"blue":"red";return b;}function OpponentDodger_getActions(g,b){a=[];o=b["c"];j={r:g[o+"_rot"],x:g[o+"_x"],y:g[o+"_y"]};o=b["o"];p={r:g[o+"_rot"],x:g[o+"_x"],y:g[o+"_y"]};l=Math.degrees(Math.atan2(p.y-j.y,p.x-j.x)),x=(j.r-l+360)%360;if(x > 90 && x < 270)a.push("turn right");else a.push("turn left");a.push("fire engine");return a;}  

¡Gracias a user81655 por algún código!

ev3commander
fuente
¡Este bot ya está en vivo!
El'endia Starman
2

Espía

La historia

El prototipo de este bot era un bot que tenía dos modos: modo loco y modo normal. Cuando estaba en modo loco, permaneció allí durante un número constante de tics. Había una probabilidad constante de entrar en modo loco. También se hiperespaciaba cuando estaba cerca del sol. En modo loco, apuntó al otro bot y disparó constantemente. En modo normal, voló lejos del otro bot, no disparando.

Ajusté ese prototipo para que estuviera en modo loco si y solo si el enemigo estaba lo suficientemente cerca. Entonces tuve una idea loca: ¿qué pasaría si solo se quedara en modo loco? Después de experimentar un poco (agregué hacer que el bot se disparara aleatoriamente cuando estaba en modo normal) me encontré con un nuevo bot que venció a todos los bot excepto a Helios. Este es mi código al final de este proceso, pero antes de limpiarlo.

Escribí todo mi bot en el área de texto KotH o el embellecedor JS. (Utilicé brevemente el editor Atom al limpiar, pero como dos líneas de código)

El bot

Este bot contiene una gran cantidad de código prestado de otros bots. Voltea el código de Kamikaze para huir del otro bot en lugar de correr hacia el otro bot y toma el código de EdgeCase para hiperespacio cuando está cerca del sol.

Su archienemigo es Helios. Siendo el extraño y largas conversaciones con un martini.

Se escapa del otro bot con un 70% de posibilidades de disparar un misil e hiperespacios cuando está cerca del sol. Tan sencillo como eso. Sí.

Editar: probé mi bot con el nuevo código y falla para cualquier otro bot. Estoy trabajando en arreglarlo. Acabo de confirmar que esto es solo para mi nuevo bot.

El código

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")
        }

    }
    return actions;
}

El misceláneo

Nota: Podría haber roto algo al limpiar el código porque no probé el bot después de limpiar el código.

También es mucho, mucho, mucho mejor que todos mis otros bots: en realidad venció a cualquier otro bot, excepto Helios (editar) , SetCourseFor30Degrees y OrbitBot. Se vincula con SunAvoider.

Nota al margen: soy horrible en javascript, no sé por qué.

noɥʇʎԀʎzɐɹƆ
fuente
@ El'endiaStarman, por favor, pon el pausa en vivo; Necesito arreglar mi bot: la versión limpia es mucho peor que la versión sucia.
noɥʇʎԀʎzɐɹƆ
Muy bien, avísame cuando esté arreglado.
El'endia Starman
@ El'endiaStarman Hice algo y luego funcionó nuevamente. Depuración, ya sabes! (no hecho aún)
noɥʇʎԀʎzɐɹƆ
@ El'endiaStarman ... ¡y listo!
noɥʇʎԀʎzɐɹƆ
¡Este bot ya está en vivo!
El'endia Starman
1

AttackAndComeBack

En lugar de girar, entra en la parte superior y sale en la parte inferior (regresa en la parte superior), disparando muy rápidamente. Generalmente evita el sol.

function AttackAndComeBack_setup(team) {
    var botVars = {};
    botVars["color"] = team;
    return botVars;
}

function AttackAndComeBack_getActions(gameInfo, botVars) {
    var actions = [];
    actions.push("fire missile");
    if (Math.random()>0.4){actions.push("turn right");}
    else {actions.push("turn left");}
    actions.push("fire engine");
    return actions;
}
noɥʇʎԀʎzɐɹƆ
fuente
¡Este bot ya está en vivo!
El'endia Starman
1

Máxima velocidad adelante

Siempre dispara tanto los motores como los misiles sin girar nunca. A veces dura sorprendentemente mucho antes de golpear el sol.

function FullSpeedAhead_setup(team){
    return {color: team};
}

function FullSpeedAhead_getActions(gameInfo, botVars){
    var actions = [];

    if (gameInfo[botVars["color"]+"_alive"]) {
        actions.push("fire engine");
        actions.push("fire missile");
    }
    return actions;
}
tomulainen
fuente
No es tan malo como pensaba ...
noɥʇʎԀʎzɐɹƆ
¡Este bot ya está en vivo!
El'endia Starman
1

Ataque de pánico

Tiene una probabilidad del 50% de disparar y una probabilidad del 80% de girar a la izquierda; pero si no gira a la izquierda, girará a la derecha. Después de que se quede sin misiles, el tiempo eventualmente hará que se detenga debido al sol.

EDITAR: se agregó algo de lógica para no disparar cuando el enemigo está vivo porque podría ser asesinado por sus propios misiles.

function PanicAttack_setup(team) {
    var botVars = {};
    botVars["color"] = team;
    return botVars;
}

function PanicAttack_getActions(gameInfo, botVars) {
    var actions = [];
    actions.push("fire engine");
    if(botVars.color == "red") {
        var opponentAlive = gameInfo.blue_alive;
    }
    else if(botVars.color == "blue") {
        var opponentAlive = gameInfo.red_alive;
    }

    if ((Math.random()>0.5)&&opponentAlive) {
        actions.push("fire missile");
    }

    if (Math.random()>0.2) {
        actions.push("turn left");
    } else {
        actions.push("turn right");
    }

    return actions;
}
noɥʇʎԀʎzɐɹƆ
fuente
¡Este bot ya está en vivo!
El'endia Starman
@ El'endiaStarman Actualícelo nuevamente
noɥʇʎԀʎzɐɹƆ
¡Tu actualización ya está en vivo!
El'endia Starman
1

DangitBobby

A Bobby Hill no le importa lo que otros piensen de él: está bastante contento de dar vueltas perezosamente por el campo y esperar pacientemente a que su oponente se quede sin fuerzas antes de golpear como una cobra "ronca".

function DangitBobby_setup(team) {
    var botVars = {};
    botVars["color"] = team;
    if (team == 'red'){
        botVars['them'] = "blue";
    }
    else{
        botVars['them'] = 'red';
    }
    return botVars;
}

function DangitBobby_getActions(gameInfo, botVars) {
    var actions = [];
    if (gameInfo[botVars["color"]+"_alive"]) {
        actions.push('turn right');
        actions.push('fire engine');
        if (gameInfo[botVars['them']+'_missileStock'] == 0){
                actions.push('fire missile');
        }

    }
}

"¡ESE ES MI MONEDERO! ¡NO TE CONOZCO!"

John Dikeman
fuente
¡Este bot ya está en vivo!
El'endia Starman
1

Francotirador

He estado jugando con la predicción durante un tiempo para crear un robot de francotirador que snipes a sus enemigos. Mi javascript es demasiado grande para caber en una respuesta, así que aquí hay un enlace, bot_Sniper .

Jake Ellenberg
fuente
Finalmente pude probar este bot, y desafortunadamente, realmente ralentiza el juego. Es bastante entrecortado, por lo que debe hacer que su código sea más rápido de alguna manera.
El'endia Starman
La próxima vez, debe publicarlo en un servicio como [GitHub Gists] (gist.github.com) que está diseñado para el código.
noɥʇʎԀʎzɐɹƆ
Intenta optimizar tu código; Apuesto a que es un bot realmente bueno considerando lo largo que es. Puede intentar introducir algunas variables o funciones.
noɥʇʎԀʎzɐɹƆ
También tiene un código duplicado: creo que tendría mucho que ganar publicando su bot en la revisión de código , en el intercambio de pila.
noɥʇʎԀʎzɐɹƆ
También puede definir las funciones que coloca en Actions () en el ámbito externo, para que el intérprete no tenga que volver a analizarlo cada vez que ejecute Actions (). También debe intentar perfilar su código para acelerarlo.
noɥʇʎԀʎzɐɹƆ
1

SmartArrow

Como Arrow, pero inteligente

function SmartArrow_setup(team) {
    var botVars = {};
    botVars['mpref'] = team + '_';
    botVars['epref'] = team == 'red' ? 'blue_' : 'red_';
    botVars['ecolor'] = team == 'red' ? 'blue' : 'red';
    return botVars;
}

function SmartArrow_getActions(gameInfo, botVars) {
    var actions = [];
    var x = gameInfo[botVars['mpref'] + 'x'],
        y = gameInfo[botVars['mpref'] + 'y'],
        rot = gameInfo[botVars['mpref'] + 'rot']; // SmartArrow position and rotation
    var ex = gameInfo[botVars['epref'] + 'x'],
        ey = gameInfo[botVars['epref'] + 'y']; // Enemy position
    var sunx = gameInfo.sun_x,
        suny = gameInfo.sun_y; // Sun position
    var Dsunx = Math.abs(x - sunx),
        Dsuny = Math.abs(y - suny); // Sun position delta
    var dex = Math.abs(x - ex),
        dey = Math.abs(y - ey); // Enemy position delta
    var sangle = Math.degrees(Math.atan2(suny - y, sunx - x)),
        snrot = (rot - sangle + 360) % 360;
    if (Dsunx < 40 && Dsuny < 40) // If SmartArrow is too close from sun, hyperspace !
        return ['hyperspace'];
    var missiles = gameInfo.missiles;
    for (var i = 0; i < missiles.length; i++) { // Avoid all these silly missiles
        var dx = Math.abs(x - missiles[i].x),
            dy = Math.abs(y - missiles[i].y);
        if (dx < 10 && dy < 10)
            return ['hyperspace'];
    }
    if (gameInfo[botVars['epref'] + 'alive']) { // If his enemy is alive, SmartArrow try to kill him (logic)
        var angle = Math.degrees(Math.atan2(ey - y, ex - x)),
            nrot = (rot - angle + 360) % 360;
        if (nrot > 90 && nrot < 270)
            actions.push('turn left');
        else
            actions.push('turn right');
        if (nrot > 80 && nrot < 100
         && Math.random() > 0.5) actions.push('fire missile'); // If SmartArrow is in a good spot, shot this silly oponnent
        if (Math.random() > 0.5) actions.push('fire engine');
    }
    else { // Simply (try to) act like SunAvoider if his enemy is dead
        if (snrot > 90 && snrot < 270)
            actions.push('turn right');
        else
            actions.push('turn left');
        if (Dsunx < 300 && Dsuny < 300)
            actions.push('fire engine');
        if (dex < 40 && dey < 40)
            actions.push('hyperspace'); // Dying on the corpse of his opponent is dumb.
    }
    return actions;
}
TuxCrafting
fuente
¡Este bot ya está en vivo!
El'endia Starman
1

Kamikaze-

Tampoco está diseñado para ser competitivo. Solo por diversión. Se hiperespacia cuando está cerca del sol y persigue al jugador sin disparar balas. Es divertido ver a este robot perseguir una versión desarmada de Spy, pero desafortunadamente no puede tener más de un robot de usuario.

El'endia: alguna vez consideró agregar más de un robot de usuario;)

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


function KamikazePlus_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 left");
        } else {
            actions.push("turn right");
        };
        actions.push("fire engine");
    }
    return actions;
}

Solo tomé el código de Kamikaze + y me deshice de la parte de disparo de misiles.

noɥʇʎԀʎzɐɹƆ
fuente
Probablemente no agregaré este bot ya que ya teníamos otro bot Kamikaze , y prefiero no tener tres bots kamikaze. Además, este es más trivial que los otros dos.
El'endia Starman
@ El'endiaStarman entonces estoy solicitando múltiples userbots - campo de código de la segunda puede ser un defecto oculto ampliable
noɥʇʎԀʎzɐɹƆ
0

MissilesPlusScore

Se me ocurrió una idea extraña que toma que el valor absoluto de la diferencia de los puntajes y utiliza una lista de movimientos de forma aleatoria en función del juego. Funciona bien contra bots con una estrategia, pero falla contra tormentas de misiles. También mi primer .

function MissilesPlusScore__setup(team) {
var botVars = {};
botVars["color"] = team;
return botVars;
}
function MissilesPlusScore_getActions(gameInfo, botVars) {
var actions = [];
var moves=["fire missile","hyperspace","turn right","turn left","fire engine","fire missile","turn right","hyperspace","turn left","fire missile","hyperspace","turn right","turn left","hyperspace","fire engine","fire missile","turn right","turn left","hyperspace","fire missile","turn right","turn left","fire engine","hyperspace","fire missile","turn right","turn left","hyperspace"];
if(gameInfo[botVars["color"]+"_alive"]){
var num=gameInfo["redScore"]-gameInfo["blueScore"];
if(num<0){num=num*-1;}
if(num===0){actions.push(moves[Math.round(Math.random()*4)]);}
else{
actions.push(moves[num+gameInfo["numMissiles"]]);
}
}
    return actions;
}

HIPER

¡¡¡HIPERSPACE ES FRESCO !!!!!!!!!!!!!!!!

function HYPER_setup(team){var botVars={};botVars["color"]=team;return botVars}function HYPER_getActions(gameInfo,botVars){var actions=[];if(gameInfo[botVars["color"]+"_alive"]){actions.push(["fire engine","fire missile","hyperspace"][Math.round(Math.random()*2)])};return actions}

Influencia coordinada

Basado en las coordenadas, sorprendentemente eficaz:

function CoordinateInfluence_setup(team) {
var botVars = {};
botVars["color"] = team;
return botVars;
}
function CoordinateInfluence_getActions(gameInfo, botVars) {
var actions = [];
if (gameInfo[botVars["color"]+"_alive"]) {
if(gameInfo["blue_x"]>gameInfo["red_x"]){
if(gameInfo["blue_y"]<gameInfo["red_y"]){actions.push("turn right");}
else{actions.push("fire engine");}
}
else if(gameInfo["blue_y"]<gameInfo["red_y"]){
if(gameInfo["blue_x"]>gameInfo["red_x"]){actions.push("turn left");}
else{actions.push("fire missile");}
}
else{actions.push("hyperspace");}
}
return actions;
}
Usuario genérico
fuente
Ambos bots son en vivo.
El'endia Starman
Deberías publicar múltiples respuestas en su lugar.
noɥʇʎԀʎzɐɹƆ
Si alguna vez agrega otro bot, hágame un ping para que sepa que lo hizo. Tu tercer bot ya está en vivo.
El'endia Starman
0

SetCourseFor30Degrees

No tengo idea de por qué el capitán es tan insistente en establecer la nave en un curso de 30 grados, pero bueno, como una humilde bandera, ¿a quién interrogarás? ¡Al menos te han dado permiso para evitar el sol! Y se te permite disparar los misiles ... simplemente no puedes apuntarlos ...

function SetCourseFor30Degrees_setup(team) 
{
  var botVars = {};
  botVars["color"] = team;
  return botVars;
}


function SetCourseFor30Degrees_getActions(gameInfo, botVars)
{
var actions = [];
var ang1 = gameInfo[botVars["color"]+"_rot"]+0;
var fireChance=0.95;
// sun avoidance
   var x = gameInfo[botVars["color"]+"_x"];
   var y = gameInfo[botVars["color"]+"_y"];
   var sunX = gameInfo["sun_x"]+0;
   var sunY = gameInfo["sun_y"]+0;
  var dx = sunX- x;
   var dy = sunY - y;
var shortRangeAvoidanceDistance = (dx * dx + dy * dy ) ;

 x = gameInfo[botVars["color"]+"_x"]+gameInfo[botVars["color"]+"_xv"]*10;
 y = gameInfo[botVars["color"]+"_y"]+gameInfo[botVars["color"]+"_yv"]*10;
 dx = sunX- x;
 dy = sunY - y;

var longRangeAvoidanceDistance = (dx * dx + dy * dy ) ;


var vel = Math.sqrt(gameInfo[botVars["color"]+"_xv"]*gameInfo[botVars["color"]+"_xv"]+
gameInfo[botVars["color"]+"_yv"]*gameInfo[botVars["color"]+"_yv"]);

var close=vel*1.5;

if (shortRangeAvoidanceDistance <= close* close)
{
  actions.push("hyperspace");
}
else
{
   if (longRangeAvoidanceDistance <= 200*200)
   {

     x = x+Math.cos((ang1-5)*Math.PI/180)*vel ;
     y = y+Math.sin((ang1-5)*Math.PI/180)*vel ;
     dx = sunX- x;
     dy = sunY - y;
     if (( dx * dx + dy * dy ) > longRangeAvoidanceDistance  )
     {
       actions.push("turn right")
     }
     else
     {
        actions.push("turn left")
     }
  }
  else
  {
    var course = botVars["color"]=="red"?30:-30;
    if (ang1>course ) {actions.push("turn left")}
    if (ang1<course ) {actions.push("turn right")}
  }
  if (Math.random() > fireChance){ actions.push("fire missile") }
  actions.push("fire engine")
}
return actions;
}
Moogie
fuente
¡Este bot ya está en vivo!
El'endia Starman
0

Flecha

Simplemente persigue a su enemigo, hiperespacio cuando está en peligro e inactivo cuando su enemigo está muerto.

function Arrow_setup(team) {
    var botVars = {};
    botVars['mpref'] = team + '_';
    botVars['epref'] = team == 'red' ? 'blue_' : 'red_';
    return botVars;
}

function Arrow_getActions(gameInfo, botVars) {
    var actions = [];
    var x = gameInfo[botVars['mpref'] + 'x'],
        y = gameInfo[botVars['mpref'] + 'y'],
        rot = gameInfo[botVars['mpref'] + 'rot']; // My position and rotation
    var ex = gameInfo[botVars['epref'] + 'x'],
        ey = gameInfo[botVars['epref'] + 'y']; // Enemy position
    var Dsunx = Math.abs(x - gameInfo.sun_x);
    var Dsuny = Math.abs(y - gameInfo.sun_y);
    if (Dsunx < 30 && Dsuny < 30) // If Arrow is too close from sun, hyperspace !
        return ['hyperspace'];
    var missiles = gameInfo.missiles;
    for (var i = 0; i < missiles.length; i++) {
        var dx = Math.abs(x - missiles[i].x);
        var dy = Math.abs(y - missiles[i].y);
        if (dx < 10 && dy < 10)
            return ['hyperspace'];
    }
    if (gameInfo[botVars['epref'] + 'alive']) {
        var angle = Math.degrees(Math.atan2(ey - y, ex - x)),
            nrot = (rot - angle + 360) % 360;
        if (nrot > 90 && nrot < 270)
            actions.push('turn left');
        else
            actions.push('turn right');
        if (Math.random() > 0.5) actions.push('fire missile');
    }
    if (Math.random() > 0.5) actions.push('fire engine');
    return actions;
}
TuxCrafting
fuente
¡Este bot ya está en vivo!
El'endia Starman
@ El'endiaStarman He actualizado el bot
TuxCrafting
¡La actualización ya está en vivo! No mucho de uno sin embargo. : P
El'endia Starman
0

Kamikaze +

No está diseñado para ser competitivo. Solo por diversión. Técnicamente, hace lo contrario de Spy: perseguir al jugador, hiperespacio cuando está cerca del sol, disparar misiles el 70% del tiempo. Solo quiero ver a KamikazePlus persiguiendo a Spy y Spy corriendo como un loco.

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


function KamikazePlus_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 left");
        } else {
            actions.push("turn right");
        };
        actions.push("fire engine");
        if (Math.random() > 0.3) {
            actions.push("fire missile")
        }

    }
    return actions;
}

Básicamente solo tomé el código de Spy y volteé "izquierda" y "derecha".

noɥʇʎԀʎzɐɹƆ
fuente
¡Este bot ya está en vivo! Y sí, es divertido ver a KamikazePlus perseguir a Spy. : P
El'endia Starman
@ El'endiaStarman Me parece divertido ver a KamikazePlus luchar sin balas y overideHyperspace = 0;; simplemente siguen desaparecidos cuando intentan enfrentarse el uno al otro.
noɥʇʎԀʎzɐɹƆ