Team of The Hill!

27

Wyzwanie to zostało zainspirowane doskonałym wyzwaniem @HelkaHomba Red vs. Blue - Pixel Team Battlebots . To wyzwanie było prawdopodobnie najlepszym, jakie widziałem na tej stronie. Zawsze.

Moje wyzwanie jest wciąż inne, ale @HelkaHomba zasługuje na uznanie za inspirację.

Przegląd

To drużynowy którym Twoja drużyna wygrywa, przy życiu wszystkich graczy. Innymi słowy, ostatnia drużyna stojąca wygrywa. Losowania zostaną ponownie wykonane.

Jesteś na tablicy. Znasz swoją pozycję w pierwszej rundzie (zaznacz 0). Wiesz także, kto jest w pobliżu:

Pojedynczy czerwony kwadrat na siatce 9 x 9, otoczony białymi komórkami.

W takim przypadku jesteś zupełnie sam (a przynajmniej tak ci się wydaje) bez nikogo w pobliżu. Możesz zobaczyć otaczające elementy w pierwszym argumencie do twojego ontickhandlera. Więcej o API później.

Twój zespół

Twój zespół jest określany na podstawie identyfikatora użytkownika. Aby się tego dowiedzieć, kliknij swoje zdjęcie profilowe:

Moje zdjęcie profilowe

Następnie znajdź swój identyfikator użytkownika w pasku adresu:

Jest pomiędzy / users / i / yourusername

Jeśli to dziwne, jesteś w niebieskiej drużynie.

Jeśli jest parzysty, jesteś w czerwonej drużynie.

Zapraszamy do ręcznie narysowanych kół.

Twoje imię (bota)

Nazwa twojego bota zaczyna się od pierwszej litery twojego zespołu („r” lub „b”). Musi pasować do wyrażenia regularnego /^(r|b)[A-Za-z_-]$/. Poza tym możesz wybrać nazwę bota. Nie używaj już istniejącego.

Startowy

Czerwoni gracze zaczną się u góry mapy, a niebieski zaczną u dołu. Otrzymasz specjalne informacje o pierwszym tiku (skręcie) w environmentparametrze ontickfunkcji. Polecam to przechowywać. Szczegółowe informacje można znaleźć w interfejsie API.

Na twoją kolej

Kolejność tur jest początkowo losowa, ale potem pozostaje taka sama.

Włącz akcje

Możesz wykonać tylko jedną akcję na turę.

  • Ruszaj się

    Gdy chcesz się przenieść, wywołujesz this.move(num)interfejs API. numto komórka, do której chcesz przenieść:

    0 to górny lewy, 1 to górny środkowy, 2 to górny prawy, 3 to środkowy prawy, 4 to środkowy lewy, 5 to dolny lewy, 6 to dolny środkowy, a 7 to dolny prawy.

    Względne lokalizacje liczb, do których można się przenieść, są przechowywane w stałej globalnej threeByThree:

[
    [0, 1, 2],
    [3, undefined, 4],
    [5, 6, 7]
]

Jeśli wejdziesz do ściany lub innego gracza, nic się nie stanie.

  • Obracać się

    Aby obrócić, dzwonisz this.rotate(num). Num to kierunek, który chcesz obrócić:

    0 jest na górze, 1 na prawo, 2 na dole, a 3 na lewo

    Rotacja jest absolutna.

  • Zabić

    Jeśli inny gracz (z innej drużyny) znajduje się w komórce, w której stoisz, możesz do niego zadzwonić this.kill()i zabić. Jeśli nikogo tam nie ma lub są w twoim zespole, to nic nie robi. Przykład:

    Te same liczby jak powyżej, komórka 0 jest zielona, ​​1 jest niebieska, 2 jest pomarańczowa, a 3 jest żółta

    Jeśli się odwrócisz 0, możesz zabić zielonego. Jeśli zmienisz na 1, możesz zabić niebieski. Jeśli zmienisz na 2, możesz zabić pomarańczę. Jeśli zmienisz na 3, możesz zabić żółty.

  • Bomba

    Bombardowanie zabija wszystkich graczy, w tym ciebie i członków drużyny na 9 polach wokół ciebie. Przykład:

    W każdej komórce znajduje się siatka 9x9 ze znakami „x”.

    Dlaczego miałbyś to robić? Kamikadze . Jeśli w 9 komórkach wokół ciebie jest więcej graczy, którzy nie są w twojej drużynie, to w twojej drużynie jest więcej graczy , możesz rozważyć zbombardowanie. (Radzę najpierw powiadomić swoich towarzyszy!)

  • Umieść minę

    To tworzy kwadrat śmierci dla osób spoza zespołu. Kiedy umieszczasz minę, również się poruszasz, aby na nią nie nadepnąć. Nazywasz this.landMine(num)gdzie num jest kwadratem chcesz się udać. Przykład:

    Pojedynczy czerwony kwadrat na siatce 9 x 9, otoczony białymi komórkami.

    Następnie dzwonisz this.landMine(4):

    [Siatka 9x9, z czerwonym „M” pośrodku i czerwoną komórką w środku po prawej stronie.

    Widzisz to „M”? To mina. Inni to widzą ... na razie. Każdy, nawet nie należący do twojego zespołu, może zobaczyć minę na kleszczu, który jest umieszczony. Ale po tym kleszczu już nie ma, nikt, nawet ty go nie widzisz. Ale eksploduje, gdy tylko nadejdzie wróg. Przykład:

    Dwie siatki 9x9, niebieska komórka po środku po lewej w pierwszej, czerwona litera „M” na środku pierwszej, czerwona „x” na środku drugiej i strzałka między nimi.

    Niebieski porusza się po twojej minie i BOOM! Właśnie dostałeś kolejnego zabójstwa.

    Za każde 2 zabójstwa, które otrzymujesz (z bezpośredniego zabijania lub min), dostajesz 1 dodatkową minę na miejsce. Dostajesz też jeden na początku.

  • Kopać

    Podczas kopania szukasz min przeciwpiechotnych w obszarze 5 x 5, który jest wokół ciebie. Nie pokazuje to zespołu bota, który umieścił minę. (Pamiętaj, że nie możesz zostać zabity przez minę lądową umieszczoną przez kogoś w twojej drużynie). Na przykład, jeśli była to siatka wokół ciebie:

    Wtedy zwracana wartość this.dig()to:

[undefined,undefined,undefined,true,undefined,
undefined,undefined,undefined,undefined,undefined,
undefined,undefined,undefined,undefined,
undefined,undefined,true,undefined,undefined,
true,undefined,undefined,undefined,undefined]

Indeksy tablic zaczynają się od lewego górnego rogu, w prawo, niż w dół, nie obejmując ciebie:

W sumie jest ich 23, a ich względne lokalizacje są przechowywane w stałej globalnej fiveByFive:

[
    [0, 1, 2, 3, 4],
    [5, 6, 7, 8, 9],
    [10, 11, undefined, 12, 13],
    [14, 15, 16, 17, 18],
    [19, 20, 21, 22, 23]
]

Zauważ, że wykop odsłania miny umieszczone na poprzednich kleszczach, w przeciwieństwie do aroundMe.

Komunikacja

Kiedy chcesz z kimś porozmawiać, dzwonisz this.sendMessage(recipients, team, data). Dane mogą być dowolne i możesz je wysłać do dowolnej osoby, nawet graczy z innych drużyn. Można to wykorzystać do oszukiwania źle zaprogramowanych botów, ale wszyscy gracze mogą zobaczyć, kto wysłał wiadomość i do kogo należą.

Przykład:

Wyślij coś do bota o nazwie „redisbest”:

this.sendMessage("redisbest", undefined, "Hi!");

Wyślij coś do bota o nazwie „redisbest” i „blueiscool”:

this.sendMessage(["redisbest", "blueiscool"], undefined, {hello: "there"});

Wyślij coś do całej czerwonej drużyny

this.sendMessage(undefined, "red", {hello: "red"});

Wyślij coś każdemu

this.sendMessage(undefined, "*", {hello: "everyone"});

Wyślij coś do całego czerwonego zespołu i bota o nazwie „blueiscool”:

this.sendMessage("blueiscool", "red", {hello: "bots"});

API

Kod powinien składać się z jednego połączenia do createBotfunkcji. Nic więcej. Przykładowy kod:

createBot({
    ontick: function(environment) {
        return new Promise((resolve, reject)=>{
            this.move(0);//example
            resolve();//please call this when you are done
        });
    },
    onmessage: function(data, from, fromBot) {
        console.log("onMessage: " + this.name + " from " + this.team + " got message ", data, " from " + from + ", on team " + fromTeam);
        this.sendMessage(["bot", "otherbot"], "team", "some data");
    },
    team: "red",//your team
    name: "rmyteamname",//team name must begin with the first letter of your team's name
    onkill: function(){
        //say goodbye
    }
});

(Możesz to skopiować i wkleić. Po prostu zmodyfikuj dla swojego zespołu itp.)

Metody

  • ontick(environment)

    Wywoływany, kiedy jest twoja kolej. Musi zwrócić a, Promisektóre rozwiązuje się w ciągu 1 sekundy lub krócej, albo zostanie zignorowane. Jest to spowodowane wydajnością i ma fajny efekt uboczny polegający na tym, że karta się nie zawiesiła.

    this (w trybie ontick)

    • landMines Ile min min pozostało. Im więcej zabijasz, tym więcej masz min lądowych. Za każde 2 roboty, które zabijesz, zyskujesz 1 dodatkową minę lądową. Dostajesz także 1, aby rozpocząć.
    • direction Kierunek, w którym patrzysz.
    • storage Pamięć, która utrzymuje się między połączeniami do onTicki onMessage. Pusty obiekt na początku. Modyfikuj w dowolnym celu, ale upewnij się, że jest to tablica lub obiekt zawsze, aby upewnić się, że nadal działa poprawnie.
    • move(num) Przejdź do określonej pozycji. Nie robi nic, jeśli jest nieprawidłowy. Szczegóły powyżej.
    • rotate(num) Obróć do określonej pozycji. Nie robi nic, jeśli jest nieprawidłowy. Szczegóły powyżej.
    • kill() Zabija gracza, z którym się mierzysz, jeśli istnieje i nie należy do twojej drużyny. Szczegóły powyżej.
    • bomb() Zabija każdego na 9 polach wokół ciebie, w tym ciebie.
    • landMine(num) Umieszcza minę, gdzie jesteś, a następnie przesuwa się na określoną pozycję. Nie robi nic, jeśli jest nieważny numlub nie masz go już. Szczegóły powyżej.
    • dig() Nowy! Zwraca tablicę informacji o minach w obszarze 5x5, który jest wokół ciebie. Szczegóły powyżej.
    • sendMessage(recipients, team, data) recipientsmoże być pojedynczym botem (ciągiem), tablicą bota lub undefined/ null. To do kogo chcesz wysłać wiadomość. teamto ciąg zespołu, który chcesz wysłać wiadomość. Służy "*"do wysyłania wiadomości do wszystkich. datato wszystko, co można przekazać do funkcji JS. Jest wysyłany do odbiorców. Jeśli jest to obiekt lub tablica, jest przekazywany przez referencję , więc ty i odbiorca (-ci) możecie zapisać to na sobie, storagea wszelkie modyfikacje obiektu wpływają na kopie obu botów. Zauważ, że odbiorcy, którzy znajdują się na liście botów, dokładnego bota określonego w ciągu lub bota w podanym zespole, otrzymają wiadomość.

environment

Na pierwszym tyknięciu

  • x: Pozycja x twojego gracza
  • y: Pozycja y twojego gracza
  • gridWidth: Szerokość siatki (w komórkach)
  • gridHeight: Wysokość siatki (w komórkach)

    Na wszystkich kleszczach

  • aroundMe: Tablica graczy i min. Gracze to obiekty, które wyglądają podobnie jak {name: "bot name", team: "bot team"}miny {team: "team of bot who placed mine"}. Indeksy tablicy:

    0 to górny lewy, 1 to górny środkowy, 2 to górny prawy, 3 to środkowy prawy, 4 to środkowy lewy, 5 to dolny lewy, 6 to dolny środkowy, a 7 to dolny prawy.

    Pamiętaj, że miny umieszczone na kleszczu innym niż bieżący nie zostaną pokazane.

    aroundMe przykład:

    Powiedzmy, że to jest siatka (jesteś czerwony):

    Siatka 9x9, z jasnoniebieskim w lewym górnym rogu, szarym „M” w prawym górnym rogu, czerwonym w środku, żółtym w środkowym lewym rogu i czerwonym „M” w lewym dolnym rogu.

    Twój aroundMebędzie wyglądał następująco:

[
    {name: "bexamplebluebot", team: "blue"},
    undefined,//sparse array, nothing in index 1
    undefined,//there is technically a landmine here, but it wasn't placed this tick, so it is not shown
    undefined,//nothing in 3
    {name: "yexampleyellowbot", team: "yellow"},
    {team: "red"},//this is a landmine, you can tell is not a bot because it has no name. mines have the team name of the player they were placed by. This mine was placed this tick, otherwise you couldn't see it
    //nothing else after index 5, so the array's length is 5.
]

Indeksy tablicy są wyjaśnione tutaj:

0 to górny lewy, 1 to górny środkowy, 2 to górny prawy, 3 to środkowy prawy, 4 to środkowy lewy, 5 to dolny lewy, 6 to dolny środkowy, a 7 to dolny prawy.

Twój bot skutecznie widzi to:

Jasnoniebieskie pole w lewym górnym rogu z czarną liczbą 0, żółte pole na lewej krawędzi z czarną liczbą 4 i czerwone „M” w lewym dolnym rogu z czarną 5 na nim.

  • onmessage(data, fromBot, fromTeam)

    this (w wiadomości)

    • sendMessage(recipients, team, data) Standardowa funkcja wysyłania wiadomości.
    • storage Standardowe przechowywanie.

    dataDane wysłane od nadawcy. fromPlayerGracz, z którego wiadomość została wysłana. fromTeamZespół, z którego wysłano wiadomość.

  • onkill()

    this (gdy onkill)

    • sendMessage(recipients, team, data) Standardowa funkcja wysyłania wiadomości.

Wygodne (stałe) tablice globalne:

threeByThree:

[
    [0, 1, 2],
    [3, undefined, 4],
    [5, 6, 7]
]

Przydatny do przekazywania danych do funkcji przenoszenia oraz tłumaczenia aroundMe. Patrz wyżej.

fiveByFive :

[
    [0, 1, 2, 3, 4],
    [5, 6, 7, 8, 9],
    [10, 11, undefined, 12, 13],
    [14, 15, 16, 17, 18],
    [19, 20, 21, 22, 23]
]

Przydatne dla this.dig()funkcji w ontickprzewodnika.

Wypróbuj to!

Kontroler będzie uruchamiany z mojego komputera na hoście lokalnym ze względu na wydajność, ale możesz użyć CodePen do przetestowania swojego bota.

Pamiętaj, że musisz wkleić kod w konsoli i nacisnąć Enterprzed kliknięciem przycisku Uruchom. Możesz wkleić tyle botów, ile chcesz. „Boty testowe” są przykładami do przetestowania. Jeśli potrafisz je wszystkie pokonać lub związać, masz przynajmniej przyzwoitego bota.

Zgłoszenia

Zasady

Zasady (egzekwowane przez kontrolera)

  • Twój główny ontickkod nie może zająć więcej niż 1 sekundę. Nie chcemy, aby rundy trwały wiecznie. Jeśli Twój kod zajmie> 1 sekundę, zostanie zatrzymany.
  • Jeśli spróbujesz wykonać więcej niż 1 akcję na turę lub wykonasz nieprawidłową akcję (np. this.move(-1) Lub przejście do ściany), zostanie to zignorowane.
  • Więcej może wkrótce ...

Reguły (egzekwowane przeze mnie mogą powodować DQ)

  • Nie pisz zmiennych globalnych ( czytanie jest w porządku ).
  • Twój kod musi działać w Nodejs (w przypadku, gdy kontroler jest przeniesiony do Nodejs), więc JSON.parse(...)jest w porządku, ale alert()nie jest.
  • Nie możesz createBotw żaden sposób dzwonić lub ingerować w kontroler .
  • Nie używaj cudzego kodu bez pozwolenia i znaczących zmian. Bez kopiowania.
  • Proszę, żadnych luk!
  • Więcej może wkrótce ...

Moje boty

Oto niektóre boty:

Ten bot losowo wybiera akcję. Cóż, jest ważony losowo, ale wciąż dość losowo. Jeśli możesz zabić tego bota (w końcu sam się zabije, to się nie liczy), to masz przynajmniej przyzwoitego bota. Opublikuj i zobacz, co się stanie!

Moje boty mają nazwę zaczynającą się od „x” i zespół „none”. Zapraszamy do korzystania z niektórych tego kodu, ale proszę zrobić przynajmniej kilka modyfikacji. Jeśli nie będziesz miał najmniejszych kłopotów z poprawieniem numeru, nie wygrasz.

Formatowanie zgłoszenia

Proszę użyć tego formatu:

# rmyamazingbot

    createBot({
        ontick: function(environment) {
            return new Promise((resolve, reject)=>{
                this.move(0);//example
                resolve();//please call this when you are done
            });
        },
        onmessage: function(data, fromTeam, fromBot) {
            console.log("onMessage: " + this.name + " from " + this.team + " got message ", data, " from " + from + ", on team " + fromTeam);
            this.sendMessage(["bot", "otherbot"], "team", "some data");
        },
        team: "red",//your team
        name: "rmyteamname",//team name must begin with the first letter of your team's name
        onkill: function(){
            //say goodbye
        }
    });

Long, but cool explanation...

Prośby o nowe funkcje, błędy, pytania itp.?

Komentarz poniżej! Sprawdź, czy jest już z tym komentarz. Jeśli już istnieje, oceń go.

Chcesz porozmawiać ze swoim zespołem?

Korzystaj z pokojów czatowych w kolorze czerwonym i niebieskim .

Język

Obecnie obsługiwany jest tylko JS i coś, co kompiluje się do JS, ale jeśli znasz sposób, aby inne języki współpracowały z Nodejsem, chętnie przeniesie kontroler do Nodejsa.

Uwagi końcowe

Pomysły na strategię

Pomóż swojemu zespołowi! Stworzenie bota, który ma pomóc innym botom i współpracować ze sobą. Ta strategia działała dobrze dla Red vs. Blue - Pixel Team Battlebots

Osoby poszukujące przedstawicieli

Przyjmuję najwyższą głosowaną odpowiedź na zwycięską drużynę. Należy pamiętać, że wcześniejsze odpowiedzi zwykle zdobywają więcej głosów, ale ich słabości są bardziej prawdopodobne do znalezienia i wykorzystania.

Ponadto, jeśli odpowiesz wkrótce, możesz otrzymać nagrodę +100.

programmer5000
źródło
1
Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
Dennis
Czy mogę zrobić więcej niż jednego bota? (przepraszam, wiem, że rozmowa została przeniesiona, jestem po prostu zbanowany na czacie, więc tak)
Matthew Roh
@SIGSEGV tak, ale ktoś inny musi to opublikować. Możesz wysłać jednego bota i podać kod innego komuś z twojego zespołu, ale nie możesz wysłać dwa razy.
programista
Jeśli chodzi o pozycjonowanie, gdzie jest komórka indeksowana [0, 0], czy jest to komórka w lewym górnym rogu? Czy wysyłanie wiadomości pochłania twoje działanie (na turę)? Dzięki.
Thrax,
@ Thrax tak i nie. Możesz nawet wysłać wiadomość w odpowiedzi na wiadomość.
programator5000

Odpowiedzi:

7

xscared (niekonkurujący)

createBot({
    ontick: function(environment) {
        var reverse = [0, 1, 2, 3, 4, 5, 6, 7].reverse();
        return new Promise((resolve, reject)=>{
            (this.aroundMe || []).forEach((item,idx)=>{
                this.move(reverse[idx]);
                return resolve();
            });
            this.move(~~(Math.random() * 8));
            return resolve();
        });
    },
    onmessage: function() {
    },
    team: "none",
    name: "xscared",
    onkill: function(){
    }
});

Bardzo boję się ludzi. Odchodzi od pierwszej osoby (lub miny), którą widzi. W przeciwnym razie porusza się losowo. Pamiętaj, że to nie jest konkurencja, tylko przykład. Spróbuj go pokonać!

programmer5000
źródło
6

backup, niebieski bot

Jak ostrzegałem na czacie, w moim życiu nigdy nie pisałem niczego w języku JavaScript, więc jeśli znajdziesz jakiś błąd, powiedz mi! (Podziękowania dla @ programmer5000 za to, że już mi pomogłem)
. Koncepcja tego bota polega na tym, że komunikuje się on z innymi botami z tego samego zespołu i wysyła im swoją pozycję wraz z mapą znalezionych min. Próbuje dołączyć do najbliższego niebieskiego bota (jeśli ktoś wysyła dane o swojej pozycji [podane jako tablica [x, y]]) i pozostaje blisko niego (odwrócony do niego jak najwięcej), zabijając zbliżające się czerwone boty lub szukając naprzód dla kopalni.

createBot({
    team: 'blue',
    name: 'backup',
    ontick: function(environment) {
        return new Promise((resolve, reject) => {
            //if (typeof this.x != "undefined") this.storage['position'] = [this.x, this.y];
            if (typeof environment.x != "undefined") this.storage['position'] = [environment.x, environment.y]; //Modified according to @WasteD
            if (typeof this.storage['map'] == "undefined") { //Create empty map
                var map = [[]];
                //for(i=0;i<this.gridHeight;i++) map[i]=[];
                for(i=0;i<environment.gridHeight;i++) map[i]=[]; //Modified according to @WasteD
                this.storage['map'] = map;
            }
            var blue = []
            var red = []
            var x = this.storage['position'][0];
            var y = this.storage['position'][1];
            var dx = [-1, 0, 1, -1, 0, 1, -1, 0, 1]
            var dy = [1, 1, 1, 0, 0, 0, -1, -1, -1]
            (this.aroundMe || []).forEach((item, idx) => { // Update map and list positions of surrounding blues and reds
                if (item && item.team == 'red' && typeof item.name != "undefined") red += idx;
                if (item && item.team == 'red' && typeof item.name == "undefined") this.storage['map'][x+dx[idx]][y+dy[idx]] = 'M';
                if (item && item.team == 'blue' && typeof item.name != "undefined") blue += idx;
            });
            this.sendMessage(undefined, "blue", {"position": this.storage['position'], 'map': this.storage['map']}); //Send to buddies my position and the map
            if (red.indexOf([1, 4, 6, 3][this.direction]) > -1) this.kill() ; //If red guy is in front of
            else if (red.indexOf([1,4,6,3]) > -1) this.rotate(red.indexOf([1,4,6,3])); //If red guy is next but not in front of
            else if (blue.indexOf(3) > -1){ //If blue buddy on the left
                if (blue.indexOf(4) > -1){ //If another one is on the right
                    if (blue.indexOf(1) > -1 && this.direction != 2) this.rotate(2); //...and a third one at the top
                    else var digging = this.dig();
                    }
                else if (this.direction != 1) this.rotate(1);
                else var digging = this.dig();
            }
            else if (blue.indexOf(1) > -1){
                if (blue.indexOf(6) > -1 && this.direction != 3) this.rotate(3);
                else if (this.direction != 2) this.rotate(2);
                else var digging = this.dig();
            }
            else if (blue.indexOf(4) > -1){
                if (this.direction != 3) this.rotate(3);
                else var digging = this.dig();
            }
            else if (blue.indexOf(6) > -1 && this.direction != 0) this.rotate(0);
            else if (blue.indexOf([0,2]) > -1){ //If no blue next to me but one in diagonal, move next
                this.move(1);
                this.storage['position'][1] = y+1; //Update position
            }
            else if (blue.indexOf([5,7]) > -1){
                this.move(6);
                this.storage['position'][1] = y-1;
            }
            else if (typeof this.storage['other_blue'] != "undefined"){ //Check if buddies said where they were, try to go near the closest one
                var dmin = 99999;
                var pos = []
                (this.storage['other_blue'] || {}).forEach((item, idx) => {
                    var d = Math.sqrt(Math.pow(item['position'][0]-x,2) + Math.pow(item['position'][1]-y,2));
                    if (d < dmin){
                        dmin = d;
                        pos = item['position'];
                        }
                });
                if (pos[0]-x > 0){
                    this.move(4);
                    this.storage['position'][0] = x+1
                }
                else if (pos[0] < 0){
                    this.move(3);
                    this.storage['position'][0] = x-1
                }
                else if (pos[1] > 0){
                    this.move(1);
                    this.storage['position'][1] = y+1
                }
                else{
                    this.move(6);
                    this.storage['position'][1] = y-1
                }
            }
            else var digging = this.dig();
            if (typeof digging != "undefined"){ //Check out surroundings if dig() was played and update the map accordingly
                var dx2 = [-2,-1,0,1,2,-2,-1,0,1,2,-2,-1,0,1,2,-2,-1,0,1,2,-2,-1,0,1,2];
                var dy2 = [2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2];
                (digging || []).forEach((item, idx) => {
                    //if (item && item.team == 'red' && typeof item.name == "undefined") this.storage['map'][x+dx2[idx]][y+dy2[idx]] = 'M';
                    if (item) this.storage['map'][x+dx2[idx]][y+dy2[idx]] = 'M'; //previously misread what dig() returned
                });
            }
            resolve();
        });
    },
    onmessage: function(data, fromTeam, fromBot) {
        if (typeof data['position'] != "undefined" && fromTeam == 'blue') { //If position sent by a blue bot
            if (typeof this.storage['other_blue'] == "undefined") this.storage['other_blue'] = [];
            for (i in this.storage['other_blue']){
                var found = false;
                if ('name' in i){
                    if (i['name'] == fromBot){
                        i['position'] = data['position'];
                        found = true; //Update if position already known from previous ticks
                        }
                }
            }
            if (!found) this.storage['other_blue'] += {'position':data['position'], 'name':fromBot}; //Add position if previously unknown
            this.sendMessage(fromBot, undefined, "roger.");
        }
    },
    onkill: function() {this.sendMessage(undefined, "blue", {"position": this.storage['position'], 'map': this.storage['map']});}
});
plannapus
źródło
Hej, nie przejmuj się, jeśli również to wprowadzę, ale (pod innym imieniem) jestem też na niebiesko
Christopher
@Christopher Nie, nie mam nic przeciwko, ale byłoby to trochę bardziej interesujące dla ciebie i dla zespołu, jeśli zrobisz co najmniej trochę inny (przynajmniej jako uzupełnienie 2 botów, które już istnieją).
plannapus
Zrobi to. Zmienię to
Christopher
Jeśli spróbuję uruchomić twojego bota w codepen, to nie działa, ponieważ używasz this.xi tak dalej, ale jest, environment.xczy się mylę?
WasteD
@WasteD, jak powiedziałem, w ogóle nie znam Javascript, więc jest to możliwe. Ale jeśli tak jest, to chyba też powinno być environment.gridHeighti environment.aroundMe? W takim przypadku inne boty też nie powinny działać, ponieważ używają this.aroundMe.
plannapus
5

Niebieski, niebieski, mój świat jest niebieski

createBot({
    team: 'blue',
    name: 'blue-blue-my-world-is-blue',
    ontick: function(environment) {
        return new Promise((resolve, reject) => {
            var red = 0;
            // See who's around me
            (this.aroundMe || []).forEach((item, idx) => {
                if (item && item.team == 'red') red++;
            });
            // If surrounded, take one for the team
            if (red >= 6) this.bomb();
            else {
                // Translate direction into position
                var kill = [1, 4, 6, 3][this.direction];
                // Random values
                var move = Math.floor(Math.random() * 8);
                var nsew = Math.floor(Math.random() * 4);
                // Lay a landmine if possible
                if (this.landMines) this.landMine(move);
                // Kill if someone is in the way
                else if (this.aroundMe && this.aroundMe[kill] && this.aroundMe[kill].team == 'red' && this.aroundMe[kill].name) this.kill();
                else {
                    // Move somewhere if already in the requested direction
                    if (nsew == this.direction) this.move(move);
                    // Otherwise just rotate to the requested direction
                    else this.rotate(nsew);
                }
            }
            resolve();
        });
    },
    onmessage: function(data, from, fromBot) {},
    onkill: function() {}
});

Przeważnie losowy, ale zostanie zbombardowany, jeśli zostanie otoczony, i sprzyja sprawdzaniu się i zabijaniu zamiast ruchu.


źródło
Mądry! Niezłe.
programator5000,
3
Słuchajcie, oto historia o małym facecie, który żyje w niebieskim świecie.
Matthew Roh
3

Zrelaksowany bombowiec

Ten bot szuka miejsca z co najmniej 1 wolną komórką po każdej stronie, a następnie sadzi minę. Obozuje na nim, dopóki nie zbliży się wróg. Kiedy ktoś się zbliży, będzie się poruszał w kopalni tam iz powrotem, by wabić w nią drugiego bota. Będzie także obracał się i zabijał w razie potrzeby. Kiedy nie zostanie mu już żadna kopalnia, będzie szukał schronienia w lewym górnym rogu, tyłem do ściany i odwet, jeśli mu grozi.

Nie ma tu żadnej specjalnej gry zespołowej, oprócz nadawania swojej pozycji zespołowi za pomocą selfsłowa kluczowego.

createBot({
    team: 'red',
    name: 'relaxed-bomber',
    ontick: function(environment) {
        return new Promise((resolve, reject) => {
            if (typeof this.storage['dropped'] == "undefined") {
                this.storage['dropped'] = false;
                this.storage['covered'] = false;
                this.storage['baited'] = false;
            }
            if (typeof environment.x != "undefined" && typeof environment.y != "undefined") {
                this.storage['pos'] = [environment.x, environment.y];
            }
            if (typeof environment.gridWidth != "undefined" && typeof environment.gridHeight != "undefined") {
                this.storage['grid'] = [environment.gridWidth, environment.gridHeight];
            }
            var x = this.storage['pos'][0];
            var y = this.storage['pos'][1];
            var x0 = this.storage['grid'][0];
            var y0 = this.storage['grid'][1];
            var source = [1, 4, 6, 3];
            var dest = [6, 3, 1, 4];
            var rot = [0, 1, 2, 3];
            var movex = [-1, 0, 1, -1, 1, -1, 0, 1];
            var movey = [-1, -1, -1, 0, 0, 1, 1, 1];
            var action = false;
            if (this.landMines > 0) { 
                var move = [false, false, false, false];
                var moveIndex = -1;
                if (x <= 0) { move[1] = true; }
                if (x >= x0 - 1) { move[3] = true; }
                if (y <= 0) { move[2] = true; }
                if (y >= y0 - 1) { move[0] = true; }    
                if (move[0] && !move[1] && !move[2] && move[3]) { moveIndex = 0; }
                if (move[0] && !move[1] && !move[2] && !move[3]) { moveIndex = 1; }
                if (move[0] && move[1] && !move[2] && !move[3]) { moveIndex = 2; }
                if (!move[0] && !move[1] && !move[2] && move[3]) { moveIndex = 3; }
                if (!move[0] && move[1] && !move[2] && !move[3]) { moveIndex = 4; }
                if (!move[0] && !move[1] && move[2] && move[3]) { moveIndex = 5; }
                if (!move[0] && !move[1] && move[2] && !move[3]) { moveIndex = 6; }
                if (!move[0] && move[1] && move[2] && !move[3]) { moveIndex = 7; }  
                if (moveIndex >= 0) {
                    this.storage['pos'] = [ x + movex[moveIndex], y + movey[moveIndex]];
                    this.move(moveIndex);
                } else {
                    this.storage['dropped'] = true;
                    this.storage['covered'] = false;
                    this.landMine(1);
                }
            } else {
                if (this.storage['dropped']) {
                    this.storage['dropped'] = false;
                    this.storage['covered'] = true;
                    this.storage['pos'] = [ x + movex[6], y + movey[6]];
                    this.move(6);
                } else if (this.storage['covered']) {
                    for (var i = 0; i < source.length; i++) {
                        if (typeof environment.aroundMe[source[i]] != "undefined" && typeof environment.aroundMe[source[i]].team != "undefined" && environment.aroundMe[source[i]].team == "blue" && typeof environment.aroundMe[source[i]].name != "undefined") {
                            this.storage['covered'] = false;
                            this.storage['baited'] = true;
                            this.storage['mine'] = this.storage['pos'].slice();
                            this.storage['reverse'] = source[dest[i]];
                            this.storage['pos'] = [ x + movex[dest[i]], y + movey[dest[i]]];
                            this.move(dest[i]);
                            action = true;
                        }
                    }
                    if (!action) {
                        this.dig();
                    }
                } else if (this.storage['baited']) {
                    for (var i = 0; i < source.length; i++) {
                        if (typeof environment.aroundMe[source[i]] != "undefined" && typeof environment.aroundMe[source[i]].team != "undefined" && environment.aroundMe[source[i]].team == "blue" && typeof environment.aroundMe[source[i]].name != "undefined") {
                            if (this.direction == rot[source[i]]) {
                                this.kill();
                                this.storage['baited'] = false;
                                action = true;
                            } else {
                                this.rotate(rot[source[i]]);
                                action = true;
                            }
                        }
                    }
                    if (!action) {
                        if (this.storage['mine'][0] == this.storage['pos'][0] && this.storage['mine'][1] == this.storage['pos'][1]) {
                            this.storage['pos'] = [ x + movex[this.storage['reverse']], y + movey[this.storage['reverse']]];
                            this.move(this.storage['reverse']);
                            this.storage['reverse'] = source[this.storage['reverse']];
                        } else {
                            this.storage['pos'] = [ x + movex[this.storage['reverse']], y + movey[this.storage['reverse']]];
                            this.move(this.storage['reverse']);
                            this.storage['reverse'] = dest[this.storage['reverse']];
                        }
                    }
                } else {
                    for (var i = 0; i < source.length; i++) {
                        if (typeof environment.aroundMe[source[i]] != "undefined" && typeof environment.aroundMe[source[i]].team != "undefined" && environment.aroundMe[source[i]].team == "blue" && typeof environment.aroundMe[source[i]].name != "undefined") {
                            if (this.direction == rot[source[i]]) {
                                this.kill();
                                this.storage['baited'] = false;
                                action = true;
                            } else {
                                this.rotate(rot[source[i]]);
                                action = true;
                            }
                        }
                    }
                    if (!action) {
                        if (x > 0 && y > 0) {
                            this.storage['pos'] = [ x + movex[0], y + movey[0]];
                            this.move(0);
                        } else if (x > 0 && y == 0) {
                            this.storage['pos'] = [ x + movex[3], y + movey[3]];
                            this.move(3);
                        } else if (x == 0 && y > 0) {
                            this.storage['pos'] = [ x + movex[1], y + movey[1]];
                            this.move(1);
                        } else {
                            this.rotate(1);
                        }
                    }
                }
            }
            this.sendMessage(undefined, "red", {'self': this.storage['pos'] });
            resolve();
        });
    },
    onmessage: function(data, fromTeam, fromBot) {},
    onkill: function() {}
});
Thrax
źródło
W której drużynie jesteś?
programator5000
@ programmer5000 Ponieważ nazwy botów muszą zaczynać się od litery zespołu, myślę, że jestem Team Red :)
Thrax
Niezły bot! Sugeruję, żebyś także przekazał zespołowi to, co cię otacza.
programator5000
1

Wykonaj kopię zapasową 1 innego niebieskiego bota (zapomniałem to zrobić wcześniej)

createBot({
    team: 'blue',
    name: 'backup1',
    ontick: function(environment) {
        return new Promise((resolve, reject) => {
            //if (typeof this.x != "undefined") this.storage['position'] = [this.x, this.y];
            if (typeof environment.x != "undefined") this.storage['position'] = [environment.x, environment.y]; //Modified according to @WasteD
            if (typeof this.storage['map'] == "undefined") { //Create empty map
                var map = [[]];
                //for(i=0;i<this.gridHeight;i++) map[i]=[];
                for(i=0;i<environment.gridHeight;i++) map[i]=[]; //Modified according to @WasteD
                this.storage['map'] = map;
            }
            var blue = []
            var red = []
            var x = this.storage['position'][0];
            var y = this.storage['position'][1];
            var dx = [-1, 0, 1, -1, 0, 1, -1, 0, 1]
            var dy = [1, 1, 1, 0, 0, 0, -1, -1, -1]
            (this.aroundMe || []).forEach((item, idx) => { // Update map and list positions of surrounding blues and reds
                if (item && item.team == 'red' && typeof item.name != "undefined") red += idx;
                if (item && item.team == 'red' && typeof item.name == "undefined") this.storage['map'][x+dx[idx]][y+dy[idx]] = 'M';
                if (item && item.team == 'blue' && typeof item.name != "undefined") blue += idx;
            });
            this.sendMessage(undefined, "blue", {"position": this.storage['position'], 'map': this.storage['map']}); //Send to buddies my position and the map
            if (red.indexOf([1, 4, 6, 3][this.direction]) > -1) this.kill() ; //If red guy is in front of
            else if (red.indexOf([1,4,6,3]) > -1) this.rotate(red.indexOf([1,4,6,3])); //If red guy is next but not in front of
            else if (blue.indexOf(3) > -1){ //If blue buddy on the left
                if (blue.indexOf(4) > -1){ //If another one is on the right
                    if (blue.indexOf(1) > -1 && this.direction != 2) this.rotate(2); //...and a third one at the top
                    else var digging = this.dig();
                    }
                else if (this.direction != 1) this.rotate(1);
                else var digging = this.dig();
            }
            else if (blue.indexOf(1) > -1){
                if (blue.indexOf(6) > -1 && this.direction != 3) this.rotate(3);
                else if (this.direction != 2) this.rotate(2);
                else var digging = this.dig();
            }
            else if (blue.indexOf(4) > -1){
                if (this.direction != 3) this.rotate(3);
                else var digging = this.dig();
            }
            else if (blue.indexOf(6) > -1 && this.direction != 0) this.rotate(0);
            else if (blue.indexOf([0,2]) > -1){ //If no blue next to me but one in diagonal, move next
                this.move(1);
                this.storage['position'][1] = y+1; //Update position
            }
            else if (blue.indexOf([5,7]) > -1){
                this.move(6);
                this.storage['position'][1] = y-1;
            }
            else if (typeof this.storage['other_blue'] != "undefined"){ //Check if buddies said where they were, try to go near the closest one
                var dmin = 99999;
                var pos = []
                (this.storage['other_blue'] || {}).forEach((item, idx) => {
                    var d = Math.sqrt(Math.pow(item['position'][0]-x,2) + Math.pow(item['position'][1]-y,2));
                    if (d < dmin){
                        dmin = d;
                        pos = item['position'];
                        }
                });
                if (pos[0]-x > 0){
                    this.move(4);
                    this.storage['position'][0] = x+1
                }
                else if (pos[0] < 0){
                    this.move(3);
                    this.storage['position'][0] = x-1
                }
                else if (pos[1] > 0){
                    this.move(1);
                    this.storage['position'][1] = y+1
                }
                else{
                    this.move(6);
                    this.storage['position'][1] = y-1
                }
            }
            else var digging = this.dig();
            if (typeof digging != "undefined"){ //Check out surroundings if dig() was played and update the map accordingly
                var dx2 = [-2,-1,0,1,2,-2,-1,0,1,2,-2,-1,0,1,2,-2,-1,0,1,2,-2,-1,0,1,2];
                var dy2 = [2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2];
                (digging || []).forEach((item, idx) => {
                    //if (item && item.team == 'red' && typeof item.name == "undefined") this.storage['map'][x+dx2[idx]][y+dy2[idx]] = 'M';
                    if (item) this.storage['map'][x+dx2[idx]][y+dy2[idx]] = 'M'; //previously misread what dig() returned
                });
            }
            resolve();
        });
    },
    onmessage: function(data, fromTeam, fromBot) {
        if (typeof data['position'] != "undefined" && fromTeam == 'blue') { //If position sent by a blue bot
            if (typeof this.storage['other_blue'] == "undefined") this.storage['other_blue'] = [];
            for (i in this.storage['other_blue']){
                var found = false;
                if ('name' in i){
                    if (i['name'] == fromBot){
                        i['position'] = data['position'];
                        found = true; //Update if position already known from previous ticks
                        }
                }
            }
            if (!found) this.storage['other_blue'] += {'position':data['position'], 'name':fromBot}; //Add position if previously unknown
            this.sendMessage(fromBot, undefined, "roger.");
        }
    },
    onkill: function() {this.sendMessage(undefined, "blue", {"position": this.storage['position'], 'map': this.storage['map']});}
});
Krzysztof
źródło
1

Niebieski wojownik

createBot({
  team: "blue",
  name: "blue-fighter",
  ontick: function(environment) {
    return new Promise((resolve, reject)=>{
      let map = environment.aroundMe;
      let sides = [1, 4, 6, 3];
      let facing = sides[this.direction];
      let isTeam = (team,a) => a && a.team === team;
      let isRed = (a)=>isTeam("red",a);
      let isBlue = (a)=>isTeam("blue",a);
      let randomSquare = ()=>Math.floor(Math.random()*8);
      let redNum = map.filter(isRed).length;
      let blueNum =  map.filter(isBlue).length;
      if(redNum > blueNum && redNum > 2){
        this.bomb();
      }else if(isRed(map[facing])){
        this.kill();
      }else if(sides.includes(map.findIndex(isRed))){
        this.rotate(sides.indexOf(map.findIndex(isRed)));
      }else if(Math.random() < 0.5 && this.landMines > 0){
        this.landMine(randomSquare());
      }else{            
        this.move(randomSquare());
      }
      resolve();
    });
  },
  onmessage: function(data, from, fromBot) {},
  onkill: function(){}
});

Niebieski wojownik porusza się i minuje losowo i obraca się w kierunku czerwonych graczy. Jeśli otaczające bloki mają więcej czerwonego niż niebieskiego, bomby. Jeśli stoi naprzeciw czerwonego gracza, zabija go.

SuperStormer
źródło