Erobere die Flagge


12

Dies ist ein Spiel, in dem die Flagge gefangen genommen wird, das stark inspiriert ist und auf Rot-Blau-Pixel-Team-Battlebots basiert . Das war eine großartige Frage (vielen Dank an Calvin'sHobbies; ich hoffe, es macht Ihnen nichts aus, dass ich Ihnen schamlos eine Menge Code gestohlen habe) - hier ist ein weiteres Team, das auf King-of-the-Hill basiert. Hoffentlich erfordert die Eroberung der Flagge mehr Teamzusammenarbeit sowie mehr Strategie.

Um es zu verwechseln, werden Sie im roten Team berücksichtigt, wenn die letzte Ziffer Ihrer ID zwischen 0und 4einschließlich liegt. Dies sollte verhindern, dass genau dieselben Teams erneut gegeneinander antreten, wenn dieselben Personen antworten. Der Vorstand ist 350pxvon 350px. Das blaue Team startet in der oberen Hälfte des Bretts und das rote Team startet in der unteren Hälfte.

Die Art und Weise, wie Sie spielen, um die Flagge zu erobern, ist folgende: Ziel des Spiels ist es, die Flagge des gegnerischen Teams zu nehmen und sie auf Ihre eigene Seite zurückzubringen. Wenn Sie auf ihrer Seite sind, können Sie markiert und ins Gefängnis geschickt werden. Wenn Sie im Gefängnis sind, können Sie sich nicht bewegen. Wenn Sie auf Ihrer Seite sind, besteht Ihre Aufgabe darin, gegnerische Teammitglieder zu markieren, um sie ins Gefängnis zu schicken. Die einzige Möglichkeit, aus dem Gefängnis auszusteigen, besteht für jemanden in Ihrem Team, dem es freisteht, alle im Gefängnis zu markieren. (Beachten Sie, dass sich das Gefängnis auf der Seite des gegnerischen Teams befindet.)

Speziell:

  • Es gibt eine Konstante - FIELD_PADDING-, die auf 20 gesetzt ist. Dies ist die Auffüllung für das Feld. Wenn es Null wäre, wären die Flaggen und das Gefängnis genau in den Ecken der Leinwand. Da dies nicht der Fall ist, sind die Flagge und das Gefängnis 20 Pixel von den Ecken entfernt.
  • Die blaue Flagge (denken Sie daran: Das blaue Team befindet sich in der oberen Hälfte) befindet sich z. (WIDTH - FIELD_PADDING, FIELD_PADDING) = (330, 20)B. in der rechten oberen Ecke.
  • Die rote Fahne ist bei (FIELD_PADDING, HEIGHT - FIELD_PADDING) = (20, 330)
  • Das blaue Gefängnis (in dem rote Mitglieder untergebracht sind) befindet sich (20, 20)oben links auf der blauen Seite.
  • Das rote Gefängnis, in dem blaue Mitglieder untergebracht sind, befindet sich in (330, 330)

Jedes Teammitglied startet zufällig an einer Position 45 < x < 305und 45 < y < 175für Blau und 175 < y < 305für Rot. Kein Teammitglied kann innerhalb der DEFENSE_RADIUS = 25Pixel seiner eigenen Flagge oder seines eigenen Gefängnisses gehen (es sei denn, Ihre eigene Flagge wurde von einem gegnerischen Bot erbeutet. In diesem Fall müssen Sie diesen Bot markieren). Dies soll verhindern, dass Welpen wie Bots bewacht werden. Wenn Sie in diesen Bereich gehen, werden Sie "zurückgedrängt". Ebenso kann kein Teammitglied die Grenzen überschreiten (weniger als null oder mehr als 350) - wenn Sie dies tun, werden Sie an den nächstgelegenen legalen Ort zurückgeschoben, an dem Sie sein können.

Jedes Mal, wenn Sie sich bewegen, verbrauchen Sie strength. Ihr strengthfängt um an 20und wird von 2jeder Runde aufgefüllt . Die Stärke, die Sie verwenden, entspricht der zurückgelegten Strecke. Wenn Ihre Stärke durch das Bewegen zu einem bestimmten Ort negativ wird, können Sie diesen Zug nicht ausführen. Es ist wahrscheinlich eine gute Idee, einfach mit 2normaler Geschwindigkeit zu jagen. Sie sollten höhere Geschwindigkeiten nur verwenden, wenn Sie kurz vor dem Sieg stehen und die zusätzliche Geschwindigkeit benötigen (meiner Meinung nach).

Spec :

Die Spezifikation ist der Pixel Team Battlebots-Frage ziemlich ähnlich. Sie sollten einen Codeblock (denken Sie daran, keine globalen Variablen) in Javascript schreiben. Es sollte ein Objekt mit einem x-Wert und einem y-Wert zurückgeben, die Ihre Änderung von x- und y-Werten darstellen. Die folgende Antwort:

return {
  x: 0,
  y: -2
};

bewegt sich immer nach oben, bis es gegen eine Wand stößt. Sie dürfen 8 Stunden nach dem Posten keine Änderungen vornehmen (mit Ausnahme von LegionMammal98, die dachten, dass der Controller seinen Code nicht geladen und nicht getestet hat) . Sie haben Zugriff auf die folgenden Variablen in Ihrem Code:

  • this - Sie selbst als Spieler (siehe unten, was Spieler sind)
  • move - die runde Zahl, beginnend mit 0
  • tJailed - Eine Reihe von Spielern in Ihrem Team, die inhaftiert sind
  • eJailed - Eine Reihe aller Spieler der gegnerischen Mannschaft, die inhaftiert sind
  • team - Eine Reihe von Spielern in Ihrem Team, nicht nur die in Ihrer Nähe
  • enemies - Eine Reihe aller Spieler der anderen Mannschaft, NICHT nur der in Ihrer Nähe
  • tFlag - deine Flagge (du versuchst sie zu schützen)
  • eFlag - die andere Flagge (du versuchst sie zu stehlen)
  • messages - unten erklärt
  • Eine Liste von Konstanten: WIDTH = 350, HEIGHT = 350, FIELD_PADDING = 20, DEFENSE_RADIUS = 25.

Jeder "Spieler" ist ein Objekt mit folgenden Eigenschaften:

  • x und y
  • strength
  • id
  • isJailed - wahr, wenn der Spieler im Gefängnis ist

Jede Flagge hat folgende Eigenschaften:

  • x und y
  • pickedUpBy - der Spieler, der aktuell die Flagge hat, oder null, wenn kein Spieler die Flagge hat.

Nun messagesist ein Objekt, das unter Ihren Teamkollegen geteilt wird. Es ist mir egal, was du damit machst. Das gleiche Objekt wird gemeinsam genutzt und an alle Teammitglieder weitergegeben. Nur so können Sie kommunizieren. Sie können Eigenschaften anhängen, Objekte freigeben usw. Es kann so groß sein, wie Sie möchten - ohne Größenbeschränkung.

In jeder Runde passiert folgendes:

  • Die Liste der Spieler (rot und blau) wird nach dem Zufallsprinzip in die richtige Reihenfolge gebracht.
  • Jeder Spieler macht einen Zug.
  • Wenn ein rotes Teammitglied ein blaues Teammitglied auf der roten Seite berührt (innerhalb von 10 Pixeln), schicke es ins Gefängnis und umgekehrt. Ein eingesperrter Spieler lässt seine Flagge fallen und die Stärke sinkt auf Null. Beachten Sie, dass die Schrittfunktion (der von Ihnen bereitgestellte Code) weiterhin aufgerufen wird. Sie können also Nachrichten abrufen / setzen, sich jedoch nicht im Gefängnis bewegen.
  • Wenn ein Spieler die andere Flagge berührt (innerhalb von 10 Pixeln), wird die andere Flagge von diesem Spieler als "aufgenommen" markiert. Wenn sich der Spieler bewegt, bewegt sich die Flagge - bis der Spieler markiert ist und ins Gefängnis geht, das heißt.
  • Wenn ein Spieler das Gefängnis der anderen Seite berührt, befreie alle in diesem Gefängnis. Wenn ein Spieler aus dem Gefängnis entlassen wird, wird er an einen zufälligen Ort auf seiner Seite teleportiert.

Hinweise:

  • Zumindest beim regulären Erobern der Flagge funktionieren Angriffe viel besser, wenn viele Spieler gleichzeitig angreifen, da sie die Verteidiger eher verwirren, welchen Spielern sie nachjagen sollten.
  • In ähnlicher Weise möchten Verteidiger möglicherweise koordinieren, wem sie nachjagen, damit Angriffe nicht durchgehen

Stack-Snippet:

window.onload=function(){(function(){function p(a,b,c,e){return Math.sqrt((a-c)*(a-c)+(b-e)*(b-e))}function l(a,b){this.x=this.y=0;this.id=a.id;this.title=a.title+" ["+this.id+"]";this.link=a.link||"javascript:;";this.team=b;this.isJailed=!1;this.flag=null;this.moveFn=new Function("move","tJailed","eJailed","team","enemies","tFlag","eFlag","messages","WIDTH","HEIGHT","FIELD_PADDING","DEFENSE_RADIUS",a.code);this.init()}function x(a,b){return Math.floor(Math.random()*(b-a))+a}function q(a,b){this.startX=this.x=a;this.startY=
this.y=b;this.following=null}function t(a,b){return a===e&&b||a===h&&!b?{x:20,y:20}:{x:g.width-20,y:g.height-20}}function y(){var a,b=$("#redTeam"),c=$("#blueTeam");for(a=0;a<e.length;++a)e[a].addToDiv(b);for(a=0;a<h.length;++a)h[a].addToDiv(c)}function z(){d.clearRect(0,0,g.width,g.height);d.beginPath();d.moveTo(0,g.height/2);d.lineTo(g.width,g.height/2);d.stroke();var a=e.concat(h),b,c;for(b=a.length-1;0<b;b--){c=Math.floor(Math.random()*(b+1));var f=a[b];a[b]=a[c];a[c]=f}for(b=0;b<a.length;++b)a[b].step(u);
for(b=0;b<e.length;++b)for(c=0;c<h.length;++c)10>p(e[b].x,e[b].y,h[c].x,h[c].y)&&(e[b].y<g.height/2&&e[b].goToJail(),h[c].y>g.height/2&&h[c].goToJail());for(b=0;b<a.length;++b)c=a[b].team===e!==!0?m:n,!c.following&&10>p(a[b].x,a[b].y,c.x,c.y)&&(c.following=a[b]);for(b=0;b<a.length;++b)if(c=t(a[b].team,!0),!a[b].isJailed&&10>p(a[b].x,a[b].y,c.x,c.y))for(c=a[b].team,f=0;f<c.length;++f)c[f].isJailed&&(c[f].isJailed=!1,c[f].init());m.follow();n.follow();b=m.y<g.height/2;c=n.y>g.height/2;b&&c&&alert("EXACT TIE!!!! This is very unlikely to happen.");
b&&!c&&(alert("Blue wins!"),$("#playpause").click().hide());c&&!b&&(alert("Red wins!"),$("#playpause").click().hide());for(b=0;b<a.length;++b)a[b].draw(d);m.draw("red");n.draw("blue");u++}$.ajaxSetup({cache:!1});var e=[],h=[],g=$("canvas")[0],d=g.getContext("2d"),v,u=0,m={},n={},r=!0,A={},B={},w;l.prototype.init=function(){this.x=x(45,g.width-45);this.y=x(45,g.height/2);this.team===e&&(this.y+=g.height/2);this.strength=20};l.prototype.makeShallowCopy=function(){return{x:this.x,y:this.y,strength:this.strength,
id:this.id,isJailed:this.isJailed}};l.prototype.goToJail=function(){this.isJailed=!0;var a=this.team===e!==!0?m:n;(this.team===e!==!0?m:n).following===this&&(a.following=null);a=t(this.team,!0);this.x=a.x;this.y=a.y;this.strength=0};l.prototype.step=function(a){function b(a,b,c){var e,d,f;for(e=0;e<a.length;++e)d=a[e],d!==C&&(f=d.makeShallowCopy(),d.isJailed?b.push(f):c.push(f))}var c=[],f=[],d=[],k=[],l=this.team===e?h:e,C=this,q=this.team===e?m:n,r=this.team===e?n:m;b(this.team,c,d);b(l,f,k);f=
this.moveFn.call(this.makeShallowCopy(),a,c,f,d,k,q.copy(),r.copy(),this.team===e?A:B,g.width,g.height,20,25);"object"===typeof f&&"number"===typeof f.x&&"number"===typeof f.y&&(d=p(0,0,f.x,f.y),a=t(this.team,!1),c=this.team===e!==!1?m:n,d<=this.strength&&(this.strength-=d,this.x+=f.x,this.y+=f.y,0>this.x&&(this.x=0),0>this.y&&(this.y=0),this.x>g.width&&(this.x=g.width),this.y>g.height&&(this.y=g.height),f=p(this.x,this.y,c.x,c.y),d=p(this.x,this.y,a.x,a.y),25>f&&null===c.following&&(this.x=25*(this.x-
c.x)/f*1.3+c.x,this.y=25*(this.y-c.y)/f*1.3+c.y),25>d&&(this.x=25*(this.x-a.x)/d*1.3+a.x,this.y=25*(this.y-a.y)/d*1.3+a.y)),this.isJailed||(this.strength+=2),20<this.strength&&(this.strength=20))};l.prototype.addToDiv=function(a){var b=$("<option>").text(this.title).val(this.id);a.find(".playersContainer").append(b)};l.prototype.draw=function(a){a.fillStyle=this.team===e?"red":"blue";a.beginPath();a.arc(this.x,this.y,5,0,2*Math.PI,!0);a.fill();!this.isJailed&&$("#labels").is(":checked")&&a.fillText(this.title,
this.x+5,this.y+10)};q.prototype.draw=function(a){d.strokeStyle=a;d.beginPath();d.arc(this.x,this.y,5,0,2*Math.PI,!0);d.stroke();d.fillStyle=a;d.strokeRect(this.x-2,this.y-2,4,2);d.beginPath();d.moveTo(this.x-2,this.y);d.lineTo(this.x-2,this.y+3);d.stroke()};q.prototype.copy=function(){return{x:this.x,y:this.y,pickedUpBy:this.following&&this.following.makeShallowCopy()}};q.prototype.follow=function(){null!==this.following&&(this.x=this.following.x,this.y=this.following.y)};$("#newgame").click(function(){function a(a,
b){w?b(w):$.get("https://api.stackexchange.com/2.2/questions/"+(49028).toString()+"/answers",{page:a.toString(),pagesize:100,order:"asc",sort:"creation",site:"codegolf",filter:"!JDuPcYJfXobC6I9Y-*EgYWAe3jP_HxmEee"},b,"json")}function b(g){w=g;g.items.forEach(function(a){function b(a){return $("<textarea>").html(a).text()}var d=4>=a.owner.user_id%10?e:h;a.owner.display_name=b(a.owner.display_name);if(!(a.hasOwnProperty("last_edit_date")&&28800<a.last_edit_date-a.creation_date&&33208!==a.owner.user_id||
-1<p.indexOf(a.owner.user_id))){p.push(a.owner.user_id);var g=c.exec(a.body);if(!(null===g||1>=g.length)){var f={};f.id=a.owner.user_id;f.title=a.owner.display_name;f.code=b(g[1]);f.link=a.link;d.push(new l(f,d))}}});g.has_more?a(++d,b):(console.log("Red team",e),console.log("Blue team",h),y(),clearInterval(v),r=!0,$("#playpause").show().click())}var c=/<pre><code>((?:\n|.)*?)\n<\/code><\/pre>/,d=1,p=[];e=[];h=[];u=0;m=new q(20,g.height-20);n=new q(g.width-20,20);$(".teamColumn select").empty();var k=
$("#testbotCode").val();0<k.length&&(console.log("Using test entry"),k={title:"TEST ENTRY",link:"javascript:;",code:k},$("#testbotIsRed").is(":checked")&&(k.id=-1,e.push(new l(k,e)),k.id=-3,e.push(new l(k,e))),$("#testbotIsBlue").is(":checked")&&(k.id=-2,h.push(new l(k,h)),k.id=-4,h.push(new l(k,h))));a(1,b)});$("#playpause").hide().click(function(){r?(v=setInterval(z,25),$(this).text("Pause")):(clearInterval(v),$(this).text("Play"));r=!r})})();}
#main{padding:10px;text-align:center}#testbot{padding:10px;clear:both}.teamColumn{width:25%;padding:0 10px;border:3px solid;border-color:#000;text-align:center;height:500px;overflow:scroll;white-space:nowrap}.playersContainer p{padding:0;margin:0}#redTeam{float:left;border-color:red;color:red;background-color:#fee}#blueTeam{float:right;border-color:#00f;color:#00f;background-color:#fee}#arena{display:inline-block;width:40%;text-align:center}canvas{border:1px solid #000}select{width:100%}
<script src=https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js></script><div id=main><div class=teamColumn id=redTeam><h1>Red Team</h1><select size=20 class=playersContainer></select></div><div id=arena><h1>Battlefield</h1><canvas width=350 height=350></canvas></div><div class=teamColumn id=blueTeam><h1>Blue Team</h1><select size=20 class=playersContainer></select></div><div id=loadingInfo><button id=newgame>New Game</button> <button id=playpause>Play</button><br><input type=checkbox id="labels"> Show labels</div></div><div id=testbot><textarea id=testbotCode placeholder="testbot code"></textarea><br><input type=checkbox id="testbotIsRed">Red Team<br><input type=checkbox id="testbotIsBlue">Blue Team<br></div>

Controller: http://jsfiddle.net/prankol57/4L7fdmkk/

Vollbild-Controller: http://jsfiddle.net/prankol57/4L7fdmkk/embedded/result/

Lassen Sie mich wissen, ob der Controller Fehler enthält.

Hinweis: Wenn Sie zum Controller gehen und glauben, dass er nichts lädt, drücken Sie "Neues Spiel". Es wird erst geladen, nachdem Sie auf "Neues Spiel" geklickt haben, damit alle Bots und möglichen Testbots gleichzeitig geladen werden können.

Viel Glück.


Wenn jemand ein Beispielspiel sehen möchte, habe ich einen Beispiel-Bot erstellt, den Sie kopieren und in das Textfeld "Testbot" einfügen können.

var r2 = Math.sqrt(2);
if (this.id === -1) {
  // red team 1
  // go after flag regardless of what is going on
  if (eFlag.pickedUpBy !== null && eFlag.pickedUpBy.id === this.id) {
    return {
      x: 0,
      y: 2
    };
  }
  return {
    x: this.x < eFlag.x ? r2 : -r2,
    y: this.y < eFlag.y ? r2 : -r2
  };
}
if (this.id === -2) {
  // blue team 1
  // a) go after opposing team members on your side b) get the other flag if no enemies on your side
  var closestEnemy = null;
  for (var i = 0; i < enemies.length; ++i) {
    if (enemies[i].y < HEIGHT/2 && (closestEnemy === null || enemies[i].y < closestEnemy.y)) {
      closestEnemy = enemies[i];
    }
  }
  if (closestEnemy !== null) {
    return {
      x: this.x < closestEnemy.x ? r2 : -r2,
      y: this.y < closestEnemy.y ? r2 : -r2
    };
  }
  if (eFlag.pickedUpBy !== null && eFlag.pickedUpBy.id === this.id) {
    return {
      x: 0,
      y: -2
    };
  }
  return {
    x: this.x < eFlag.x ? r2 : -r2,
    y: this.y < eFlag.y ? r2 : -r2
  };
}
if (this.id === -3) {
  // red team 2
  // a) defend the flag b) if at least half of enemies in jail and no enemies on this side, free jailed reds and quickly return
  var closestEnemy = null;
  for (var i = 0; i < enemies.length; ++i) {
    if (enemies[i].y > HEIGHT/2 && (closestEnemy === null || enemies[i].y > closestEnemy.y)) {
      closestEnemy = enemies[i];
    }
  }
  if (closestEnemy !== null) {
    return {
      x: this.x < closestEnemy.x ? r2 : -r2,
      y: this.y < closestEnemy.y ? r2 : -r2
    };
  }
  if (enemies.length / eJailed.length <= 1 && tJailed.length > 0) {
    return {
      x: this.x < FIELD_PADDING ? r2 : -r2,
      y: this.y < FIELD_PADDING ? r2 : -r2
    };
  }
  if (this.y < 350/2) return {x: 0, y: 2};
  return {
    x: this.x < tFlag.x ? r2 : -r2, 
    y: this.y < tFlag.y ? r2 : -r2
  };
}
if (this.id === -4) {
  // blue team 2
  // a) try freeing jail if there are jailed team members b) capture the flag
  if (tJailed.length > 0) {
    return {
      x: this.x < WIDTH - FIELD_PADDING ? r2 : -r2,
      y: this.y < HEIGHT - FIELD_PADDING ? r2 : -r2
    };
  }
  if (eFlag.pickedUpBy !== null && eFlag.pickedUpBy.id === this.id) {
    return {
      x: 0,
      y: -2
    };
  }
  return {
    x: this.x < eFlag.x ? r2 : -r2,
    y: this.y < eFlag.y ? r2 : -r2
  };
}

8
Vielleicht möchten Sie dies zuerst (oder sogar gleichzeitig) als Sandbox-Post in Meta veröffentlichen, wie ich es mit RvB getan habe . Es ist eine komplizierte Art von Wettbewerb, und es ist sehr hilfreich, einen Ort zu haben, an dem Sie und andere Dinge debuggen können. (Übrigens, es macht mir nichts aus, dass Sie meinen Code verwenden, obwohl ich nicht sagen kann, dass er dokumentiert oder sogar schrecklich gut organisiert ist: P)
Calvins Hobbys

1
Es wäre hilfreich, wenn Sie den Controller-Link auf jsfiddle.net/prankol57/4L7fdmkk/embedded/result für Vollbild ändern würden.
LegionMammal978

2
Ist der Controller nicht einer der wichtigsten Teile ...?
Alex A.

1
@AlexA Ja, aber wie würde das Posten in der Sandbox helfen, Fehler im Controller zu beheben (keine Antworten laden, Antworten ausführen)? Die Leute müssten anfangen, tatsächliche Antworten zu posten, die funktionieren, was meiner Meinung nach nicht der Grund für Meta ist, was bedeutet, dass ich es wahrscheinlich einfach hier posten sollte. Selbst in normalen KOTH-Controllern treten unvermeidlich Fehler auf.
Soktinpk

1
Mein Bot erscheint nicht auf dem Controller.
LegionMammal978

Antworten:


4

Red - Lazy Jail Hog | Fauler Flagger

Geht näher an diese beiden heran: Blaus Gefängnis oder Blaus Flagge.

  • Wenn du ins Gefängnis gehst, ziehst du ins Gefängnis und hörst auf. (Da Blau sein eigenes Gefängnis nicht berühren kann, wird es unbesiegbar sein und automatisch alle Verbündeten befreien.)
  • Wenn es um die Flagge geht, bewegt es sich blindlings um die Flagge und kehrt zurück.

Schließlich wird sein Gehirn nur im messages[29354]ersten Zug vollständig gespeichert und initialisiert. Wenn Verbündete eine bessere Verwendung für diesen Bot finden, können sie sein Gehirn für ihren höheren Zweck ersetzen.

if (move === 0) {
    //On the first turn, set messages[this.id] to the function I will call to move me
    messages[this.id] = function(move, tJailed, eJailed, team, enemies, tFlag, eFlag, messages) {
        //Arbitrary function to move to a point at some speed, which may be in the point
        //  If we are at the point, undefined is returned
        var moveTo = function(p, max) {
            if (!p) {
                return {x:0, y:0};
            }
            max = Math.min(this.strength, max || p.max || 2);
            var dx = p.x - this.x;
            var dy = p.y - this.y;
            var dist = Math.abs(dx)+Math.abs(dy);
            if (dist === 0) {
                return undefined; 
            } else if (dist < max) {
                return {x: dx, y: dy};
            }
            var ux = Math.floor(max * dx / dist);
            var uy = Math.floor(max * dy / dist);
            while (Math.abs(ux) + Math.abs(uy) < max) {
                if (ux + this.x !== p.x) {
                    ux += ux > 0 ? 1 : -1;
                } else if (uy + this.y !== p.y) {
                    uy += uy > 0 ? 1 : -1;
                } else {
                    break;
                }
            }
            return {x: ux, y:uy};
        }.bind(this);

        //Set the way points
        var points = [];
        if (this.x > WIDTH/2) {
            points.push({x: WIDTH-FIELD_PADDING, y:HEIGHT/2+5});
            points.push({x: WIDTH-FIELD_PADDING, y:FIELD_PADDING, max: 5});
            points.push({x: WIDTH-FIELD_PADDING, y:HEIGHT/2+25, max: 5});
        } else {
            points.push({x: FIELD_PADDING, y:HEIGHT/2+5});
            points.push({x: FIELD_PADDING, y:FIELD_PADDING, max: 5});
            points.push(undefined); //Special case to do nothing / hog the jail
        }

        //Move through the points
        var state = messages[this.id].state || 0;
        var ret;
        while (!ret) {
            //Special case: if we were doing nothing, make sure we're where we think we were
            if (!points[state]) {
                ret = moveTo(points[state-1]);
                if (ret) {
                    state = 0;
                }
            }

            //Move to the next point
            ret = moveTo(points[state]);
            if (!ret) {
                state = (state + 1) % points.length;
            }
        }
        messages[this.id].state = state;
        return ret;
    };
}
//Move me based on that function, which may be changed by my allies
return messages[this.id].call(this, move, tJailed, eJailed, team, enemies, tFlag, eFlag, messages);

Der Regler verwendet den euklidischen Abstand für Bewegungen.
TheNumberOne

4

Rot - Die Wache

Dieser Bot wird die Flagge ziemlich gut bewachen. Nicht in die Quere kommen ...

if (!messages[this.id]) {
    //On the first turn, set messages[this.id] to the function I will call to move me. You can replace this function on subsequent turns
    //to control it. Additionally, you can use it as a library to find one of the best places to go to defend.
    messages[this.id] = function(move, tJailed, eJailed, team, enemies, tFlag, eFlag, messages, WIDTH, HEIGHT, FIELD_PADDING, DEFENSE_RADIUS) {
        var distance = function(p1, p2) {
            var dx = p1.x - p2.x;
            var dy = p1.y - p2.y;
            return Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
        }

        var moveTo = function(p) {
            if (!p) {
                return {x:0, y:0};
            }
            var dx = p.x - this.x;
            var dy = p.y - this.y;
            var max = this.strength;
            var dist = distance(p, this);
            if (dist < max) {
                return {x: dx, y: dy};
            }
            dx = dx * max / dist;
            dy = dy * max / dist;
            while (Math.sqrt(Math.abs(dx)+Math.abs(dy)) > max) {
                if (dx > dy) {
                    dx = dx - 0.001;
                } else {
                    dy = dy - 0.001;
                }
            }
            return {x: dx, y:dy};
        }.bind(this);

        if (tFlag.pickedUp) {
            if (tFlag.y - HEIGHT / 2 > distance(this, {x: tFlag.x, y: HEIGHT / 2})) {
                return moveTo(tFlag);
            } else {
                return moveTo({y: Math.min(this.y, tFlag.y), x: tFlag.x });
            }
        }

        if (eFlag.pickedUp == this.id) {
            return moveTo({x: x, y: HEIGHT / 2});            
        }

        var targetPoints = [];
        var crossedBorder = false;

        var weightedMiddlePoint = function(enemy) {
            var x1 = (enemy.x + tFlag.x) / 2;
            var y1 = (enemy.y + tFlag.y) / 2;
            var w = 1/Math.pow(distance(enemy, tFlag),2);
            return {x:x1,y:y1,w:w};
        }

        for (var i = 0; i < enemies.length; i++) {
            var enemy = enemies[i];
            if (enemy.isJailed){
                continue;
            }
            if (enemy.y > HEIGHT / 2) {
                crossedBorder = true;
            }
        }

        for (var i = 0; i < enemies.length; i++) {
            enemy = enemies[i];
            if (enemy.isJailed){
                continue;
            }
            if (crossedBorder) {
                if (enemy.y > HEIGHT / 2) {
                    targetPoints.push(weightedMiddlePoint(enemy));
                }
            } else {
                targetPoints.push(weightedMiddlePoint(enemy));
            }
        }

        if (targetPoints.length == 0) {
            return moveTo(eFlag);
        }

        var sumX = 0;
        var sumY = 0;
        var sumW = 0;

        for (var i = 0; i < targetPoints.length; i++) {
            point = targetPoints[i];
            sumX += point.x * point.w;
            sumY += point.y * point.w;
            sumW += point.w;
        }

        var targetPoint = {x: sumX / sumW, y: sumY / sumW};

        return moveTo(targetPoint);

    };
}

return messages[this.id].call(this, move, tJailed, eJailed, team, enemies, tFlag, eFlag, messages, WIDTH, HEIGHT, FIELD_PADDING, DEFENSE_RADIUS);

4

Blau - LegionMammal978

function repeat(el, n) // Helper function
{
    var rtn = [];
    for (var i = 0; i < n; i++)
        rtn.push(el);
    return rtn;
}
function sign(n) { return n ? n < 0 ? -1 : 1 : 0; } // Another helper function
if (!messages[this.id])
    messages[this.id] = { "dir": 1 };
if (this.isJailed) // Oh noes, I'm in jail!
{
    console.log(this.id, messages);
    if (!messages[this.id].jailTicks)
        messages[this.id].jailTicks = 0;
    messages[this.id].jailTicks++;
    // Call for help!
    messages.callsForHelp = repeat(["Help!", this.id, this.x, this.y], messages[this.id].jailTicks);
    return { "x": 0, "y": 0 };
}
if (messages[this.id].jailTicks)
    if (!(delete messages[this.id].jailTicks && delete messages.callsForHelp)) // Cleanliness
        messages[this.id].jailTicks = messages.callsForHelp = undefined;       // ...
var bounds = Math.floor(HEIGHT / 2); // Be safe with fractions
if (this.y > bounds - 5) // Get back to shelter!
    return { "x": 0, "y": this.y - this.strength <= bounds - 5 ? bounds - 5 - this.y : -4 };
var target = { "none": true, "x": WIDTH << 1, "y": HEIGHT << 1 };
enemies.forEach(function (en) { if (!en.isJailed && en.y < bounds - 5 && Math.abs(en.x - this.x) < Math.abs(target.x - this.x) && Math.abs(en.y - this.y) < Math.abs(target.y - this.y)) target = en; }, this);
if (target.none)
{
    if (this.y < bounds - 5)
        return { "x": 0, "y": 2 };
    var speed = this.strength < 30 ? 1 : 2;
    if (this.x == 5 || this.x == WIDTH - 5)
        messages[this.id].dir = -messages[this.id].dir;
    return { "x": speed * messages[this.id].dir, "y": 0 };
}
if (this.x - target.x >= 0 && this.x - target.x < this.strength)
{
    if (this.y - target.y > 0 && this.y - target.y < this.strength + target.x - this.x)
        return { "x": this.x - target.x, "y": this.y - target.y };
    if (target.y - this.y > 0 && target.y - this.y < this.strength + target.x - this.x)
        return { "x": this.x - target.x, "y": target.y - this.y };
}
if (target.x - this.x > 0 && target.x - this.x < this.strength)
{
    if (this.y - target.y > 0 && this.y - target.y < this.strength + this.x - target.x)
        return { "x": target.x - this.x, "y": this.y - target.y };
    if (target.y - this.y > 0 && target.y - this.y < this.strength + this.x - target.x)
        return { "x": target.x - this.x, "y": this.y - target.y };
}
return { "x": 6 * sign(target.x - this.x), "y": 6 * sign(target.y - this.y) };

Verteidigungsbot.


1
Ein kleines Problem mit Javascript - Sie können es nicht thisinnerhalb einer Funktion (in Ihrer forEachSchleife) verwenden. Sie müssen es vorher als Variable speichern (dh var _this = this;) und verwenden _this. Ich werde Sie als Ausnahme hinzufügen, wenn Sie bald bearbeiten, da Sie dachten, dass der Controller Ihren Code nicht geladen hat und nicht testen konnte.
Soktinpk

@soktinpk Wird nur forEachoptional verwendet thisArg.
LegionMammal978

Ich habe den Controller so aktualisiert, dass Sie ihn später bearbeiten können.
Soktinpk

1

Jäger der roten Fahne

var distance = function(x1, y1, x2, y2) {
    return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
var moveTo = function(x, y, max) {
    if (max > this.strength)
        max = this.strength;
    var dX = x - this.x;
    var dY = y - this.y;
    var dist = distance(x, y, this.x, this.y);
    if (dist <= max) {
        return {x: dX, y: dY};
    }
    dX = dX * max / dist;
    dY = dY * max / dist;
    while (Math.sqrt(Math.abs(dX)+Math.abs(dY)) > max) {
        if (dX > dY) {
            dX = dX - 0.001;
        } else {
            dY = dY - 0.001;
        }
    }
    return {x: dX, y:dY};
}.bind(this);

var getSurroundingPoints = function(x, y, dist) {
    var points = [];
    for (var i = x - dist; i <= x + dist; i+= 0.2) {
        for (var j = y - dist; j <= y + dist; j+= 0.2) {
            if (i >= 0 && j >= 0 && j <= 180 && distance(i,j,x,y) <= dist) {
                points.push({x: i, y: j, danger: 0});
            }
        }
    }
    return points;
}

if (this.isJailed) {
    return {x:0, y:0};
}

var destination = {x: eFlag.x, y: eFlag.y}; //default: try to get the flag
if (eFlag.pickedUpBy != null) { //we got the flag
    if (eFlag.pickedUpBy.id == this.id) { //I got the flag => get back to the red side
        if (distance(this.x, this.y, this.x, 175.1) <= this.strength) {
            return moveTo(this.x, 175.1, this.strength);
        }
        destination.x = this.x;
        destination.y = 180;
    } else { //someone else got the flag => free those in the jail
        destination.x = 20;
        destination.y = 20;
    }
} else if (this.y > HEIGHT / 2) { //I am on the red side
    return moveTo(175, 175, 2);
} else if (distance(this.x, this.y, eFlag.x, eFlag.y) <= 15)  { //I am in the safe zone (flag)
    if (this.strength < 20)
        return {x:0, y:0};
    return moveTo(eFlag.x, eFlag.y, 2); //get the flag
} else if (distance(this.x, this.y, eFlag.x, eFlag.y) - this.strength <= 15)  { //I can reach the safe zone (flag)
    return moveTo(eFlag.x, eFlag.y, distance(this.x, this.y, eFlag.x, eFlag.y) - 14);
} else if (distance(this.x, this.y, 20, 20) < 10)  { //I am in the safe zone (jail)
    if (this.strength < 20)
        return {x:0, y:0};
} else if (distance(this.x, this.y, eFlag.x, eFlag.y) - this.strength <= 15)  { //I can reach the safe zone (jail)
    return moveTo(20, 20, this.strength);
}

//I am somewhere on the blue side
var points = getSurroundingPoints(this.x, this.y, this.strength);
var me = this;
points.forEach(function(point) {
    if (point.y < 175) {
        enemies.forEach(function(enemy) {
            if (distance(enemy.x, enemy.y, point.x, point.y) <= enemy.strength+10) {
                point.danger += 5;
            }
        });
        if (distance(me.x, me.y, point.x, point.y) <= 2 && point.danger == 0) {
            point.danger--;
        }
    }
});
var bestPoint = points[0];
points.forEach(function(point) {
    if (point.danger < bestPoint.danger || (point.danger == bestPoint.danger && distance(point.x, point.y, destination.x, destination.y) < distance(bestPoint.x, bestPoint.y, destination.x, destination.y))) {
        bestPoint = point;
    }
});
return moveTo(bestPoint.x, bestPoint.y, this.strength);

Versucht die Flagge zu bekommen. Wenn jemand anderes es bereits hat, läuft Flag Hunter auf das Gefängnis zu, verwirrt den Feind oder befreit seine Teammitglieder.


1

Blau - Ein lustiger guter Kerl

Erster Versuch sowohl mit Javascript als auch mit Code-Golf zu programmieren. Es jagt alles, was der Flagge zu nahe kommt und versucht, ihre Züge nach vorne zu lenken. Andernfalls wird es ausgeführt, um Teamkollegen im Gefängnis zu retten oder faul zu versuchen, die Flagge des anderen Teams zu erreichen.

// Euclidean distance
var distance = function(p1,p2){
 return Math.sqrt( (p1.x - p2.x)**2 + (p1.y - p2.y)**2 );
}

// points from p1 to p2
var direction = function(p1, p2){
 return Math.atan2( p2.y - p1.y, p2.x - p1.x);
}

//moving
var move2 = function(dir, step){
    if(isNaN(dir)){   dir = 0; };
    if(isNaN(step)){ step = 0; };
    return {
        x: Math.cos(dir)*step,
        y: Math.sin(dir)*step
    };
}


var intercept_at = function(me, they, field){
    if ( distance(me, they)<me.strength ){
        return they;
    }

    //console.log("I am at (", me.x, me.y, ") ");
    //console.log("They are at (", they.x, they.y, ") ");           


    //first goal
    if( field.my_flag.pickedUpBy == null ){
        their_goal = field.my_flag;
        eta = (distance(they, their_goal) - they.strength)/2;
        their_dir = direction(they, their_goal);
        for( var i=1; i<eta; i++){
          they_next = {
            x: they.x + Math.cos(their_dir)*(they.strength/2 + (i+1)*2),
            y: they.y + Math.sin(their_dir)*(they.strength/2 + (i+1)*2)
          };
          if( (distance(me, they_next) )<(1.95*i) ){
            //console.log("goal is flag at (", their_goal.x, their_goal.y, ") ");   
            //console.log("I can reach it at (", they_next.x, they_next.y, ") in less than ", i);
            return they_next;
          }
        }
    // second goal  
    }

    my_flag = field.my_flag;
    their_goal = { x: my_flag.x, y:field.h/2 - 5};
    eta = (distance(my_flag, their_goal) - they.strength)/2;
    their_dir = direction(my_flag, their_goal);
    for( var i=0; i<eta; i++){
        they_next = {
            x: my_flag.x + Math.cos(their_dir)*(they.strength/2 + (i+1)*2),
            y: my_flag.y + Math.sin(their_dir)*(they.strength/2 + (i+1)*2)
        };
        if( (distance(me, they_next) )<(1.95*i) ){
            //console.log("goal is escaping at (", their_goal.x, their_goal.y, ") "); 
            //console.log("I can front-run it at (", they_next.x, they_next.y, ") in less than ", i);
            return they_next;
        }       
    }
    //console.log("Goose chase at (", they.x, they.y, ") ");
    return they;
}

var intercept = function(me, they, field){
  they_at = intercept_at(me, they, field);
  they_at.y = Math.min(they_at.y, field.h/2-5)
  dist2me = distance(me, they_at);
  dir2me = direction(me, they_at);  
  if ( dist2me<me.strength ){
    return move2(dir2me, dist2me);
  }else{
    return move2(dir2me, 2);
  }
}


var closest_enemy = function(my_flag, enemies){
    cur_tgt_num = null;
    cur_tgt_dst = 999;

    for( var i=0; i<enemies.length; i++){
      if(!enemies[i].isJailed){
        cur_dst = distance(enemies[i], my_flag);
        if ( cur_dst < cur_tgt_dst ){
          cur_tgt_dst = cur_dst;
          cur_tgt_num = i;
        }
      }
    }    

    return enemies[cur_tgt_num];
}


var enemies_closer_than = function(enemies, radius, field){
    closer_than = 0;
    for( var i = 0; i<enemies.length; i++){
        if(!enemies[i].isJailed){
            closer_than = closer_than + ( distance(enemies[i], field.my_flag)<radius );
        }
    }
    return closer_than;
}


var team_jailed = function(team){
    for( var i = 0; i<team.length; i++){
        if(team[i].isJailed){
            return team[i];
        }
    }
    return null;
}


var bound_positions = function(p0, field){
    p0.x = Math.max(0, Math.min(p0.x, field.w));
    p0.y = Math.max(0, Math.min(p0.y, field.h));    
    return p0;
}

var avoid_obstacle = function(me, goal, obstacle, field, can_run){
    //we know that there is a safe haven
    if( distance(me, goal)<me.strength && can_run){
        return move2(direction(me, goal), me.strength)
    }

    if( obstacle == null ){
        return move2(direction(me, goal), 2);
    }

    ob_dir = direction(me, obstacle);
    if( distance(me, obstacle) < Math.sqrt(2)*(4+obstacle.strength)){
        me_next1 = bound_positions({x: me.x - 4*Math.cos(ob_dir),y: me.y - 4*Math.sin(ob_dir)}, field);
        me_next2 = bound_positions({x: me.x - 4*Math.sin(ob_dir),y: me.y - 4*Math.cos(ob_dir)}, field);
        me_next3 = bound_positions({x: me.x - 4*Math.sin(ob_dir),y: me.y - 4*Math.cos(ob_dir)}, field);
        if( distance(goal, me_next1) < distance(goal, me_next2) ){
          if( distance(goal, me_next1) < distance(goal, me_next3) ){
            me_next = me_next1;
          }else{
            me_next = me_next3;
          }
        }else{
          if( distance(goal, me_next2) < distance(goal, me_next3) ){
            me_next = me_next2;
          }else{
            me_next = me_next3;
          }
        }           

        //console.log("Escaping from (", obstacle.x, obstacle.y, ")");
        return move2(direction(me, me_next), 4);
    }

    eta = (distance(me, goal)/2);
    my_dir = direction(me, goal);
    me_next = me;
    i=0;
    while(i<eta && (distance(me_next, obstacle) > obstacle.strength+2*i)){
       i++;
       me_next = {x: me_next.x + i*Math.cos(my_dir),y: me_next.y + i*Math.sin(my_dir)};
       me_next = bound_positions(me_next, field);
       if( distance(me_next, obstacle) < obstacle.strength+2*i ){
         me_next1 = {x: me_next.x + i*Math.sin(ob_dir),y: me_next.y - i*Math.cos(ob_dir)};
         me_next2 = {x: me_next.x - i*Math.sin(ob_dir),y: me_next.y + i*Math.cos(ob_dir)};
         if( distance(goal, me_next1) > distance(goal, me_next2) ){
            me_next = bound_positions(me_next2, field);
         }else{
            me_next = bound_positions(me_next1, field);
         }
       }
    }
    if( distance(me_next, obstacle) > obstacle.strength+2*i ){
        //console.log("Trying to reach goal at (", goal.x, goal.y, ") by pointing at (",me_next.x, me_next.y,")");      
        return move2(direction(me, me_next), 2);
    }

    //console.log("Waiting to reach (", goal.x, goal.y,")");
    my_dir = direction(me, goal);
    me_next = {
        x: me.x + Math.cos(my_dir)*6,
        y: me.y + Math.sin(my_dir)*6
    }
    for( var i=0; i<field.team.length; i++){
        me_next.x = me_next.x - Math.sign(field.team[i].x - me_next.x);
        me_next.y = me_next.y - Math.sign(field.team[i].y - me_next.y);
    }               
    return move2(direction(me, me_next), Math.floor(Math.random() * 2));
}


var field = {
    w: WIDTH, 
    h: HEIGHT, 
    g: DEFENSE_RADIUS,
    my_flag: tFlag,
    their_flag: eFlag,
    team: team,
    enemies: enemies
    };

var n_enemy = enemies.length;


  if( enemies_closer_than(enemies, field.h*0.67, field)>0 || tFlag.pickedUpBy !== null){
    //console.log("My flag is in danger");      

    // directive defend
    messages[123 + this.id] = 'defend_own_flag';
    if ( tFlag.pickedUpBy !== null ) {
      return intercept(this, tFlag.pickedUpBy, field);
    }else{
      return intercept(this, closest_enemy(tFlag, enemies), field);
    }   
  }else{

    if( tJailed.length>0 ){

        // directive support
        console.log("rescueing team member");
        console.log(tJailed);
        return avoid_obstacle(this, tJailed[0], closest_enemy(this, enemies), field, 0);
    }else{

      // directive attack
      messages[123 + this.id] = 'capture_enemy_flag';
      if ( eFlag.pickedUpBy == null ){
        //console.log("Going to capture the flag");
        return avoid_obstacle(this, eFlag, closest_enemy(this, enemies), field, 0)

      }else if (this.id == eFlag.pickedUpBy.id){
        //console.log("I have the flag");
        return avoid_obstacle(this, {x:this.x, y:field.h/2 - 1}, closest_enemy(this, enemies), field, 1);      

      }else {
        //console.log("Someone else has the flag");
        return avoid_obstacle(this, eFlag, closest_enemy(this, enemies), field, 0);

      }
    }
  }

return move2(0,0);
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.