Intro
Dies ist ein interaktiver King-of-the-Hill- Wettbewerb, bei dem der Controller vollständig in einem Stapel-Snippet am Ende der Frage enthalten ist. Der Controller liest die Antworten automatisch und spielt die Spiele durch. Jeder kann es jederzeit direkt in seinem Browser ausführen.
Die Mechanik dieses Wettbewerbs ist der von Red vs. Blue - Pixel Team Battlebots sehr ähnlich . Abgesehen davon ist das gespielte Spiel, obwohl es noch gitterbasiert ist, völlig anders. Jedes Spiel ist 1 gegen 1 und es gibt keine Teams. Jeder Beitrag kämpft für sich und nur einer wird der endgültige Champion.
Der Controller verwendet JavaScript. Da JavaScript die einzige clientseitige Skriptsprache ist, die von den meisten Browsern unterstützt wird, müssen alle Antworten auch in JavaScript geschrieben werden .
In dieser Spezifikation wird kursiver Text verwendet, um den formalen Begriff für eine Spielmechanik oder -eigenschaft anzugeben. Diese Begriffe werden durchgehend verwendet, um eine zusammenhängende und klare Art der Bezugnahme auf die verschiedenen Teile des Spiels zu gewährleisten.
Spielweise
Grundlagen
Jede Antwort auf diese Frage repräsentiert einen Spieler . Ein Spiel ist ein Wettbewerb zwischen zwei Spielern, P1 und P2 . Jeder Spieler kontrolliert eine Herde von 8 Bots , die von 0 bis 7 nummeriert sind. Die Spiele finden im Raster statt , in einer Arena mit 128 × 64 Zellen , deren unterste 8 Reihen als Wände (die "Blöcke") beginnen, und in anderen Reihen als Luft . Zellen außerhalb der Gittergrenzen werden als Luft betrachtet.
Die x-Koordinate des Gitters reicht von 0 links bis 127 rechts und y reicht von 0 oben bis 63 unten.
Beispiel Startaufstellung:
Bots bleiben immer an den Rasterzellen ausgerichtet und mehrere Bots können dieselbe Zelle belegen. Bots können nur Luftzellen besetzen. Die Bots von P1 beginnen immer in einer Zeile 0-7 ganz links in der Zeile über den Wänden und die Bots von P2 beginnen immer in einer Zeile 7-0 ganz rechts.
Die Nachbarn eines Bots oder einer Zelle sind die 8 Zellen, die direkt orthogonal und diagonal dazu sind.
Das Sichtfeld ( FOV ) eines Bots ist das 13 × 13-Zellenquadrat, das auf einem Bot zentriert ist. Ein Zellen- oder Feindbot befindet sich im Sichtfeld eines Spielers, wenn es sich im Sichtfeld von mindestens einem der Bots des Spielers befindet.
Bewegungen und Aktionen
Während eines Spiels darf sich jeder Spieler 1000 Mal bewegen . P1 bewegt sich zuerst, dann P2, dann P1 und so weiter, bis insgesamt 2000 Züge ausgeführt wurden. An diesem Punkt endet das Spiel.
Während eines Zuges erhält jeder Spieler Informationen über den Spielstatus und die Gitterzellen und feindlichen Bots in seinem Sichtfeld und entscheidet anhand dieser Informationen über eine Aktion, die jeder seiner Bots ausführen soll.
Die Standardaktion ist nichts zu tun , wenn sich der Bot nicht bewegt oder mit dem Gitter interagiert.
Die anderen Aktionen sind Bewegen , Greifen und Platzieren :
Ein Bot kann bewegt auf eine ihrer Nachbarzellen C , wenn:
- C ist nicht außerhalb der Grenzen,
- C ist Luft (dh keine Wand),
- und mindestens einer von Cs Nachbarn ist eine Mauer.
Im Erfolgsfall wechselt der Bot nach C.
Ein Bot kann eine seiner Nachbarzellen C greifen, wenn:
- C ist nicht außerhalb der Grenzen,
- C ist eine Wand,
- und der bot trägt noch keine mauer.
Bei Erfolg wird C zu Luft und der Bot trägt jetzt eine Wand.
Ein Bot kann in eine seiner Nachbarzellen C legen , wenn:
- C ist nicht außerhalb der Grenzen,
- C ist Luft,
- Keine Bots eines Spielers besetzen C,
- und der bot trägt eine mauer.
Bei Erfolg wird C zu einer Mauer und der Bot trägt keine Mauer mehr.
Erfolglose Aktionen führen zu einem Nichtstun.
Über einer Zelle, die von mindestens einem Bot mit Wänden besetzt ist, ist ein kleines, wandfarbenes Quadrat gezeichnet. Bots starten ohne Wände.
Erinnerung
Während eines Zuges kann ein Spieler auf sein Gedächtnis zugreifen und es ändern , eine anfangs leere Zeichenfolge, die das ganze Spiel über gültig ist und zum Speichern strategischer Daten verwendet werden kann.
Tor
Die Zelle im gelben Fadenkreuz ist das Ziel , das an einer zufälligen Position beginnt. Jeder Spieler hat eine Punktzahl , die bei 0 beginnt. Wenn sich der Bot eines Spielers zum Ziel bewegt, erhöht sich die Punktzahl dieses Spielers um 1 und das Ziel wird vor dem nächsten Zug zufällig neu positioniert. Der Spieler mit der höchsten Punktzahl am Ende eines Spiels gewinnt. Es ist ein Gleichstand, wenn die Ergebnisse gleich sind.
Wenn sich mehrere Bots während eines Zuges zum Ziel bewegen, erhält der Spieler immer noch nur einen Punkt.
Wenn sich das Ziel 500 Züge lang an derselben Stelle befunden hat, wird es nach dem Zufallsprinzip neu positioniert. Jedes Mal, wenn das Ziel zufällig positioniert wird, wird es garantiert nicht auf eine Zelle gelegt, die von einem Bot besetzt ist.
Was zu programmieren
Schreiben Sie einen Body für diese Funktion:
function myMove(p1, id, eid, move, goal, grid, bots, ebots, getMem, setMem) {
//body goes here
}
Es wird jedes Mal aufgerufen, wenn sich Ihr Spieler bewegt, und muss die Aktionen zurückgeben, die jeder Ihrer Bots während dieser Bewegung ausführen soll.
Sie können den Basiscode als Ausgangspunkt verwenden.
Parameter
p1
ist ein Idiot,true
wenn du P1false
bist und wenn du P2 bistid
ist eine Ganzzahl, die die Antwort-ID Ihrer Antwort ist.
- Sie finden die ID einer Antwort, indem Sie auf den Link "Teilen" darunter klicken und
a/
in der URL direkt nach der Nummer suchen .- Die ID des Testeintrags ist -1.
eid
ist eine Ganzzahl, die die Antwort-ID der Antwort Ihres Feindes ist.move
ist eine ganze Zahl von 1 bis 1000, die angibt, in welcher Bewegung Sie sich befinden.goal
ist ein Objekt mitx
undy
Eigenschaften. Dies sind die Koordinaten des Ziels. Sie werden auch dann gegeben, wenn das Ziel außerhalb Ihres Sichtfelds liegt.grid
ist eine Funktion, die x- und y-Argumente akzeptiert, zgrid(x,y)
. Es gibt zurück:
-1
für 'unbekannt', wenn die Argumente keine zwei Ganzzahlen sind oder wennx,y
nicht in Ihrem Sichtfeld.0
für "Luft", wennx,y
außerhalb der Grenzen oder wenn die Zelle beix,y
Luft ist.1
für 'Wand', wenn die Zelle beix,y
eine Wand ist.
bots
ist ein Array Ihrer 8 Bots. Seine Elemente sind Objekte mit Eigenschaftenx
,y
undhasWall
:
x
undy
sind die Koordinaten des Bots.hasWall
ist,true
wenn der Bot eine Wand trägt undfalse
wenn nicht.
bots
Wird immer normal geordnet, entspricht der N-te Index der Bot-Nummer N.ebots
ist ein Array von Objekten mitx
,y
undhasWall
Eigenschaften wiebots
. Nur die feindlichen Bots in Ihrem FOV sind inebots
. Es hätte also die Länge 0, wenn sich keine feindlichen Bots in Ihrem Sichtfeld befinden. Es wird zufällig bestellt.getMem
ist eine Funktion ohne Argumente, die Ihr Gedächtnis zurückgibt.setMem
ist eine Funktion, die ein Argument M akzeptiert. Wenn M eine Zeichenfolge mit maximal 256 Zeichen ist, wird Ihr Speicher auf M aktualisiert, andernfalls passiert nichts.
Das Browserobjekt console
ist nur für den Testeintrag verfügbar.
Rückgabewert
Ihre Funktion muss ein Array mit genau 8 Ganzzahlen im Bereich von 0 bis 24 zurückgeben. Der Wert am Index N ist die Aktion, die der Bot Nummer N ausführen wird.
Alle Ihre Bots werden nichts tun, wenn Ihre Funktion:
- Wirft einen Fehler jeglicher Art. ( Fehler )
- Die Ausführung dauert länger als 20 Millisekunden . ( Zeitüberschreitung )
- Gibt kein Array mit 8 ganzen Zahlen zwischen 0 und 24 zurück. ( Fehlerhaft )
Der Einfachheit halber werden die Anzahl der Fehler, Zeitüberschreitungen und fehlerhaften Aktionen angezeigt, wenn ein Spiel endet.
Jede der Zahlen von 0 bis 24 entspricht einer bestimmten Bot-Aktion:
- 0 ist für nichts zu tun.
- 1-8 sind für den Umzug.
- 9-16 sind zum greifen.
- 17-24 sind für die Platzierung.
Jeder der 8 Werte für Verschieben, Greifen und Platzieren entspricht einer der Nachbarzellen des Bots, wie hier gezeigt:
So ist zum Beispiel 15
die Aktion zum Ergreifen der Zelle unter dem Bot.
Bot-Aktionen werden in der Reihenfolge Bot 0 bis Bot 7 ausgeführt. Wenn beispielsweise Bot 0 während eines Zuges angewiesen wird, eine Wand in dieselbe Luftzelle zu platzieren, zu der sich Bot 1 bewegen soll, wird die Luftzelle zu einer Wand vor Bot Die Aktion von 1 wird ausgeführt und Bot 1 ist nicht erfolgreich.
Erfolglose Handlungen werden zu Nichts und sollen gescheitert sein . Fehlgeschlagene Aktionszähler werden auch angezeigt, wenn das Spiel endet.
Regeln
Ich kann Benutzer oder Antworten, die diesen Regeln nicht entsprechen, vorübergehend oder dauerhaft disqualifizieren . Disqualifizierte Einsendungen sind nicht gewinnberechtigt.
Wenn Sie Variablen oder Funktionen deklarieren, müssen Sie das
var
Schlüsselwort verwenden.
ZBvar x = 10
odervar sum = function(a, b){ return a + b }
Dinge, die deklariert wurden, ohnevar
global zu werden, und die den Controller stören könnten. Es wurden Schritte unternommen, um diese Störung auszuschließen, aber stellen Sie dies sicher.Ihr Code sollte nicht langsam laufen oder Zeit verschwenden.
Es ist unmöglich, die Ausführung von JavaScript-Funktionen während der Ausführung zu stoppen, sodass der Code jedes Spielers vollständig ausgeführt wird. Wenn die Ausführung Ihres Codes viel Zeit in Anspruch nimmt, wird jeder, der Ihren Player ausführt, dies bemerken und sich darüber ärgern. Im Idealfall werden die Einträge immer innerhalb der 20-ms-Grenze ausgeführt.- Sie müssen Code verwenden, der mit ECMAScript 5 in der neuesten Version von Firefox kompatibel ist, da ich ihn hier ausführen werde. Verwenden Sie keine Funktionen aus ECMAScript 6, da dies in vielen Browsern noch nicht unterstützt wird.
- Sie können bis zu dreimal antworten , aber nur, wenn jede Ihrer Strategien erheblich anders ist. Sie können die Antworten beliebig oft bearbeiten.
- Sie dürfen nicht versuchen, irgendeine Art von Speicher zu haben, außer durch die Verwendung von
getMem
undsetMem
. - Sie dürfen nicht versuchen, auf den Controller, den Code eines anderen Players oder externe Ressourcen zuzugreifen oder diese zu ändern.
- Sie dürfen nicht versuchen, etwas in JavaScript eingebautes zu ändern.
- Antworten müssen nicht deterministisch sein. Sie können verwenden
Math.random
.
Antwortformat
#EntryName
Notes, etc.
<!-- language: lang-js -->
//function body
//probably on multiple lines
More notes, etc.
Der erste mehrzeilige Codeblock muss Ihren Funktionskörper enthalten.
Der Eintragsname ist auf 20 Zeichen begrenzt.
Ihr Eintrag wird im Controller mit dem Titel EntryName - Username [answer ID]
sowie, [DQ]
falls er disqualifiziert ist, angezeigt.
Gewinnen
Wenn die Frage mindestens drei Wochen lang gestellt wurde und sich die Beantwortung beruhigt hat, werde ich den Champion krönen.
Ich verwende die Autorun- Funktion des Controllers . In einer Autorun-Runde spielt jeder nicht disqualifizierte Spieler zwei Spiele gegeneinander, eines als P1, eines als P2 (Double Round Robin).
Ich werde in ein paar Stunden so viele Runden wie möglich automatisch starten. Dies hängt davon ab, wie viele Einreichungen es gibt und wie zeitintensiv sie sind. Aber seien Sie versichert, ich bin bestrebt, eine genaue endgültige Rangliste zu erhalten. Der Spieler mit den meisten Gewinnen ist der Champion und seine Antwort wird akzeptiert.
Ich verwende Firefox auf einem Laptop mit Windows 8.1 64-Bit, 4 GB RAM und einem 1,6-GHz-Quad-Core-Prozessor.
Preis
Ich werde eine PPCG-Challenge schreiben und veröffentlichen, die speziell dem Champion gewidmet ist. Es wird irgendwie ihren Benutzernamen oder Avatar oder etwas über sie beinhalten. Ich werde privat entscheiden, worum es bei der Herausforderung geht, wenn dieser Wettbewerb vorbei ist. Ich werde es nach besten Kräften schreiben und versuchen, sicherzustellen, dass es sich um eine Hot Network-Frage handelt.
Regler
Führen Sie dieses Snippet aus oder rufen Sie dieses JSFiddle auf, um den Controller zu verwenden. Es beginnt mit zufälligen Spielern. Ich habe es nur gründlich in Firefox und Chrome getestet.
<style>html *{font-family:Consolas,Arial,sans-serif}canvas{margin:6px}button,input table,select{font-size:100%}textarea{font-family:monospace}input[type=text],textarea{padding:2px}textarea[readonly]{background-color:#eee}select{width:250pt;margin:3px 0}input[type=radio]{vertical-align:-.25em}input[type=checkbox]{vertical-align:-.15em}.c{margin:12px}.h{font-size:125%;font-weight:700}#main td{padding:12px;text-align:left}#main table{margin-left:auto;margin-right:auto}#main{text-align:center}#title{margin:12px;font-size:175%;font-weight:700;color:#333}#delay{text-align:right}#statsTable table{border-collapse:collapse}#statsTable td{border:1px solid gray;padding:3pt;font-family:monospace;text-align:center}#footnotes{margin:18px 0 0;font-size:75%}#arWrapper{border:2px solid red;background-color:#fff4f4}</style><div id=loadStatus>Loading entries...</div><div id=main><div id=title>Block Building Bot Flocks</div><div><span id=p1Title class=p1Color></span> vs. <span id=p2Title class=p2Color></span></div><canvas id=canvas>Canvas unsupported!</canvas><div><span id=p1Score class=p1Color>0</span> | <span id=moveCounter>0</span> | <span id=p2Score class=p2Color>0</span></div><div class=c><button id=runPause type=button onclick=runPause()>Run</button> <button id=moveOnce type=button onclick=moveOnce()>Move Once</button> <button type=button onclick=newGame()>New Game</button></div><div class=c><input id=delay size=4 value=20> ms delay <input id=showNumbers type=checkbox onclick=toggleNumbers()><label for=showNumbers>Show bot numbers</label> <input id=showLOS type=checkbox onclick=toggleLOS()><label for=showLOS>Show field of view</label></div><table><tr><td><div id=p1Header class="p1Color h">Player 1</div><div><select id=p1Select onchange=changeSelect(!0)></select></div><div><a id=p1Link href=javascript:;>Answer Link</a></div><td><div id=p2Header class="p2Color h">Player 2</div><div><select id=p2Select onchange=changeSelect(!1)></select></div><div><a id=p2Link href=javascript:;>Answer Link</a></div></table><div>Test Entry</div><div><textarea id=testEntry rows=8 cols=64>return [0,0,0,0,0,0,0,0]</textarea></div><div class=c><button type=button onclick=autorun()>Autorun N Rounds</button> N = <input id=N size=4 value=1> <input id=arTestEntry type=checkbox><label for=arTestEntry>Include Test Entry</label></div><div id=footnotes><input id=debug type=checkbox onclick=toggleDebug()><label for=debug>Console debug messages</label> | Scale: <input id=sc1 type=radio name=sc value=1><label for=sc1>Micro</label><input id=sc3 type=radio name=sc value=3><label for=sc3>Small</label><input id=sc6 type=radio name=sc value=6 checked><label for=sc6>Normal</label><input id=sc9 type=radio name=sc value=9><label for=sc9>Large</label> | Colors: <input id=normalCo type=radio name=co value=normal checked><label for=normalCo>Normal</label><input id=pastelCo type=radio name=co value=pastel><label for=pastelCo>Pastels</label><input id=neonCo type=radio name=co value=neon><label for=neonCo>Neon</label> <button type=button onclick=reload()>Reload</button><div id=invalidWrapper><br>No entry name/code found: <span id=invalid></span></div></div></div><div id=arWrapper><div id=arInfo class=c>Autorun in progress. Running game <span id=arProgress></span>.</div><div id=arResults><div class="c h">Autorun Results</div><div class=c>Players: <span id=arPlayers></span><br>Rounds: <span id=arRounds></span><br>Games per round: <span id=arGpR></span><br>Total games: <span id=arTotal></span><br></div><div class=c><strong>Leaderboard:</strong></div><div id=leaderboard class=c></div><div class=c>(W = wins, T = ties, L = losses, G = total goals, E = errors, I = timeouts, M = malformed actions, F = failed actions)</div><div class=c><strong>Player vs. Player Statistics:</strong></div><div id=statsTable class=c></div><div class=c>The top row has the ID's of P1.<br>The left column has the ID's of P2.<br>Every other cell not on the diagonal has the form "[P1 win count] [tie count] [P2 win count]".</div><div class=c><button type=button onclick=closeAutorun()>Close</button></div></div></div><script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><script>function setGlobals(e){G={},G.QID=50690,G.SITE="codegolf",G.DQ_ANSWERS=[],G.DQ_USERS=[],G.DEBUG=Q("#debug").is(":checked"),G.SHOW_NUMBERS=Q("#showNumbers").is(":checked"),G.SHOW_LOS=Q("#showLOS").is(":checked"),G.BOTS=8,G.LOS=6,G.W=128,G.H=64,G.SCALE=e?6:parseInt(Q('input[name="sc"]:checked').val()),G.CW=G.SCALE*G.W,G.CH=G.SCALE*G.H,G.TOTAL_MOVES=2e3,G.GOAL_LIFESPAN=500,G.MEM_MAX_LENGTH=256,G.TIME_LIMIT=20;var t=Q('input[name="co"]:checked').val();e||"normal"===t?G.COLORS={AIR:"#ccc",WALL:"#888",GOAL:"rgba(255,255,0,0.6)",BG:"#f7f7f7",P1:"#00f",P1_TEXT:"#008",P1_LOS:"rgba(0,0,255,0.1)",P2:"#f00",P2_TEXT:"#800",P2_LOS:"rgba(255,0,0,0.1)"}:"pastel"===t?G.COLORS={AIR:"#cef0ff",WALL:"#66cc66",GOAL:"rgba(0,0,0,0.3)",BG:"#fdfde6",P1:"#f4a034",P1_TEXT:"#a35f00",P1_LOS:"rgba(255,179,71,0.2)",P2:"#f67cf6",P2_TEXT:"#b408b4",P2_LOS:"rgba(249,128,249,0.2)"}:"neon"===t&&(G.COLORS={AIR:"#000",WALL:"#444",GOAL:"rgba(255,255,0,0.9)",BG:"#999",P1:"#0f0",P1_TEXT:"#5f5",P1_LOS:"rgba(255,128,0,0.15)",P2:"#f0f",P2_TEXT:"#f5f",P2_LOS:"rgba(0,255,255,0.15)"}),G.SCOREBOARD={P1SCORE:void 0,MOVE:void 0,P2SCORE:void 0},G.CTX=void 0,G.PLAYERS=void 0,G.GAME=void 0,G.TIMER=void 0,G.RUNNING=!1}function reload(){var e="undefined"==typeof G;e||stopTimer(),setGlobals(e);var t=Q("#canvas");t.width(G.CW).height(G.CH).prop({width:G.CW,height:G.CH}),G.CTX=t[0].getContext("2d"),G.CTX.font=(2*G.SCALE).toString()+"px Courier New",G.SCOREBOARD.P1SCORE=Q("#p1Score"),G.SCOREBOARD.MOVE=Q("#moveCounter"),G.SCOREBOARD.P2SCORE=Q("#p2Score"),Q("body").css("background-color",G.COLORS.BG),Q(".p1Color").css("color",G.COLORS.P1),Q(".p2Color").css("color",G.COLORS.P2),Q("#invalidWrapper").hide(),Q("#arWrapper").hide(),loadAnswers(G.SITE,G.QID,function(e){Q.isArray(e)?(Q("#loadStatus").remove(),loadPlayers(e),newGame()):Q("#loadStatus").text("Error loading entries - "+e)})}function maskedEval(e,t){var r={};for(i in this)r[i]=void 0;for(i in t)t.hasOwnProperty(i)&&(r[i]=t[i]);return new Function("with(this) { "+e+";}").call(r)}function toKey(e,t){return G.W*t+e}function fromKey(e){return{x:e%G.W,y:Math.floor(e/G.W)}}function outOfBounds(e,t){return 0>e||e>=G.W||0>t||t>=G.H}function rnd(e){return Math.floor(Math.random()*e)}function isInt(e){return"number"==typeof e&&e%1===0}function isString(e){return"string"==typeof e||e instanceof String}function decode(e){return Q("<textarea>").html(e).text()}function shuffle(e){for(var t,r,o=e.length;o;t=rnd(o),r=e[--o],e[o]=e[t],e[t]=r);}function makeTable(e){for(var t=Q("<table>"),r=0;r<e.length;r++){for(var o=Q("<tr>"),a=0;a<e[r].length;a++)o.append(Q("<td>").text(e[r][a]));t.append(o)}return t}function toggleDebug(){G.DEBUG=Q("#debug").is(":checked")}function toggleNumbers(){G.SHOW_NUMBERS=Q("#showNumbers").is(":checked"),drawGame(G.GAME)}function toggleLOS(){G.SHOW_LOS=Q("#showLOS").is(":checked"),drawGame(G.GAME)}function closeAutorun(){Q("#arWrapper").hide(),Q("#main").show()}function changeSelect(e){var t=Q(e?"#p1Select":"#p2Select").val(),r=Q(e?"#p1Link":"#p2Link");null===t&&0>t?r.attr("href","javascript:;"):r.attr("href",G.PLAYERS[t].link)}function stopTimer(){"undefined"!=typeof G.TIMER&&clearInterval(G.TIMER)}function moveOnce(){gameOver(G.GAME)||(moveGame(G.GAME),drawGame(G.GAME),gameOver(G.GAME)&&(stopTimer(),Q("#runPause").text("Run").prop("disabled",!0),Q("#moveOnce").prop("disabled",!0),G.DEBUG&&console.log("======== GAME OVER: "+G.GAME.p1.score+" TO "+G.GAME.p2.score+" ========"),alert(gameOverMessage(G.GAME))))}function runPause(){if(G.RUNNING)stopTimer(),Q("#runPause").text("Run"),Q("#moveOnce").prop("disabled",!1);else{var e=parseInt(Q("#delay").val());if(isNaN(e)||0>e)return void alert("Delay must be a non-negative integer.");Q("#runPause").text("Pause"),Q("#moveOnce").prop("disabled",!0),G.TIMER=setInterval(moveOnce,e)}G.RUNNING=!G.RUNNING}function newGame(){stopTimer();var e=G.PLAYERS[Q("#p1Select").val()],t=G.PLAYERS[Q("#p2Select").val()];G.RUNNING=!1,Q("#runPause").text("Run").prop("disabled",!1),Q("#moveOnce").prop("disabled",!1),Q("#p1Title").text(e.title),Q("#p2Title").text(t.title),G.GAME=createGame(e,t),drawGame(G.GAME)}function tryParse(e,t){var r=parseInt(Q(e).val());return!isNaN(r)&&r>=0?r:void alert(t+" must be a non-negative integer.")}function autorun(){function e(){for(var e=new Array(a.length),t={},r=["wins","goals","errors","timeouts","malformed","invalid"],n=0;n<e.length;n++){t.wins=t.ties=t.losses=t.goals=t.errors=t.timeouts=t.malformed=t.invalid=0;for(var l=0;l<e.length;l++)n!==l&&(t.ties+=s[n][l].ties+s[l][n].ties,t.losses+=s[n][l].p2.wins+s[l][n].p1.wins,r.forEach(function(e){t[e]+=s[n][l].p1[e]+s[l][n].p2[e]}));e[n]={wins:t.wins,text:a[n].title+" : "+t.wins+"W, "+t.ties+"T, "+t.losses+"L, "+t.goals+"G, "+t.errors+"E, "+t.timeouts+"I, "+t.malformed+"M, "+t.invalid+"F"}}e=e.sort(function(e,t){return t.wins-e.wins}).map(function(t,r){return r+1+". "+t.text+(r<e.length-1?"<br>":"")});for(var i=new Array(s.length+1),G=0;G<i.length;G++){i[G]=new Array(s.length+1);for(var c=0;c<i.length;c++){var f;i[G][c]=0===c&&0===G?"P2\\P1":0===c?a[G-1].id:0===G?a[c-1].id:(f=s[c-1][G-1])?f.p1.wins+" "+f.ties+" "+f.p2.wins:"-"}}Q("#arPlayers").text(a.length),Q("#arRounds").text(o),Q("#arGpR").text(S/o),Q("#arTotal").text(S),Q("#leaderboard").empty().append(e),Q("#statsTable").empty().append(makeTable(i)),Q("#arInfo").hide(),Q("#arResults").show()}function t(e,t){for(var r=createGame(a[e],a[t]);!gameOver(r);)moveGame(r);r.p1.score>r.p2.score?s[e][t].p1.wins++:r.p1.score<r.p2.score?s[e][t].p2.wins++:s[e][t].ties++,["p1","p2"].forEach(function(o){s[e][t][o].goals+=r[o].score,s[e][t][o].errors+=r[o].stats.errors,s[e][t][o].timeouts+=r[o].stats.timeouts,s[e][t][o].malformed+=r[o].stats.malformed,s[e][t][o].invalid+=r[o].stats.invalid.reduce(function(e,t){return e+t},0)})}function r(){if(c!==f&&(t(c,f),++p<=S&&Q("#arProgress").text(p+"/"+S)),f+1<a.length)f++;else if(f=0,c+1<a.length)c++;else{if(c=0,!(o>i+1))return void e();i++}setTimeout(r,0)}var o=parseInt(Q("#N").val());if(isNaN(o)||1>o)return void alert("N must be a positive integer.");var a=[];Q("#arTestEntry").is(":checked")&&a.push(G.PLAYERS[0]);for(var n=1;n<G.PLAYERS.length;n++)G.PLAYERS[n].dq||a.push(G.PLAYERS[n]);for(var s=new Array(a.length),n=0;n<a.length;n++){s[n]=new Array(a.length);for(var l=0;l<a.length;l++)n!==l&&(s[n][l]={ties:0,p1:{wins:0,goals:0,errors:0,timeouts:0,malformed:0,invalid:0},p2:{wins:0,goals:0,errors:0,timeouts:0,malformed:0,invalid:0}})}var i=0,c=0,f=0,p=1,S=o*a.length*(a.length-1);Q("#arProgress").text("1/"+S),Q("#main").hide(),Q("#arInfo").show(),Q("#arResults").hide(),Q("#arWrapper").show(),setTimeout(r,0)}function gameOver(e){return e.move>=G.TOTAL_MOVES}function gameOverMessage(e){function t(e,t){return"P"+(t?1:2)+": "+e.entry.title+"\nScore: "+e.score+"\nErrors: "+e.stats.errors+"\nTimeouts: "+e.stats.timeouts+"\nMalformed actions: "+e.stats.malformed+"\nFailed actions: ["+e.stats.invalid.toString().replace(/,/g,", ")+"]"}var r="GAME OVER - ";return r+=e.p1.score>e.p2.score?"PLAYER 1 WINS":e.p1.score<e.p2.score?"PLAYER 2 WINS":"TIE GAME",r+="\n\n"+t(e.p1,!0)+"\n\n"+t(e.p2,!1)}function createGame(e,t){function r(e){return{entry:e,bots:new Array(G.BOTS),mem:"",score:0,stats:{errors:0,timeouts:0,malformed:0,invalid:Array.apply(null,new Array(G.BOTS)).map(Number.prototype.valueOf,0)}}}var o={},a=Math.floor(.875*G.H)-1;o.move=0,o.walls=new Array(G.H);for(var n=0;n<G.H;n++){o.walls[n]=new Array(G.W);for(var s=0;s<G.W;s++)o.walls[n][s]=n>a}o.p1=r(e),o.p2=r(t);for(var l=0;l<G.BOTS;l++)o.p1.bots[l]={x:l,y:a,hasWall:!1},o.p2.bots[l]={x:G.W-1-l,y:a,hasWall:!1};if(-1===o.p1.entry.id||-1===o.p2.entry.id){var i=decode(Q("#testEntry").val());-1===o.p1.entry.id&&(o.p1.entry.code=i),-1===o.p2.entry.id&&(o.p2.entry.code=i)}return resetGoal(o),G.DEBUG&&console.log("======== NEW GAME: "+o.p1.entry.title+" VS "+o.p2.entry.title+" ========"),o}function moveGame(e){movePlayer(e,++e.move%2===1),++e.goal.age>=G.GOAL_LIFESPAN&&resetGoal(e)}function setupParams(e,t){function r(e,t){var r=toKey(e,t);if(!n.hasOwnProperty(r)){n[r]=!1;for(var a=0;a<G.BOTS;a++)if(Math.abs(o.bots[a].x-e)<=G.LOS&&Math.abs(o.bots[a].y-t)<=G.LOS){n[r]=!0;break}}return n[r]}var o=t?e.p1:e.p2,a=t?e.p2:e.p1,n={},s={};s.p1=t,s.id=o.entry.id,s.eid=a.entry.id,s.score=o.score,s.escore=a.score,s.move=Math.floor((e.move+1)/2),s.goal={x:e.goal.x,y:e.goal.y},s.getMem=function(){return o.mem},s.setMem=function(e){isString(e)&&e.length<=G.MEM_MAX_LENGTH&&(o.mem=e)},s.grid=function(t,o){return isInt(t)&&isInt(o)&&r(t,o)?outOfBounds(t,o)?0:e.walls[o][t]?1:0:-1},s.bots=new Array(G.BOTS),s.ebots=[];for(var l=0;l<G.BOTS;l++)s.bots[l]={x:o.bots[l].x,y:o.bots[l].y,hasWall:o.bots[l].hasWall},r(a.bots[l].x,a.bots[l].y)&&s.ebots.push({x:a.bots[l].x,y:a.bots[l].y,hasWall:a.bots[l].hasWall});return shuffle(s.ebots),-1===o.entry.id&&(s.console=console),s}function movePlayer(e,t){var r,o,a=t?e.p1:e.p2,n=t?e.p2:e.p1,s=setupParams(e,t);G.DEBUG&&(console.log("######## MOVE "+e.move+" - P"+(t?1:2)+" ########"),console.log("PARAMETERS:"),console.log(s)),o=performance.now();try{r=maskedEval(a.entry.code,s)}catch(n){return a.stats.errors++,void(G.DEBUG&&(console.log("!!!! ERRORED !!!!"),console.log(n)))}if(o=performance.now()-o,G.DEBUG&&console.log("TIME TAKEN: "+o+"ms"),o>G.TIME_LIMIT)return a.stats.timeouts++,void(G.DEBUG&&console.log("!!!! TIMED OUT !!!!"));if(G.DEBUG&&(console.log("ACTIONS:"),console.log(r)),!Array.isArray(r)||r.length!==G.BOTS)return a.stats.malformed++,void(G.DEBUG&&console.log("!!!! MALFORMED ACTIONS !!!!"));for(var l=0;l<G.BOTS;l++)if(!isInt(r[l])||r[l]<0||r[l]>24)return a.stats.malformed++,void(G.DEBUG&&console.log("!!!! MALFORMED ACTIONS !!!!"));performActions(e,a,r)}function performActions(e,t,r){function o(e){t.stats.invalid[e]++,G.DEBUG&&console.log("!! BOT"+e+" ACTION FAILED !!")}function a(e){return e.x!==i||e.y!==c}for(var n=!1,s=0;s<G.BOTS;s++){var l=r[s];if(l){var i,c;switch((l-1)%8){case 0:i=-1,c=-1;break;case 1:i=0,c=-1;break;case 2:i=1,c=-1;break;case 3:i=-1,c=0;break;case 4:i=1,c=0;break;case 5:i=-1,c=1;break;case 6:i=0,c=1;break;case 7:i=1,c=1}if(i+=t.bots[s].x,c+=t.bots[s].y,outOfBounds(i,c))o(s);else switch(Math.floor((l-1)/8)){case 0:!e.walls[c][i]&&(i>0&&c>0&&e.walls[c-1][i-1]||c>0&&e.walls[c-1][i]||i<G.W-1&&c>0&&e.walls[c-1][i+1]||i>0&&e.walls[c][i-1]||i<G.W-1&&e.walls[c][i+1]||i>0&&c<G.H-1&&e.walls[c+1][i-1]||c<G.H-1&&e.walls[c+1][i]||i<G.W-1&&c<G.H-1&&e.walls[c+1][i+1])?(t.bots[s].x=i,t.bots[s].y=c,i!==e.goal.x||c!==e.goal.y||n||(n=!0,G.DEBUG&&console.log("** BOT"+s+" REACHED GOAL **"))):o(s);break;case 1:e.walls[c][i]&&!t.bots[s].hasWall?(e.walls[c][i]=!1,t.bots[s].hasWall=!0):o(s);break;case 2:!e.walls[c][i]&&t.bots[s].hasWall&&e.p1.bots.every(a)&&e.p2.bots.every(a)?(e.walls[c][i]=!0,t.bots[s].hasWall=!1):o(s)}}}n&&(t.score++,resetGoal(e)),G.DEBUG&&(console.log("FINAL PLAYER STATE:"),console.log(t))}function resetGoal(e){for(var t={},r=[],o=0;o<G.BOTS;o++)t[toKey(e.p1.bots[o].x,e.p1.bots[o].y)]=!0,t[toKey(e.p2.bots[o].x,e.p2.bots[o].y)]=!0;for(var a=0;a<G.H;a++)for(var n=0;n<G.W;n++){var s=toKey(n,a);t.hasOwnProperty(s)||r.push(s)}var l=fromKey(r[rnd(r.length)]);e.goal={age:0,x:l.x,y:l.y}}function drawGame(e){function t(e,t){G.CTX.fillRect(e*G.SCALE,t*G.SCALE,G.SCALE,G.SCALE)}function r(e,t){G.CTX.fillRect(e*G.SCALE+1,t*G.SCALE+1,G.SCALE-2,G.SCALE-2)}G.CTX.fillStyle=G.COLORS.AIR,G.CTX.fillRect(0,0,G.CW,G.CH),G.CTX.fillStyle=G.COLORS.WALL;for(var o=0;o<G.H;o++)for(var a=0;a<G.W;a++)e.walls[o][a]&&t(a,o);if(G.SHOW_LOS){var n=(2*G.LOS+1)*G.SCALE;G.CTX.fillStyle=G.COLORS.P1_LOS;for(var s=0;s<G.BOTS;s++)G.CTX.fillRect((e.p1.bots[s].x-G.LOS)*G.SCALE,(e.p1.bots[s].y-G.LOS)*G.SCALE,n,n);G.CTX.fillStyle=G.COLORS.P2_LOS;for(var s=0;s<G.BOTS;s++)G.CTX.fillRect((e.p2.bots[s].x-G.LOS)*G.SCALE,(e.p2.bots[s].y-G.LOS)*G.SCALE,n,n)}G.CTX.fillStyle=G.COLORS.P1;for(var s=0;s<G.BOTS;s++)t(e.p1.bots[s].x,e.p1.bots[s].y);G.CTX.fillStyle=G.COLORS.P2;for(var s=0;s<G.BOTS;s++)t(e.p2.bots[s].x,e.p2.bots[s].y);G.CTX.fillStyle=G.COLORS.WALL;for(var s=0;s<G.BOTS;s++)e.p1.bots[s].hasWall&&r(e.p1.bots[s].x,e.p1.bots[s].y),e.p2.bots[s].hasWall&&r(e.p2.bots[s].x,e.p2.bots[s].y);if(G.SHOW_NUMBERS){var l=-.1,i=2.75;G.CTX.fillStyle=G.COLORS.P1_TEXT;for(var s=0;s<G.BOTS;s++)G.CTX.fillText(s.toString(),(e.p1.bots[s].x+l)*G.SCALE,(e.p1.bots[s].y+i)*G.SCALE);G.CTX.fillStyle=G.COLORS.P2_TEXT;for(var s=0;s<G.BOTS;s++)G.CTX.fillText(s.toString(),(e.p2.bots[s].x+l)*G.SCALE,(e.p2.bots[s].y+i)*G.SCALE)}G.CTX.fillStyle=G.COLORS.GOAL,t(e.goal.x+1,e.goal.y),t(e.goal.x-1,e.goal.y),t(e.goal.x,e.goal.y+1),t(e.goal.x,e.goal.y-1),G.SCOREBOARD.P1SCORE.text(e.p1.score),G.SCOREBOARD.MOVE.text(e.move),G.SCOREBOARD.P2SCORE.text(e.p2.score)}function loadPlayers(e){var t=/<pre\b[^>]*><code\b[^>]*>([\s\S]*?)<\/code><\/pre>/,r=/<h1\b[^>]*>(.*?)<\/h1>/;G.PLAYERS=[];var o={id:-1,dq:!1,code:void 0,link:"javascript:;",title:"TEST ENTRY [-1]"};G.PLAYERS.push(o);var a=[];e.forEach(function(e){var o=decode(e.owner.display_name),n=t.exec(e.body),s=r.exec(e.body);if(null===n||n.length<=1||null===s||s.length<=1)return a.push(" "),void a.push(Q("<a>").text(o).attr("href",e.link));var l={};l.id=e.answer_id,l.dq=G.DQ_ANSWERS.indexOf(e.answer_id)>-1||G.DQ_USERS.indexOf(e.owner.user_id)>-1,l.code=decode(n[1]),l.link=e.link,l.title=s[1].substring(0,20)+" - "+o+" ["+l.id.toString()+"]",l.dq&&(l.title+="[DQ]"),G.PLAYERS.push(l)}),a.length>0&&(Q("#invalid").empty().append(a),Q("#invalidWrapper").show());for(var n=new Array(G.PLAYERS.length),s=new Array(G.PLAYERS.length),l=0;l<G.PLAYERS.length;l++)n[l]=Q("<option>").text(G.PLAYERS[l].title).val(l),s[l]=Q("<option>").text(G.PLAYERS[l].title).val(l);Q("#p1Select").empty().append(n).val(rnd(G.PLAYERS.length)),changeSelect(!0),Q("#p2Select").empty().append(s).val(rnd(G.PLAYERS.length)),changeSelect(!1)}function loadAnswers(e,t,r){function o(){Q.get("https://api.stackexchange.com/2.2/questions/"+t.toString()+"/answers?page="+(s++).toString()+"&pagesize=100&order=asc&sort=creation&site="+e+"&filter=!YOKGPOBC5Yad4mOOn8Z4WcAE6q",a)}function a(e){e.hasOwnProperty("error_id")?r(e.error_id.toString()):(n=n.concat(e.items),e.hasMore?o():r(n))}var n=[],s=1;o(s,a)}Q=jQuery,Q(reload);</script>
Diese Frage hat einen eigenen Chatroom. Ich werde dort alle paar Tage Bestenlisten veröffentlichen.