Король горы - Космическая война!

64

Если вы когда-нибудь играли в Spacewar! Знаешь, это была веселая игра. Если нет, знайте: это была (и есть) одна из самых первых и самых важных компьютерных игр. И это все еще весело! Клон, на котором я вырос, - это , по-видимому, и, к сожалению, только Windows. Так я его воссоздал!

KotH находится здесь: PPCG - Spacewar! Король горы . Я призываю вас играть как человек против хотя бы одного другого бота, чтобы понять, как работает игра.

Игра

  • Один кадр составляет 30 миллисекунд (таким образом, около 33 кадров в секунду).
  • Поле имеет ширину 800 пикселей и высоту 600 пикселей.
  • Поле является тороидальным, что означает, что космические корабли и ракеты, которые движутся за пределами поля, вновь появляются на противоположной стороне.
  • Есть два космических корабля, красный и синий.
    • Красный расположен при x = 50, а случайный y между 50 (высота поля - 50) пикселей.
    • Синий расположен в точке x = (ширина поля - 50) и случайным образом y между 50 (высота поля - 50) пикселей.
    • Обе грани х = (ширина поля) / 2.
  • Доступные элементы управления:
    • Поверните налево - 5 градусов на кадр против часовой стрелки.
    • Поверните направо - 5 градусов на кадр по часовой стрелке.
    • Ракета огня - движется с дополнительными 10 пикселями на кадр в дополнение к скорости корабля, в направлении, которое указывал корабль.
    • Пожарная машина - ускоряет космический корабль со скоростью 0,30 пикселя за кадр в направлении, указанном космическим кораблем.
    • Гиперпространственный прыжок - телепортируется на случайные координаты в поле с вероятностью взрыва 25%. Эти случайные координаты могут быть на вершине солнца.
  • Максимальная скорость для кораблей составляет 15 пикселей на кадр при мощности двигателя и 40 пикселей на кадр при усилении силы тяжести.
    • При движении быстрее 15 пикселей на кадр, тяга двигателя может только изменить направление или замедлить.
  • Что касается ракет:
    • Ракеты движутся по прямой.
    • Ракеты могут быть запущены с максимальной скоростью 1 за 0,1 секунды.
    • Срок службы ракеты составляет 2,25 секунды.
    • Корабли имеют максимум 20 ракет каждая.
    • Ракеты - это точечные частицы внутри.
  • В самом центре есть солнце, которое чрезвычайно опасно для вашего корабля. Малейший контакт со смертельным исходом. Это солнце также уничтожает ракеты.
  • Солнце имеет гравитацию. Результирующее ускорение составляет 5000 / (расстояние ^ 2) пикселей / кадр ^ 2, где расстояние в пикселях. Космические корабли и ракеты пострадали.
  • Оба корабля имеют три зоны удара: нос, левое крыло и правое крыло.
    • Удар по носу - это мгновенная смерть.
    • Удар по любому из крыльев уменьшает скорость поворота космического корабля и ускорение двигателя вдвое.
    • Если оба крыла уничтожены, космический корабль не может маневрировать и может стрелять только ракетами.
  • Корабли могут сталкиваться друг с другом.
    • Удар нос-нос смертелен для обоих кораблей.
    • Удар носового крыла разрушает крыло.
    • Удар крыло уничтожает оба крыла.
  • Мертвые корабли тверды и заморожены, пока не взорвутся через 1 секунду.
  • После того, как погиб хотя бы один корабль, поле сбрасывается через 3 секунды. До тех пор солнце и любые оставшиеся ракеты все еще опасны.

У оригинальной игры также есть смертельные и неразрушимые астероиды, но я не буду включать те.

Правила

  • Ваш бот должен быть написан на JavaScript.
  • Ваш бот должен ограничить свое решение до 10 миллисекунд. Если я замечу постоянное отставание из-за вашего бота , я дисквалифицирую его и дам вам знать, чтобы вы могли это исправить.
  • Боты будут иметь доступ к следующему:
    • Ширина поля и высота поля
    • Положение и радиус Солнца
    • Положение, вращение, скорость, форма, запас ракет и статус в гиперпространстве обоих кораблей
    • Положение и скорость всех ракет
  • При появлении запроса ваш бот должен вернуть список строк.
    • Эти строки должны быть один из следующих: turn left, turn right, fire engine, fire missile,hyperspace . Любая другая строка будет проигнорирована.
    • Если есть какие-либо дубликаты, будет отмечен только первый.
    • hyperspace имеет приоритет над всеми остальными.
    • turn leftи turn rightв то же время не будет иметь никакого эффекта.
    • fire engine не будет иметь никакого эффекта, если у корабля только нос или он мертв.
    • fire missile не будет иметь эффекта, если ракета будет запущена слишком недавно.
  • В отличие от обычного, ваш бот может использовать поведение других ботов. Я хочу поощрять метагейм.
    • Боты не могут эмулировать других ботов. (Т.е. нет чтения мыслей.)
    • Боты не могут устанавливать переменные, используемые в игровом и физическом коде. (Т.е. без обмана.)

Детали реализации бота

Я буду хранить вашего бота в его собственном файле JavaScript, который автоматически включается вместе с именем файла bot_<name>.js. Так что не ставьте пробелы или символы, которые мешали бы этому или именовали функцию в JavaScript. Это потому, что вы должны определить следующие функции: <name>_setup(team)и <name>_getActions(gameInfo, botVars). Далее вниз по странице есть текстовые области для userbot , которые вы можете редактировать для проверки своего кода.

<name>_setup(team)

Эта функция предназначена для определения любых переменных, которые вы хотите сохранить. teamбудет либо "red"или "blue". Эта функция должна возвращать объект. Определите переменные следующим образом:

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

Этот varsобъект будет передан другой функции:

<name>_getActions(gameInfo, botVars)

botVarsэто объект , возвращаемый <name>_setup(team). gameInfoявляется объектом, содержащим следующие переменные:

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

Ваш бот имеет полный доступ к ним. Я уверен, что вы можете писать в них и не влиять на исходные переменные, но все равно не делайте этого. Примечание о поворотах: точка корабля в направлении + y вниз, поэтому все, что вы хотите выровнять с кораблем, должно быть смещено на 90 градусов. Кроме того, положительное вращение по часовой стрелке.

Эта функция должна возвращать список строк, представляющих действия вашего бота. Например, ["turn right","thrust"]. Подробнее об этом в разделе « Правила ».

дополнительные детали

Вы также можете использовать следующее:

LineIntersection(L1, L2)

L1 и L2 - двухэлементные массивы из двухэлементных массивов. То есть L1 := [[x1,y1],[x2,y2]]и L2 := [[u1,v1],[u2,v2]]. Эта функция вычисляет пересечение двух линий и возвращает это: [[x,y], [a,b]]. [x,y]являются координатами точки пересечения и [a,b]представляют собой пару соотношений, которые выражают, как далеко вдоль каждой линии находится точка пересечения. Как и в, a = 0.25будет означать, что точка пересечения четверть пути от [x1,y1]к [x2,y2], и также для b. Если пересечения нет, возвращается пустой массив.

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]]
};

Это координаты полигонов кораблей. Чтобы упростить получение текущих координат, вы также можете использовать ...

getShipCoords(<color>)

getShipCoords("red")вернет текущие координаты вершин корабля Красного, а также для getShipCoords("blue")и Blue. Эти координаты в списке , как так: [[x1,y1],[x2,y2],[x3,y3],...]. Полигоны неявно замкнуты, поэтому между первой и последней парами координат есть линия.

Вы не можете получить доступ или изменять любые другие переменные или функции, используемые игрой / веб-сайтом. И определенно не называйте ваши функции одинаковыми. Я не предвижу, что это будет проблемой, но если ваш бот нарушает код игры, это одна из возможностей. Нет регистрации или отлова исключений.

выигрыш

  • Каждое соединение ботов должно быть сыграно не менее 10 раз в обе стороны. (Итого минимум 20 игр.)
  • Старайтесь иметь самые высокие коэффициенты выигрыша / проигрыша в целом . Если ваш бот отлично справляется с одним другим ботом, но проигрывает против трех других, это не так хорошо, как выигрывать против двух и проигрывать против двух (как общее правило).
  • Для каждого бота будут рассчитаны соотношения (выигрыши + 1) / (проигрыши + 1), а затем будет вычислено среднее и стандартное отклонение этих соотношений. Более высокое среднее значение будет иметь приоритет, и если средние значения находятся в пределах 1 единицы друг от друга, более низкая дисперсия будет иметь приоритет.
  • Оценка начнется либо через неделю с сегодняшнего дня, либо через три дня после новых заявок. Это так, что мне не нужно повторять спаривание ботов.

Прежде всего, получайте удовольствие!


Таблица лидеров (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

Примечание: это может измениться, поскольку я запускаю больше игр. Кроме того, порядок рангов 9-13 беспокоит меня, поэтому я могу настроить метод подсчета очков, чтобы он лучше соответствовал интуиции о том, как их оценивать.

(Значения и стандартные отклонения были округлены до трех десятичных цифр. Кроме того, Hyperдолжно быть, HYPERно это портит подсветку.: P)

Эльендия Старман
источник
Есть очки? ....
ev3commander
Это регистрирует пойманные исключения?
TheNumberOne
1
Вы должны указать, что вызов LineIntersectionнепересекающихся сегментов возвращает пустой массив.
LegionMammal978
1
Я думаю, что сделал это!
ev3commander
3
@CrazyPython: Я бы поспорил с первыми двумя, учитывая, что я в основном скопировал игру, но третий - именно то, что я хотел. Спасибо! : D
El'endia Starman

Ответы:

12

Helios

Этот бот - центр вселенной, или, по крайней мере, он так считает. Первое, что он делает, это исправляет серьезную ошибку и помещает себя в центр системы координат. Затем он вращает все вокруг себя.

Ему не нравится другое (поддельное) солнце, поэтому он старается держаться от него подальше. Ему также не нравятся другие боты, поэтому он стреляет в них, если он находится в хорошей стрельбе.

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
источник
1
Я думаю, что это один из моих любимых ботов до сих пор. Это на удивление хорошо!
El'endia Starman
@ El'endiaStarman Я сделал несколько обновлений для бота.
Sleafar
Ваше обновление теперь в прямом эфире!
El'endia Starman
Это очень хорошо работает против OrbitBot :)
TheNumberOne
1
@ Soaku Я думаю, что основное различие между этим ботом и большинством других заключается в том, что этот бот направлен на своего противника перед стрельбой.
Sleafar
9

SunAvoider

Этот просто пытается держаться подальше от солнца. Он делает это очень хорошо ... пока он не уничтожит одно или оба крыла, тогда, как правило, это только вопрос времени, когда он упадет.

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;
}
Эльендия Старман
источник
9

EdgeCase

Полетает на полной скорости от Солнца к краю карты! Когда он окажется направленным на солнце, он начнет стрелять, отвернувшись, чтобы вернуться к краю. Это также входит в гиперпространство, когда это собирается поразить солнце.

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;
}
user81655
источник
Этот бот сейчас жив! Кроме того, против этого было удивительно легко выжить. Вероятно, это связано с тем, что он не распространяет ракеты повсюду, как некоторые другие. : P
El'endia Starman
7

OrbitBot

В настоящее время нет нацеливания или предотвращения столкновений . Он пытается вращаться вокруг солнца.

Изменить: теперь переходит в гиперпространство, когда воздействие неизбежно.

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;
}
Номер один
источник
Ваш бот был добавлен.
Конор О'Брайен
Ваше обновление теперь в прямом эфире!
Эльендия Старман
5

RighthandedSpasms

Название довольно наглядно. Выбирает turn rightс вероятностью 0,5, fire engineс вероятностью 0,5 и fire missileвероятностью 0,8. Удивительно сложно, в основном потому, что это действительно непредсказуемо.

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;
}
Эльендия Старман
источник
5

RandUmmm

Для этого испытания нужен случайный бот. Бонусные баллы за гольф?

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();
}
Конор О'Брайен
источник
Здорово! (Кстати, мой бот выиграл 13-7 Не. На много, учитывая , что я потерял 9-1 раз, но это много очков в общей сложности 20 очков за 90 секунд.!)
ev3commander
@ BlockCoder1392 это является случайным бот;)
Конор О'Брайен
4

инженер

Любит использовать гиперпространство, когда в опасности. Чтобы увидеть его истинную силу, откройте консоль браузера и введите overideHyperspace = 0;. Если вы забудете точку с запятой, вы получите ASI на Рождество.

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;
}
Конор О'Брайен
источник
3

SprayAndPray

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;
}

Огненно стреляет во всех направлениях. Это не очень эффективно!

Джек Браунштейн
источник
Этот бот сейчас жив!
El'endia Starman
3

Камикадзе

Не очень конкурентоспособный, но я думал, что это будет весело! Просто летит прямо к противнику во время стрельбы.

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;
}
user81655
источник
Ваш бот был добавлен!
Конор О'Брайен
Ужасно против OpponentDodger ... Связано с PanicAttack ...
noɥʇʎԀʎzɐɹƆ
2

UhhIDKWhatToCallThisBot

Просто случайные вещи.

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
источник
что случилось с загадочной игрой в гольф?
noɥʇʎԀʎzɐɹƆ
2

OpponentDodger

ВЗЯТЬ ОТ МНЕ, ПРОТИВНИК !!!

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;}  

Спасибо user81655 за некоторый код!

ev3commander
источник
Этот бот сейчас жив!
El'endia Starman
2

шпион

История

Прототипом этого бота был бот, который имел два режима: сумасшедший режим и обычный режим. Когда он был в сумасшедшем режиме, он оставался там в течение постоянного числа тиков. Была постоянная вероятность входа в сумасшедший режим. Это также гиперпространство, когда это было близко к солнцу. В безумном режиме он нацелился на другого бота и постоянно стрелял. В обычном режиме он улетел от другого бота, не стреляя.

Я настроил этот прототип так, чтобы он был в сумасшедшем режиме, если и только если враг был достаточно близко. Тогда у меня возникла сумасшедшая идея: что, если он останется только в сумасшедшем режиме? После некоторых экспериментов (я добавил, что бот запускается случайным образом, когда он был в обычном режиме), я обнаружил, что новый бот побеждает каждого бота, кроме Helios. Это мой код в конце этого процесса, но до очистки.

Я написал весь свой бот в текстовой области KotH или в JS beautifier. (Я кратко использовал редактор Atom при очистке - но для двух строк кода)

Бот

Этот бот содержит много кода, позаимствованного у других ботов. Он переворачивает код из Kamikaze, чтобы убежать от другого бота, вместо того, чтобы бежать к другому боту, и берет код из EdgeCase для гиперпространства, когда он находится близко к солнцу.

Это заклятый враг Гелиоса. Это нечетные и длинные чаты с мартини.

Он убегает от другого бота с 70% -ной вероятностью запуска ракеты и гиперпространства, когда он находится близко к солнцу. Так просто, как, что. Ага.

Изменить: я проверил мой бот с новым кодом, и он не работает для любого другого бота. Я работаю над тем, чтобы исправить это. Я только что подтвердил, что это только для моего нового бота.

Код

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;
}

Разное

Примечание: я мог что-то сломать при очистке кода, потому что я не тестировал бота после очистки кода.

Это также намного намного лучше, чем все мои другие боты - на самом деле он побил любого другого бота, кроме Helios (править) , SetCourseFor30Degrees и OrbitBot! Это связано с SunAvoider.

Примечание: я ужасен в javascript, не знаю почему.

noɥʇʎԀʎzɐɹƆ
источник
@ El'endiaStarman, пожалуйста, переведите бота в режим паузы; Мне нужно исправить мой бот - очищенная версия намного хуже, чем нечистая версия.
noɥʇʎԀʎzɐɹƆ
Хорошо, дайте мне знать, когда это будет исправлено.
El'endia Starman
@ El'endiaStarman Я кое-что сделал, а потом все заработало. Отладка, вы знаете! (еще не сделано)
noɥʇʎԀʎzɐɹƆ
@ El'endiaStarman ... и готово!
noɥʇʎԀʎzɐɹƆ
Этот бот сейчас жив!
El'endia Starman
1

AttackAndComeBack

Вместо закручивания он входит сверху и выходит внизу (возвращается сверху), стреляя очень быстро. Вообще избегает солнца.

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ɐɹƆ
источник
Этот бот сейчас жив!
El'endia Starman
1

FullSpeedAhead

Всегда запускает как двигатели, так и ракеты, не поворачиваясь никогда. Иногда длится на удивление задолго до попадания на солнце.

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
источник
Не так плохо, как я думал ...
noɥʇʎԀʎzɐɹƆ
Этот бот сейчас жив!
El'endia Starman
1

Паническая атака

Вероятность стрельбы 50% и 80% поворота налево; но если он не повернет налево, он повернет направо. После того, как у него закончатся ракеты, время в конечном итоге остановит его из-за солнца.

РЕДАКТИРОВАТЬ: Добавлена ​​логика, чтобы не стрелять, когда враг жив, потому что он может быть убит своими собственными ракетами.

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ɐɹƆ
источник
Этот бот сейчас жив!
El'endia Starman
@ El'endiaStarman Пожалуйста, обновите его снова
noɥʇʎԀʎzɐɹƆ
Ваше обновление теперь в прямом эфире!
El'endia Starman
1

DangitBobby

Бобби Хиллу все равно, что о нем думают другие - он вполне доволен, чтобы лениво раскачиваться по полю и терпеливо ждать, пока противник не выдохнется, прежде чем ударить, как "хриплая" кобра.

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');
        }

    }
}

"Это мой кошелек! Я не знаю тебя!"

Джон Дайкман
источник
Этот бот сейчас жив!
El'endia Starman
1

снайпер

Я немного поигрался с предсказанием, чтобы создать снайперского бота, который будет стрелять из врагов. Мой javascript слишком большой, чтобы уместиться в ответе, так что вот ссылка, bot_Sniper .

Джейк Элленберг
источник
Наконец-то дошли руки до тестирования этого бота, и, к сожалению, он действительно тормозит игру. Это довольно изменчиво, поэтому вам нужно как-то ускорить ваш код.
El'endia Starman
В следующий раз вы должны опубликовать его в сервисе, подобном [GitHub Gists] (gist.github.com), который предназначен для кода.
noɥʇʎԀʎzɐɹƆ
Попробуйте оптимизировать свой код; Бьюсь об заклад, это действительно хороший бот, учитывая, как долго это будет. Вы можете попробовать ввести некоторые переменные или функции.
noɥʇʎԀʎzɐɹƆ
У вас также есть некоторый повторяющийся код - я думаю, что вы сможете извлечь выгоду из публикации своего бота для проверки кода на обмене стека.
noɥʇʎԀʎzɐɹƆ
Вы также можете определить функции, которые вы помещаете в Actions (), во внешнюю область, так что интерпретатору не нужно повторно анализировать его каждый раз, когда вы запускаете Actions (). Вам также следует попробовать профилировать ваш код, чтобы ускорить его.
noɥʇʎԀʎzɐɹƆ
1

SmartArrow

Вроде Стрелка, но умная

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
источник
Этот бот сейчас жив!
El'endia Starman
1

Камикадзе-

Также не предназначен, чтобы быть конкурентоспособным.Просто для удовольствия. Гиперпространство, когда рядом с солнцем и преследует игрока, не стреляя пулями. Забавно наблюдать, как этот бот преследует невооруженную версию Spy, но, к сожалению, у вас не может быть более одного пользователя.

El'endia: когда-нибудь рассматривал возможность добавления более одного пользователя;)

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;
}

Просто взял код Камикадзе + и избавился от части ракетного обстрела.

noɥʇʎԀʎzɐɹƆ
источник
Я, вероятно, не буду добавлять этого бота, поскольку у нас уже был еще один бот Kamikaze , и я бы предпочел не иметь трех ботов Kamikaze . Кроме того, этот более тривиален, чем два других.
El'endia Starman
@ El'endiaStarman, тогда я запрашиваю несколько пользовательских ботов - поле кода второго может быть скрытым расширяемым по умолчанию
noɥʇʎԀʎzɐɹƆ
0

MissilesPlusScore

Какая-то странная идея, с которой я столкнулся, заключается в том, что абсолютное значение разницы в оценках и случайный выбор списка ходов основаны на игровом пути. Это хорошо работает против ботов со стратегией, но терпит неудачу против штормов ракет. Также мой первый .

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;
}

HYPER

HYPERSPACE - это ОХЛАЖДЕНИЕ !!!!!!!!!!!!!!!!

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}

CoordinateInfluence

Исходя из координат, удивительно эффективно:

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;
}
Общий пользователь
источник
Оба этих бота живы.
El'endia Starman
Вместо этого вы должны опубликовать несколько ответов.
noɥʇʎԀʎzɐɹƆ
Если вы когда-нибудь добавите еще одного бота, пожалуйста, пингуйте меня, чтобы я знал, что вы сделали. Ваш третий бот теперь жив.
El'endia Starman
0

SetCourseFor30Degrees

Понятия не имею, почему капитан так настойчиво ставит корабль на курс 30 градусов, но, эй, как смиренный прапорщик, кого вы спрашиваете? По крайней мере, вы получили разрешение избегать солнца! И вам разрешено запускать ракеты ... просто не разрешается нацеливать их ...

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
источник
Этот бот сейчас жив!
El'endia Starman
0

Стрелка

Просто преследуйте своего врага, гиперпространство, когда он в опасности, и бездействуйте, когда его враг мертв.

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
источник
Этот бот сейчас жив!
El'endia Starman
@ El'endiaStarman Я обновил бота
TuxCrafting
Обновление теперь живое! Не так много, хотя. : P
El'endia Starman
0

Камикадзе +

Не предназначен для того, чтобы быть конкурентоспособным. Просто для удовольствия. Технически, это делает противоположность Spy: преследовать игрока, гиперпространство, когда он находится близко к солнцу, запускать ракеты 70% времени. Я просто хочу видеть, как KamikazePlus преследует Шпиона, и Шпион убегает, как сумасшедший.

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;
}

В основном просто взял код шпиона и щелкнул «влево» и «вправо».

noɥʇʎԀʎzɐɹƆ
источник
Этот бот сейчас жив! И да, забавно наблюдать, как KamikazePlus преследует Шпиона. : P
El'endia Starman
@ El'endiaStarman Я нахожу забавным наблюдать, как KamikazePlus сражается сам без пуль и overideHyperspace = 0;; они просто пропадают, когда пытаются друг на друга.
noɥʇʎԀʎzɐɹƆ