Équipe de The Hill!

27

Ce défi a été inspiré par l 'excellent défi de @HelkaHomba , Red vs Blue - Pixel Team Battlebots . Ce défi était probablement le meilleur que j'ai vu sur ce site. Déjà.

Mon défi est toujours très différent, mais @HelkaHomba mérite le crédit de l'inspiration.

Présentation

Il s'agit d'une équipe où votre équipe gagne en ayant tous les joueurs en vie dans votre équipe. En d'autres termes, la dernière équipe debout gagne. Les tirages seront refaits.

Vous êtes sur un tableau. Vous connaissez votre position au premier tour (cochez 0). Vous savez également qui se trouve dans les environs:

Un seul carré rouge dans une grille 9x9, entouré de cellules blanches.

Dans ce cas, vous êtes tout seul (ou du moins vous le pensez) sans personne autour de vous. Vous pouvez voir les éléments environnants dans le premier argument de votre ontickgestionnaire. Plus d'informations sur l'API plus tard.

Ton équipe

Votre équipe est déterminée par votre ID utilisateur. Pour le savoir, cliquez sur votre photo de profil:

Ma photo de profil

Trouvez ensuite votre ID utilisateur dans la barre d'adresse:

C'est entre / utilisateurs / et / votre nom d'utilisateur

Si c'est étrange, vous faites partie de l'équipe bleue.

Si c'est égal, vous êtes dans l'équipe rouge.

Vous êtes les bienvenus pour les cercles dessinés à la main.

Votre nom (de bot)

Le nom de votre bot commence par la première lettre de votre équipe ("r" ou "b"). Il doit correspondre à l'expression régulière /^(r|b)[A-Za-z_-]$/. En dehors de cela, vous pouvez choisir le nom de votre bot. Veuillez ne pas en utiliser un déjà existant.

Départ

Les joueurs rouges commenceront près du haut de la carte et le bleu commencera près du bas. On vous donne des informations spéciales sur la première coche (tour) dans le environmentparamètre de la ontickfonction. Je recommande de stocker cela. Voir l'API pour plus de détails.

À votre tour

L'ordre du tour est initialement aléatoire, mais reste le même.

Actions de virage

Vous ne pouvez effectuer qu'une seule action par tour.

  • Bouge toi

    Lorsque vous souhaitez déménager, vous appelez this.move(num)l'API. numest la cellule vers laquelle vous souhaitez vous déplacer:

    0 est en haut à gauche, 1 est en haut au milieu, 2 est en haut à droite, 3 est au milieu à droite, 4 est au milieu à gauche, 5 est en bas à gauche, 6 est en bas au milieu et 7 est en bas à droite.

    Les emplacements relatifs des nombres vers lesquels vous pouvez vous déplacer sont stockés dans la constante globale threeByThree:

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

Si vous vous déplacez dans un mur ou un autre joueur, rien ne se passe.

  • Tourner

    Pour faire pivoter, vous appelez this.rotate(num). Num est la direction que vous souhaitez faire pivoter:

    0 est en haut, 1 est à droite, 2 est en bas et 3 est à gauche

    La rotation est absolue.

  • Tuer

    Si un autre joueur (d'une autre équipe) se trouve dans la cellule à laquelle vous faites face, vous pouvez l'appeler this.kill()et le tuer. S'il n'y a personne là-bas, ou qu'ils sont dans votre équipe, cela ne fait rien. Exemple:

    Mêmes nombres que ci-dessus, la cellule 0 est verte, la 1 est bleue, la 2 est orange et la 3 est jaune

    Si vous êtes tourné vers 0, vous pouvez tuer le vert. Si vous êtes tourné vers 1, vous pouvez tuer le bleu. Si vous êtes tourné vers 2, vous pouvez tuer l'orange. Si vous êtes tourné vers 3, vous pouvez tuer le jaune.

  • Bombe

    Le bombardement tue tous les joueurs, y compris vous et vos coéquipiers, dans les 9 cases autour de vous. Exemple:

    Il y a une grille 9x9 avec des "x" dans chaque cellule.

    Pourquoi voudriez-vous jamais faire ça? Kamikaze . S'il y a plus de joueurs qui ne font pas partie de votre équipe dans les 9 cellules autour de vous, alors qu'il y en a dans votre équipe, vous pourriez envisager de bombarder. (Je vous suggère de prévenir d'abord vos camarades!)

  • Placer une mine terrestre

    Cela crée un carré de mort pour les autres personnes qui ne font pas partie de votre équipe. Lorsque vous placez une mine terrestre, vous vous déplacez également pour ne pas marcher dessus. Vous appelez this.landMine(num)où num est le carré où vous voulez aller. Exemple:

    Un seul carré rouge dans une grille 9x9, entouré de cellules blanches.

    Ensuite, vous appelez this.landMine(4):

    [Une grille 9x9, avec un "M" rouge au milieu et une cellule rouge au milieu à droite.

    Tu vois ce "M"? C'est une mine terrestre. D'autres peuvent le voir ... pour l'instant. Tout le monde, même ceux qui ne font pas partie de votre équipe, peut voir une mine terrestre sur la coche où elle est placée. Mais une fois cette tique terminée, personne, même vous ne pouvez la voir. Mais elle explosera dès qu'un ennemi la traversera. Exemple:

    Deux grilles 9x9, une cellule bleue au milieu à gauche dans la première, un "M" rouge au milieu de la première, un "x" rouge au milieu de la seconde et une flèche entre elles.

    Blue s'est déplacé sur votre mine et BOOM! Vous venez de recevoir un autre kill.

    Pour chaque 2 tués (tués directement ou mines terrestres), vous obtenez 1 mine supplémentaire à placer. Vous en obtenez également un au début.

  • Creuser

    Lorsque vous creusez, vous recherchez des mines terrestres dans une zone 5x5 centrée autour de vous. Cela ne montre pas l'équipe du bot qui a placé la mine. (N'oubliez pas que vous ne pouvez pas être tué par une mine posée par un membre de votre équipe.) Par exemple, si c'était la grille autour de vous:

    La valeur de retour de this.dig()serait alors:

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

Les index des tableaux commencent en haut à gauche, en allant vers la droite, puis vers le bas, sans vous inclure:

Il y en a 23 au total, et leurs emplacements relatifs sont stockés dans la constante globale 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]
]

Notez que creuser révèle des mines placées sur les tiques précédentes, contrairement aroundMe.

la communication

Lorsque vous voulez parler à quelqu'un, vous appelez this.sendMessage(recipients, team, data). Les données peuvent être ce que vous voulez et vous pouvez les envoyer à qui vous voulez, même aux joueurs des autres équipes. Cela peut être utilisé pour tromper les bots mal programmés, mais tous les joueurs peuvent voir qui a envoyé un message et à quelle équipe ils appartiennent.

Exemple:

Envoyez quelque chose à un bot nommé "redisbest":

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

Envoyez quelque chose à un bot nommé "redisbest" et "blueiscool":

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

Envoyez quelque chose à toute l'équipe rouge

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

Envoyez quelque chose à tout le monde

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

Envoyez quelque chose à toute l'équipe rouge et un bot nommé "blueiscool":

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

API

Votre code doit consister en un seul appel à la createBotfonction. Rien d'autre. Exemple de code:

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

(Vous êtes libre de copier-coller ceci. Modifiez-le simplement pour votre équipe, etc.)

Les méthodes

  • ontick(environment)

    Appelé quand c'est ton tour. Doit renvoyer un Promisequi se résout en 1 seconde ou moins sinon il sera ignoré. Ceci est pour des raisons de performances et a le bel effet secondaire de ne pas faire bloquer la tabulation.

    this (quand en ontick)

    • landMines Combien de mines terrestres il vous reste. Plus vous en tuez, plus vous obtenez de mines terrestres. Pour chaque 2 robots tués, vous obtenez 1 mine supplémentaire. Vous obtenez également 1 pour commencer.
    • direction La direction à laquelle vous faites face.
    • storage Stockage qui persiste entre les appels vers onTicket onMessage. Un objet vide au début. Modifiez pour n'importe quel but, mais assurez-vous qu'il s'agit toujours d'un tableau ou d'un objet pour vous assurer qu'il persiste correctement.
    • move(num) Déplacer vers la position spécifiée. Ne fait rien si invalide. Voir ci-dessus pour plus de détails.
    • rotate(num) Tournez à la position spécifiée. Ne fait rien si invalide. Voir ci-dessus pour plus de détails.
    • kill() Tue le joueur auquel vous êtes confronté, s'il existe et ne fait pas partie de votre équipe. Voir ci-dessus pour plus de détails.
    • bomb() Tue quiconque dans les 9 cases autour de vous, y compris vous-même.
    • landMine(num) Place une mine terrestre où vous vous trouvez, puis se déplace vers la position spécifiée. Ne fait rien si invalide numou si vous n'en avez plus. Voir ci-dessus pour plus de détails.
    • dig() Nouveau! Renvoie un tableau d'informations sur les mines terrestres dans une zone 5x5 centrée autour de vous. Voir ci-dessus pour plus de détails.
    • sendMessage(recipients, team, data) recipientspeut être soit un seul bot (chaîne), un tableau de bot, ou undefined/ null. C'est à qui vous souhaitez envoyer le message. teamest une chaîne de l'équipe à laquelle vous souhaitez envoyer le message. Utilisez "*"pour envoyer un message à tout le monde. dataest tout ce qui peut être passé à une fonction JS. Il est envoyé aux destinataires. S'il s'agit d'un objet ou d'un tableau, il est transmis par référence , vous et le ou les destinataires pouvez donc l'enregistrer dans leurstorage et toute modification de l'objet affecte les deux copies du bot. Notez que les bénéficiaires qui sont soit la liste des bots, le bot exact spécifié dans la chaîne, ou un bot sur l'équipe que vous avez indiqué, il recevra le message.

environment

Au premier tick

  • x: Position x de votre joueur
  • y: Position y de votre joueur
  • gridWidth: La largeur de la grille (en cellules)
  • gridHeight: La hauteur de la grille (en cellules)

    Sur toutes les tiques

  • aroundMe: Un éventail de joueurs et de mines terrestres. Les joueurs sont des objets qui ressemblent {name: "bot name", team: "bot team"}, et les mines terrestres le sont {team: "team of bot who placed mine"}. Les index du tableau:

    0 est en haut à gauche, 1 est en haut au milieu, 2 est en haut à droite, 3 est au milieu à droite, 4 est au milieu à gauche, 5 est en bas à gauche, 6 est en bas au milieu et 7 est en bas à droite.

    Notez que les mines terrestres placées sur une tique autre que la actuelle ne seront pas affichées.

    aroundMe Exemple:

    Disons que c'est la grille (vous êtes rouge):

    Une grille 9x9, avec du bleu clair en haut à gauche, un "M" gris en haut à droite, du rouge au milieu, du jaune au milieu à gauche et un "M" rouge en bas à gauche.

    Votre aroundMeressemblera à ceci:

[
    {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.
]

Les index du tableau sont expliqués ici:

0 est en haut à gauche, 1 est en haut au milieu, 2 est en haut à droite, 3 est au milieu à droite, 4 est au milieu à gauche, 5 est en bas à gauche, 6 est en bas au milieu et 7 est en bas à droite.

Votre bot voit effectivement ceci:

Une boîte bleu clair en haut à gauche avec un numéro noir 0, une boîte jaune sur le bord gauche avec un numéro noir 4 et un "M" rouge en bas à gauche avec un 5 noir.

  • onmessage(data, fromBot, fromTeam)

    this (en cas de message)

    • sendMessage(recipients, team, data) Fonction d'envoi de messages standard.
    • storage Stockage standard.

    dataLes données envoyées par l'expéditeur. fromPlayerLe joueur à partir duquel le message a été envoyé. fromTeamL'équipe à partir de laquelle le message a été envoyé.

  • onkill()

    this (quand onkill)

    • sendMessage(recipients, team, data) Fonction d'envoi de messages standard.

Tableaux globaux pratiques (constants):

threeByThree:

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

Utile pour transmettre des données à la fonction de déplacement ainsi que pour interpréter aroundMe. Voir au dessus.

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

Utile pour la this.dig()fonction du ontickgestionnaire.

Essaye le!

Le contrôleur sera exécuté à partir de ma machine sur localhost pour des raisons de performances, mais vous pouvez utiliser le CodePen pour tester votre bot.

Notez que vous devez coller votre code dans la console et appuyer sur Enteravant de cliquer sur exécuter. Vous pouvez coller autant de bots que vous le souhaitez. Les "bots de test" sont des exemples pour lesquels vous pouvez tester. Si vous pouvez les battre ou les attacher tous, vous avez au moins un bot décent.

Soumissions

Règles

Règles (appliquées par le contrôleur)

  • Votre ontickcode principal ne doit pas prendre plus d'une seconde. Nous ne voulons pas que les rondes durent éternellement. Si votre code prend> 1 seconde, il sera arrêté.
  • Si vous essayez de faire plus d'une action par tour, ou effectuez une action invalide (par ex. this.move(-1) Ou en vous déplaçant dans un mur), elle sera ignorée.
  • Plus peut arriver bientôt ...

Règles (appliquées par moi, peuvent entraîner un DQ)

  • Ne pas écrire les variables globales ( lecture est très bien ).
  • Votre code doit fonctionner dans Nodejs (au cas où le contrôleur est porté sur Nodejs), donc JSON.parse(...)c'est bien, mais ce alert()n'est pas le cas.
  • Vous n'êtes pas autorisé à appeler createBotou à interférer avec le contrôleur de quelque manière que ce soit .
  • N'utilisez pas le code de quelqu'un d'autre sans autorisation et sans modifications importantes. Pas de copybots.
  • S'il vous plaît, pas d'échappatoires!
  • Plus peut arriver bientôt ...

Mes robots

Voici quelques bots:

Ce bot choisit au hasard une action. Eh bien, c'est un hasard pondéré, mais toujours assez aléatoire. Si vous pouvez tuer ce bot (il finira par se tuer, cela ne compte pas), alors vous avez au moins un bot décent. Affichez-le et voyez ce qui se passe!

Mes bots ont un nom commençant par "x" et une équipe de "aucun". Vous êtes invités à utiliser une partie de ce code, mais veuillez effectuer au moins quelques modifications. Si vous ne pouvez pas être dérangé au moins pour ajuster un nombre, vous ne gagnerez pas.

Formatage de votre soumission

Veuillez utiliser ce format:

# 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...

Demandes de fonctionnalités, bugs, questions, etc.?

Commentaires ci-dessous! Veuillez vérifier s'il y a déjà un commentaire à ce sujet. S'il y en a déjà un, votez-le.

Vous voulez parler à votre équipe?

Utilisez les salles de chat pour le rouge et le bleu .

La langue

Actuellement, seuls JS et quelque chose qui se compile en JS sont pris en charge, mais si vous connaissez un moyen de faire fonctionner d'autres langues avec Nodejs, je serais heureux de porter le contrôleur sur Nodejs.

Notes finales

Idées de stratégie

Aidez votre équipe! Créer un bot conçu pour aider un autre bot et travailler ensemble. Cette stratégie a bien fonctionné pour Red vs. Blue - Pixel Team Battlebots

Demandeurs de représentants

J'accepterai la réponse votée la plus élevée de l'équipe gagnante. Gardez à l'esprit que les réponses antérieures ont tendance à obtenir plus de votes, mais leurs faiblesses sont plus susceptibles d'être trouvées et exploitées.

De plus, si vous répondez rapidement, vous pourriez obtenir la prime de +100.

programmer5000
la source
1
Les commentaires ne sont pas pour une discussion approfondie; cette conversation a été déplacée vers le chat .
Dennis
Puis-je créer plusieurs robots? (désolé, je sais que la conversation a été déplacée, je suis simplement interdit par chat alors oui)
Matthew Roh
@SIGSEGV oui, mais quelqu'un d'autre doit l'afficher. Vous pouvez publier un bot et donner le code d'un autre à un membre de votre équipe, mais vous ne pouvez pas poster deux fois.
programmer5000
Concernant le positionnement, où se trouve la cellule indexée [0, 0], est-ce la cellule en haut à gauche? De plus, la messagerie consomme-t-elle votre action (par tour)? Merci.
Thrax
@Thrax oui et non. Vous pouvez même envoyer un message en réponse à un message.
programmer5000

Réponses:

7

xscared (non concurrent)

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

Très peur des gens. S'éloigne de la première personne (ou mine) qu'il voit. Sinon, il se déplace de façon aléatoire. Notez que ce n'est pas en compétition, juste un exemple. Essayez de le battre!

programmer5000
la source
6

sauvegarde, un bot bleu

Comme prévenu dans le chat, je n'ai jamais rien écrit en javascript dans ma vie, donc si vous trouvez une erreur, dites-le moi! (Merci à @ programmer5000 de m'avoir déjà aidé)
Le concept de ce bot est qu'il communique avec d'autres bots de la même équipe et leur envoie sa position avec une carte des mines qu'il a trouvées. Il essaie de rejoindre le bot bleu le plus proche (si on envoie ses données de position [données sous forme de tableau [x, y]]), et reste près de lui (le dos tourné autant que possible), tuant les bots rouges approchant ou regardant à venir pour les mines.

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
la source
Hé vous vous souciez si j'entre aussi ceci mais (avec un nom différent) je suis aussi en bleu
Christopher
@Christopher Non, ça ne me dérange pas, mais ce serait un peu plus intéressant pour vous et pour l'équipe si vous en faites un au moins un peu différent (au moins pour compléter les 2 bots qui existent déjà).
plannapus
Fera cela. Je vais le changer
Christopher
Si j'essaie d'exécuter votre bot dans codepen, cela ne fonctionne pas parce que vous utilisez this.xet ainsi de suite, mais c'est environment.xfaux ou je me trompe?
WasteD
@WasteD comme je l'ai dit, je ne connais pas du tout Javascript, c'est donc possible. Mais si c'est le cas, je suppose que ça devrait aussi être environment.gridHeightet environment.aroundMe? Dans ce cas, les autres robots ne devraient pas fonctionner non plus car ils utilisent this.aroundMe.
plannapus
5

Bleu, bleu, mon monde est bleu

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

Généralement aléatoire, mais bombardera s'il est entouré, et favorise le contrôle et la mort plutôt que le déplacement.


la source
Intelligent! Joli.
programmer5000
3
Écoutez, voici une histoire, sur un petit gars qui vit dans un monde bleu.
Matthew Roh
3

Bombardier décontracté

Ce bot recherche un endroit avec au moins 1 cellule libre de chaque côté puis plante une mine. Il campe dessus jusqu'à ce qu'un ennemi s'approche. Quand quelqu'un s'approche, il va faire des allers-retours sur sa mine pour appâter l'autre bot dessus. Il fera également pivoter et tuer si nécessaire. Lorsqu'il ne lui reste plus de mine, il se réfugiera dans le coin supérieur gauche, dos au mur et ripostera s'il est menacé.

Pas de jeu d'équipe spécial ici, à part diffuser sa position à son équipe avec un selfmot-clé.

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
la source
Dans quelle équipe êtes-vous?
programmer5000
@ programmer5000 Puisque les noms des bots doivent commencer par la lettre de l'équipe, je suppose que je suis Team Red :)
Thrax
Joli bot! Je vous suggère également de diffuser ce qui vous entoure à votre équipe.
programmer5000
1

Sauvegardez 1 autre bot bleu (oublié de le faire plus tôt)

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']});}
});
Christophe
la source
1

Blue Fighter

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

Le combattant bleu se déplace et mine les mines au hasard et tourne vers les joueurs rouges. Si les blocs environnants ont plus de rouge que de bleu, il bombarde. S'il fait face à un joueur rouge, il le tue.

SuperStormer
la source