King of the Hill - Spacewar!


64

Jeśli kiedykolwiek grałeś w Spacewar! , wiesz, że to była fajna gra. Jeśli nie, wiedz o tym: była to (i jest) jedna z pierwszych i najważniejszych gier komputerowych. I nadal jest fajnie! Klon, na którym dorastałem, to ten , którym najwyraźniej i niestety jest tylko Windows. Więc odtworzyłem to!

KotH jest tutaj: PPCG - Spacewar! King of the Hill . Zachęcam cię do gry jako człowiek przeciwko przynajmniej jednemu botowi, aby przekonać się, jak działa ta gra.

Gra

  • Jedna klatka ma 30 milisekund (a więc około 33 klatek na sekundę).
  • Pole ma szerokość 800 pikseli i wysokość 600 pikseli.
  • Pole jest toroidalne, co oznacza, że ​​statki kosmiczne i pociski, które poruszają się poza polem, pojawiają się ponownie po przeciwnej stronie.
  • Istnieją dwa statki kosmiczne, czerwony i niebieski.
    • Kolor czerwony jest ustawiony na x = 50, a losowy y między 50, (wysokość pola - 50) pikseli.
    • Niebieski jest ustawiony na x = (szerokość pola - 50) i losowo y między 50, (wysokość pola - 50) pikseli.
    • Obie ściany x = (szerokość pola) / 2.
  • Dostępne elementy sterujące to:
    • Skręć w lewo - 5 stopni na klatkę przeciwnie do ruchu wskazówek zegara.
    • Skręć w prawo - 5 stopni na klatkę zgodnie z ruchem wskazówek zegara.
    • Pocisk ognia - porusza się z dodatkowymi 10 pikselami na ramkę oprócz prędkości statku, w kierunku, w którym statek był skierowany.
    • Wóz strażacki - przyspiesza statek kosmiczny z prędkością 0,30 pikseli na klatkę w kierunku, w którym wskazuje statek kosmiczny.
    • Skok nadprzestrzenny - teleportuje się do losowych współrzędnych w polu, z 25% szansą na wybuch. Te losowe współrzędne mogą znajdować się nad Słońcem.
  • Maksymalna prędkość dla statków wynosi 15 pikseli na klatkę przy mocy silnika i 40 pikseli na klatkę przy wzmocnieniu grawitacyjnym.
    • Podczas jazdy z prędkością większą niż 15 pikseli na klatkę ciąg silnika może jedynie zmienić kierunek lub zwolnić.
  • Jeśli chodzi o pociski:
    • Pociski poruszają się w linii prostej.
    • Pociski mogą być wystrzeliwane z maksymalną prędkością 1 na 0,1 sekundy.
    • Pociski mają żywotność 2,25 sekundy.
    • Statki mają maksymalnie 20 pocisków każdy.
    • Pociski są wewnętrznie cząstkami punktowymi.
  • W samym centrum jest słońce, które jest wyjątkowo niebezpieczne dla twojego statku. Najmniejszego kontaktu jest śmiertelne. To słońce niszczy również pociski.
  • Słońce ma grawitację. Wynikowe przyspieszenie wynosi 5000 / (odległość ^ 2) pikseli / ramkę ^ 2, gdzie odległość jest w pikselach. Ma to wpływ na statki kosmiczne i pociski.
  • Oba statki mają trzy strefy uderzenia: nos, lewe skrzydło i prawe skrzydło.
    • Trafienie w nos to natychmiastowa śmierć.
    • Trafienie w jedno ze skrzydeł zmniejsza prędkość obrotu statku kosmicznego i przyspieszenie silnika o połowę.
    • Jeśli oba skrzydła zostaną zniszczone, statek kosmiczny nie będzie mógł manewrować i będzie mógł strzelać tylko pociskami.
  • Statki mogą się ze sobą zderzać.
    • Uderzenie nosa w nos jest śmiertelne dla obu statków.
    • Uderzenie nosa w skrzydło niszczy skrzydło.
    • Uderzenie skrzydła w skrzydło niszczy oba skrzydła.
  • Martwe statki są solidne i zamrożone, aż wybuchną 1 sekundę później.
  • Po śmierci co najmniej jednego statku pole resetuje się 3 sekundy później. Do tego czasu słońce i pozostałe pociski są nadal niebezpieczne.

Oryginalna gra ma również śmiertelne i niezniszczalne asteroidy, ale ich nie uwzględnię.

Zasady

  • Twój bot musi być napisany w JavaScript.
  • Twój bot powinien ograniczyć swoją decyzję do około 10 milisekund. Jeśli zauważę stałe opóźnienie z powodu twojego bota , zdyskwalifikuję go i dam znać, abyś mógł go naprawić.
  • Boty będą miały dostęp do następujących elementów:
    • Szerokość i wysokość pola
    • Pozycja i promień słońca
    • Pozycja, obrót, prędkość, kształt, zapas pocisków i status hiperprzestrzeni obu statków
    • Pozycja i prędkość wszystkich pocisków
  • Po wyświetleniu monitu bot powinien zwrócić listę ciągów znaków.
    • Ciągi te powinny być jedną z następujących czynności: turn left, turn right, fire engine, fire missile, hyperspace. Każdy inny ciąg zostanie zignorowany.
    • Jeśli są jakieś duplikaty, tylko pierwsza zostanie odnotowana.
    • hyperspace ma pierwszeństwo przed wszystkimi innymi.
    • turn lefti turn rightjednocześnie nie przyniesie żadnego efektu.
    • fire engine nie przyniesie żadnego efektu, jeśli statek ma tylko dziób lub jest martwy.
    • fire missile nie przyniesie efektu, jeśli pocisk został wystrzelony zbyt niedawno.
  • W odróżnieniu od zwykłego, twój bot może wykorzystywać zachowanie innych botów. Chcę zachęcić do gry metagame.
    • Boty nie mogą emulować innych botów. (Tj. Brak czytania w myślach.)
    • Boty nie mogą ustawiać żadnych zmiennych używanych przez grę i kod fizyki. (Tj. Bez oszukiwania.)

Szczegóły implementacji bota

Będę przechowywać twojego bota we własnym pliku JavaScript, który jest automatycznie dołączany wraz z nazwą pliku bot_<name>.js. Nie umieszczaj więc spacji ani znaków, które mogłyby zakłócać to lub nazywanie funkcji w JavaScript. Jest tak, ponieważ powinieneś zdefiniować następujące funkcje: <name>_setup(team)i <name>_getActions(gameInfo, botVars). W dalszej części strony znajdują się obszary tekstowe dla robota użytkownika , które można edytować w celu przetestowania kodu.

<name>_setup(team)

Ta funkcja służy do definiowania dowolnych zmiennych, które chcesz utrwalić. teambędzie albo "red"albo "blue". Ta funkcja musi zwrócić obiekt. Zdefiniuj zmienne w następujący sposób:

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

Ten varsobiekt zostanie przekazany do innej funkcji:

<name>_getActions(gameInfo, botVars)

botVarsto obiekt zwrócony przez <name>_setup(team). gameInfoto obiekt zawierający następujące zmienne:

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

Twój bot ma do nich pełny dostęp. Jestem pewien , że możesz do nich pisać i nie wpływać na oryginalne zmienne, ale i tak tego nie rób. Uwaga na temat rotacji: statki są skierowane w kierunku + y, w dół, więc wszystko, co chcesz wyrównać ze statkiem, musi być przesunięte o 90 stopni. Ponadto dodatni obrót odbywa się zgodnie z ruchem wskazówek zegara.

Ta funkcja musi zwrócić listę ciągów, reprezentujących działania twojego bota. Na przykład ["turn right","thrust"]. Więcej informacji na ten temat znajduje się w sekcji Zasady .

Dodatkowe Szczegóły

Możesz także skorzystać z następujących opcji:

LineIntersection(L1, L2)

L1 i L2 są dwuelementowymi tablicami tablic dwuelementowych. To znaczy L1 := [[x1,y1],[x2,y2]]i L2 := [[u1,v1],[u2,v2]]. Funkcja ta oblicza punkt przecięcia dwóch prostych i zwraca to: [[x,y], [a,b]]. [x,y]są współrzędnymi punktu przecięcia i [a,b]są parą stosunków, które wyrażają, jak daleko wzdłuż każdej linii znajduje się punkt przecięcia. Jak w, a = 0.25oznaczałoby, że punkt przecięcia jest czwarta drogi od [x1,y1]celu [x2,y2], a także dla b. Jeśli nie ma przecięcia, zwracana jest pusta tablica.

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

Są to współrzędne wielokątów statków. Aby ułatwić uzyskanie bieżących współrzędnych, możesz również użyć ...

getShipCoords(<color>)

getShipCoords("red")zwróci bieżące współrzędne wierzchołków statku Czerwonego, a także dla getShipCoords("blue")i Niebieskiego. Współrzędne te są na liście tak: [[x1,y1],[x2,y2],[x3,y3],...]. Wieloboki są domyślnie zamknięte, więc między pierwszą i ostatnią parą współrzędnych istnieje linia.

Nie możesz uzyskiwać dostępu ani zmieniać żadnych innych zmiennych lub funkcji używanych przez grę / stronę internetową. I zdecydowanie nie nazywaj swoich funkcji tak samo. Nie przewiduję, że będzie to problem, ale jeśli twój bot złamie kod gry, to jedna z możliwości. Nie ma rejestrowania ani wyłapywania wyjątków.

Zwycięski

  • Każda para botów powinna być odtwarzana co najmniej 10 razy w obie strony. (Tak więc w sumie co najmniej 20 gier.)
  • Staraj się osiągnąć najwyższy ogólny stosunek wygranych do przegranych . Jeśli twój bot radzi sobie bardzo dobrze przeciwko drugiemu botowi, ale przegrywa z pozostałymi trzema, nie jest to tak dobre, jak wygrywanie z dwoma i przegrywanie z dwoma (co jest ogólną zasadą).
  • Dla każdego bota obliczone zostaną stosunki (wygrane + 1) / (straty + 1), a następnie obliczona zostanie średnia i odchylenie standardowe tych stosunków. Wyższa średnia będzie miała priorytet, a jeśli średnie będą w odległości 1 jednostki od siebie, niższa wariancja będzie miała priorytet.
  • Punktacja rozpocznie się za tydzień od dzisiaj lub po trzech dniach braku nowych zgłoszeń. Jest tak, że nie muszę powtarzać żadnej pary botów.

Przede wszystkim baw się dobrze!


Tabela liderów (08.01.2016, 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

Uwaga: może to ulec zmianie, gdy uruchamiam więcej gier. Ponadto niepokoi mnie porządkowanie rang 9-13, więc mogę dostosować metodę punktacji, aby lepiej dopasować intuicję do tego, jak powinny być uszeregowane.

(Średnie i standardowe odchylenia zostały zaokrąglone do trzech cyfr dziesiętnych. HyperPowinno być, HYPERale to pomieszało podświetlanie.: P)


Jakieś wyniki? ....
ev3commander

Czy rejestruje wyjątki?
TheNumberOne

1
Powinieneś określić, że wywołanie LineIntersectionna nie przecinających się segmentach zwraca pustą tablicę.
LegionMammal978

1
Myślę, że to zrobiłem!
ev3commander

3
@CrazyPython: Sprzeciwiłbym się dwóm pierwszym, biorąc pod uwagę, że w zasadzie skopiowałem grę, ale trzeci jest dokładnie tym, czego chciałem. Dzięki! : D
El'endia Starman,

Odpowiedzi:


12

Helios

Ten bot jest centrum wszechświata, a przynajmniej tak mu się wydaje. Pierwszą rzeczą, którą robi, jest poprawienie poważnego błędu i umieszczenie się na środku układu współrzędnych. Potem obraca wszystko wokół siebie.

Nie lubi drugiego (fałszywego) słońca, dlatego stara się trzymać z dala od niego. Nie lubi też innych botów, dlatego strzela do nich, jeśli jest w dobrej pozycji do strzelania.

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

1
Myślę, że to jeden z moich ulubionych botów. To zaskakująco dobre!
El'endia Starman

@ El'endiaStarman Wprowadziłem kilka aktualizacji bota.
Sleafar

Twoja aktualizacja jest już dostępna!
El'endia Starman

Działa to bardzo dobrze przeciwko OrbitBot :)
TheNumberOne

1
@Soaku Myślę, że główną różnicą między tym botem a większością innych jest to, że ten bot celuje w przeciwnika przed strzelaniem.
Sleafar

9

SunAvoider

Ten po prostu stara się trzymać z dala od słońca. Robi to całkiem nieźle ... dopóki nie zostanie zniszczone jedno lub oba skrzydła, wtedy zwykle jest to tylko kwestia czasu, zanim spadnie.

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

Leci z pełną prędkością od słońca w kierunku krawędzi mapy! Kiedy zostanie skierowany w stronę słońca, zacznie strzelać, jednocześnie odwracając się, by wrócić na krawędź. Wchodzi również w nadprzestrzeń, gdy ma uderzyć w słońce.

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

Ten bot jest już dostępny! Również ten był zaskakująco łatwy do przetrwania. Prawdopodobnie ma to związek z tym, że nie spamuje pocisków wszędzie tak jak niektóre inne. : P
El'endia Starman

7

OrbitBot

Obecnie nie ma możliwości celowania ani unikania kolizji . Próbuje okrążyć słońce.

Edycja: Teraz przechodzi w nadprzestrzeń, gdy nadciągają uderzenia.

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

Twój bot został dodany.
Conor O'Brien,

Twoja aktualizacja jest już dostępna!
El'endia Starman,

5

Skurcze praworęczne

Nazwa jest dość opisowa. Wybiera turn rightz prawdopodobieństwem 0,5, prawdopodobieństwem fire engine0,5 i fire missileprawdopodobieństwem 0,8. Zaskakująco trudne, głównie dlatego, że jest naprawdę nieprzewidywalne.

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

To wyzwanie wymagało losowego bota. Punkty bonusowe za golfa?

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

Chłodny! (Nawiasem mówiąc, mój bot wygrał 13-7 Not. Za dużo, biorąc pod uwagę, że stracił 9-1 raz, ale to dużo punktów w sumie 20 punktów w 90 sekund.!)
ev3commander

@ BlockCoder1392 to jest losowa Bot;)
Conor O'Brien

4

Inżynier

Lubi korzystać z hiperprzestrzeni, gdy jest w niebezpieczeństwie. Aby zobaczyć prawdziwą moc, otwórz konsolę przeglądarki i wpisz overideHyperspace = 0;. Jeśli zapomnisz średnika, dostaniesz ASI na Boże Narodzenie.

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

Wystrzeliwuje dziko we wszystkich kierunkach. To nie jest bardzo skuteczne!


Ten bot jest już dostępny!
El'endia Starman

3

Kamikadze

Niezbyt konkurencyjny, ale pomyślałem, że będzie fajnie! Leci prosto w stronę przeciwnika podczas strzelania.

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

Twój bot został dodany!
Conor O'Brien,

Straszny przeciwko
Oponentowi Oddgerowi

2

UhhIDKWhatToCallThisBot

Po prostu losowe rzeczy.

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

co jest z tajemniczą golfowością?
noɥʇʎԀʎzɐɹƆ

2

OpponentDodger

ODDAJ SIĘ OD MNIE PRZECIWNIKA !!!

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

Dzięki user81655 za trochę kodu!


Ten bot jest już dostępny!
El'endia Starman,

2

Szpieg

Historia

Prototypem tego bota był bot, który miał dwa tryby: tryb szalony i tryb normalny. Gdy był w trybie szalonym, pozostawał tam przez stałą liczbę tyknięć. Prawdopodobieństwo przejścia w tryb szalony było stałe. Przesunął się też hiperprzestrzennie, gdy był blisko słońca. W trybie szalonym celował w drugiego bota i ciągle strzelał. W trybie normalnym odleciał od drugiego bota, nie strzelając.

Ulepszyłem ten prototyp, aby działał w trybie szalonym, gdyby tylko wróg był wystarczająco blisko. Potem wpadłem na szalony pomysł: co, jeśli pozostanie tylko w trybie szalonym? Po kilku eksperymentach (dodałem losowe uruchamianie bota, gdy był on w trybie normalnym), znalazłem nowego bota, który pokonał każdego bota oprócz Heliosa. To jest mój kod na koniec tego procesu, ale przed czyszczeniem.

Cały mój bot napisałem w obszarze tekstowym KotH lub upiększaczu JS. (Podczas czyszczenia użyłem krótko edytora Atom - ale dla dwóch linii kodu)

Bot

Ten bot zawiera dużo kodu zapożyczonego z innych botów. Odwraca kod z Kamikaze, aby uciec od drugiego bota zamiast biegać do drugiego bota, i pobiera kod z EdgeCase do hiperprzestrzeni, gdy jest blisko słońca.

Jego arch-nemezis to Helios. To dziwne i długie rozmowy z martini.

Ucieka od drugiego bota z 70% szansą na wystrzelenie pocisku i hiperprzestrzeni, gdy jest blisko słońca. Tak proste jak to. Tak.

Edycja: Przetestowałem mojego bota z nowym kodem i nie działa dla każdego innego bota. Pracuję nad naprawą. Właśnie potwierdziłem, że to tylko dla mojego nowego bota.

Kod

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

Misc

Uwaga: Mogłem coś zepsuć podczas czyszczenia kodu, ponieważ nie przetestowałem bota po wyczyszczeniu kodu.

Jest także o wiele znacznie lepszy niż wszystkie moje inne boty - faktycznie pokonał każdego innego bota oprócz Heliosa (edycja) , SetCourseFor30Degrees i OrbitBot! Wiąże się z SunAvoider.

Uwaga dodatkowa: Jestem okropny w javascript, nie wiem dlaczego.


@ El'endiaStarman, proszę włączyć pauzę na żywo; Muszę naprawić mojego bota - wyczyszczona wersja jest o wiele gorsza niż wersja nieczysta.
noɥʇʎԀʎzɐɹƆ

W porządku, daj mi znać, kiedy będzie to naprawione.
El'endia Starman

@ El'endiaStarman Zrobiłem coś, a potem znowu zadziałało. Debugowanie, wiesz! (jeszcze nie zrobione)
noɥʇʎԀʎzɐɹƆ

@ El'endiaStarman ... i gotowe!
noɥʇʎԀʎzɐɹƆ

Ten bot jest już dostępny!
El'endia Starman

1

AttackAndComeBack

Zamiast wirować, wchodzi na górę i wychodzi na dole (wraca na górę), strzelając bardzo szybko. Ogólnie unika słońca.

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

Ten bot jest już dostępny!
El'endia Starman,

1

Cała naprzód

Zawsze odpala zarówno silniki, jak i pociski, nie obracając się nigdy. Czasami trwa zaskakująco długo przed uderzeniem w słońce.

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

Nie tak źle, jak myślałem ...
noɥʇʎԀʎzɐɹƆ

Ten bot jest już dostępny!
El'endia Starman,

1

Atak paniki

Ma 50% szansy na ostrzał i 80% szansy na skręt w lewo; ale jeśli nie skręci w lewo, skręci w prawo. Po tym, jak zabraknie pocisków, czas ostatecznie zatrzyma go z powodu słońca.

EDYCJA: Dodano trochę logiki, aby nie strzelać, gdy wróg żyje, ponieważ może zostać zabity przez własne pociski.

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

Ten bot jest już dostępny!
El'endia Starman,

@ El'endiaStarman Zaktualizuj go ponownie
nie

Twoja aktualizacja jest już dostępna!
El'endia Starman,

1

DangitBobby

Bobby Hill nie dba o to, co myślą o nim inni - jest zadowolony z tego, że leniwie kołysze się po boisku i cierpliwie czeka, aż jego przeciwnik wyczerpie się, zanim uderzy jak „husky” kobra.

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

    }
}

„TO MOJA PRZEKŁADKA! NIE WIEM CIEBIE!”


Ten bot jest już dostępny!
El'endia Starman

1

Snajper

Przez pewien czas bawiłem się z przewidywaniami, aby stworzyć snajperskiego bota, który snajperuje jego wrogów. Mój javascript jest zbyt duży, aby zmieścił się w odpowiedzi, więc oto link, bot_Sniper .


W końcu przystąpiłem do testowania tego bota i niestety naprawdę spowalnia grę. Jest dość niepewny, więc musisz jakoś przyspieszyć swój kod.
El'endia Starman

Następnym razem powinieneś opublikować go w serwisie takim jak [GitHub Gists] (gist.github.com), który jest przeznaczony dla kodu.
noɥʇʎԀʎzɐɹƆ

Spróbuj zoptymalizować swój kod; Założę się, że to naprawdę dobry bot, biorąc pod uwagę jego długość. Możesz spróbować wprowadzić niektóre zmienne lub funkcje.
noɥʇʎԀʎzɐɹƆ

Masz również trochę zduplikowanego kodu - myślę, że dużo byś zyskał na opublikowaniu swojego bota w recenzji kodu podczas wymiany stosu.
noɥʇʎԀʎzɐɹƆ

Możesz także zdefiniować funkcje, które umieścisz w Actions () w zakresie zewnętrznym, więc interpreter nie musi go ponownie analizować za każdym razem, gdy uruchamiasz Actions (). Powinieneś także spróbować profilować swój kod, aby go przyspieszyć.
noɥʇʎԀʎzɐɹƆ

1

SmartArrow

Jak Arrow, ale mądry

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

Ten bot jest już dostępny!
El'endia Starman

1

Kamikadze

Również nie zaprojektowany, aby być konkurencyjnym. Dla żartu. Nadprzestrzeń przesuwa się blisko słońca i goni gracza bez wystrzeliwania pocisków. Fajnie jest oglądać tego bota ścigającego nieuzbrojoną wersję Szpiega, ale niestety nie możesz mieć więcej niż jednego użytkownika.

El'endia: kiedykolwiek rozważałeś dodanie więcej niż jednego użytkownika;)

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

Właśnie wziąłem kod Kamikaze + i pozbyłem się części wystrzeliwującej pocisk.


Prawdopodobnie nie dodam tego bota, ponieważ mieliśmy już jednego innego bota Kamikaze i wolałbym nie mieć trzech botów. Poza tym ten jest bardziej trywialny niż pozostałe dwa.
El'endia Starman

@ El'endiaStarman następnie żądam wielu botów użytkowników - pole kodu drugiego może być domyślnie ukrytym rozszerzalnym
noɥʇʎԀʎzɐɹƆ

0

MissilesPlusScore

Wymyśliłem jakiś dziwny pomysł, który zakłada, że ​​bezwzględna wartość różnicy wyników i wykorzystuje listę ruchów w sposób losowy w oparciu o sposób gry. Działa dobrze przeciwko botom ze strategią, ale nie sprawdza się w przypadku burz pocisków. Także mój pierwszy .

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 JEST CHŁODNE !!!!!!!!!!!!!!!!

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

Oparty na współrzędnych, zaskakująco skuteczny:

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

Oba te boty działają na żywo.
El'endia Starman

Zamiast tego powinieneś opublikować wiele odpowiedzi.
noɥʇʎԀʎzɐɹƆ

Jeśli kiedykolwiek dodasz innego bota, wyślij mi ping, aby wiedzieć, że to zrobiłeś. Twój trzeci bot jest już włączony.
El'endia Starman

0

SetCourseFor30Degrees

Nie mam pojęcia, dlaczego kapitan tak bardzo nalega na ustawienie statku na kurs o 30 stopni, ale hej, jako mały chorąży, kogo masz pytać? Przynajmniej masz pozwolenie na unikanie słońca! I możesz strzelać z pocisków ... po prostu nie wolno ich celować ...

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

Ten bot jest już dostępny!
El'endia Starman

0

Strzałka

Po prostu ścigaj jego wroga, hiperprzestrzeń, gdy jest w niebezpieczeństwie, i bezczynnie, gdy jego wróg nie żyje.

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

Ten bot jest już dostępny!
El'endia Starman

@ El'endiaStarman Zaktualizowałem bota
TuxCrafting,

Aktualizacja jest już dostępna! Jednak niewiele z tego. : P
El'endia Starman

0

Kamikaze +

Nie zaprojektowany, aby być konkurencyjnym.Dla żartu. Technicznie robi to odwrotnie niż Szpieg: ściga gracza, hiperprzestrzeń gdy jest blisko słońca, wystrzeliwuje pocisk w 70% przypadków. Po prostu chcę zobaczyć, jak KamikazePlus goni Szpiega i Szpiega uciekającego jak szaleniec.

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

Zasadniczo po prostu wziąłem kod Szpiega i przerzuciłem „w lewo” i „w prawo”.


Ten bot jest już dostępny! I tak, fajnie jest oglądać KamikazePlus ścigającego Szpiega. : P
El'endia Starman

@ El'endiaStarman Uważam, że fajnie jest oglądać, jak KamikazePlus walczy bez kul overideHyperspace = 0;; po prostu zaginęli, kiedy próbowali na siebie rzucić.
noɥʇʎԀʎzɐɹƆ
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.