Block Building Bot Flocks!


42

Il concorso è finito!

Intro

Questo è un contest interattivo cui il controller è completamente contenuto in un frammento di stack nella parte inferiore della domanda. Il controller legge automaticamente le risposte e gioca attraverso i giochi. Chiunque può eseguirlo in qualsiasi momento direttamente nel proprio browser.

Le meccaniche di questo concorso sono molto simili a quelle di Red vs. Blue - Pixel Team Battlebots . Tranne che il gioco che si sta giocando, mentre è ancora basato sulla griglia, è completamente diverso. Ogni partita è 1 contro 1 e non ci sono squadre. Ogni voce è in lotta per se stessa e solo una sarà il campione finale.

Il controller utilizza JavaScript e poiché JavaScript è l'unico linguaggio di scripting lato client supportato dalla maggior parte dei browser, anche tutte le risposte devono essere scritte in JavaScript .

In questa specifica, il testo in corsivo viene utilizzato per indicare il termine formale per un meccanico o una proprietà di gioco. Questi termini sono usati ovunque per aiutare a mantenere un modo chiaro e coerente di riferirsi alle diverse parti del gioco.

gameplay

Nozioni di base

Ogni risposta a questa domanda rappresenta un giocatore . Una partita è una competizione tra due giocatori, P1 e P2 . Ogni giocatore controlla uno stormo di 8 robot , numerati da 0 a 7. I giochi si svolgono nella griglia , un'arena di celle 128 × 64 le cui 8 file inferiori iniziano come muri (i "blocchi") e altre file iniziano come aria . Le celle al di fuori dei limiti della griglia sono considerate aria.

La coordinata x della griglia varia da 0 a sinistra a 127 a destra e y varia da 0 in alto a 63 in basso.

Esempio di griglia iniziale:

I robot rimangono sempre allineati alle celle della griglia e più robot possono occupare la stessa cella. I robot possono occupare solo celle d'aria. I robot di P1 iniziano sempre in una riga 0-7 alla sinistra della riga sopra le pareti e i robot di P2 iniziano sempre in una riga 7-0 all'estrema destra.

I vicini di un robot o cella sono le 8 celle direttamente ortogonali e diagonali ad esso.

Il campo visivo ( FOV ) di un bot è il quadrato di cella 13 × 13 centrato su un bot. Si dice che una cellula o un robot nemico si trovi nel FOV di un giocatore se si trova nel FOV di almeno uno dei robot del giocatore.

Mosse e azioni

Durante una partita, ogni giocatore può muoversi 1000 volte. P1 si sposta prima, poi P2, poi P1 e così via fino a quando non sono state effettuate 2000 mosse totali, a quel punto il gioco termina.

Durante una mossa, ogni giocatore riceve informazioni sullo stato del gioco e sulle celle della griglia e sui robot nemici nel proprio FOV, e lo usa per decidere un'azione da eseguire per ciascuno dei suoi robot.

L'azione predefinita è non fare nulla , in cui il bot non si sposta o interagisce con la griglia.

Le altre azioni sono spostare , afferrare e posizionare :

  • Un bot può spostarsi in una delle celle adiacenti C se:

    • C non è fuori limite,
    • C è aria (cioè non un muro),
    • e almeno uno dei vicini di C è un muro.

    In caso di successo, il bot passerà a C.

  • Un bot può prendere una delle sue celle vicine C se:

    • C non è fuori limite,
    • C è un muro,
    • e il bot non sta già portando un muro.

    In caso di successo, C diventerà aria e il robot ora trasporterà un muro.

  • Un bot può posizionarsi su una delle sue celle vicine C se:

    • C non è fuori limite,
    • C è aria,
    • nessun robot di entrambi i giocatori occupa C,
    • e il robot porta un muro.

    In caso di successo, C diventerà un muro e il bot non trasporterà più un muro.

Le azioni non riuscite si traducono in non fare nulla.

Una cella occupata da almeno un robot che trasporta pareti ha un piccolo quadrato colorato a parete disegnato sopra di esso. I robot iniziano senza muri.

Memoria

Durante una mossa, un giocatore può accedere e modificare la propria memoria , una stringa inizialmente vuota che dura per tutto il gioco e può essere utilizzata per memorizzare dati strategici.

Obbiettivo

La cella nel mirino giallo è l' obiettivo , che inizia in una posizione casuale. Ogni giocatore ha un punteggio che inizia da 0. Quando il robot di un giocatore si sposta in porta, il punteggio di quel giocatore aumenta di 1 e l'obiettivo viene riposizionato casualmente prima del turno successivo. Vince il giocatore con il punteggio più alto alla fine di una partita. È un pareggio se i punteggi sono uguali.

Se più robot si muovono verso l'obiettivo durante una mossa, il giocatore ottiene ancora solo un punto.

Se l'obiettivo è stato nello stesso posto per 500 mosse, viene riposizionato di nuovo a caso. Ogni volta che l'obiettivo viene posizionato in modo casuale, è garantito che non venga posizionato su una cella occupata da un bot.

Cosa programmare

Scrivi un corpo per questa funzione:

function myMove(p1, id, eid, move, goal, grid, bots, ebots, getMem, setMem) {
    //body goes here
}

Verrà chiamato una volta ogni volta che il tuo giocatore si muove e deve restituire le azioni che vuoi che ciascuno dei tuoi robot effettui durante quella mossa.

È possibile utilizzare il codice di base come punto di partenza.

parametri

  • p1è un bool che è truese sei P1 e falsese sei P2
  • id è un numero intero che è l'ID di risposta della tua risposta.
    • Puoi trovare l'ID di una risposta facendo clic sul link "condividi" sotto di esso e cercando il numero subito dopo a/nell'URL.
    • L'ID della voce di prova è -1.
  • eid è un numero intero che è l'ID di risposta della risposta del tuo nemico.
  • move è un numero intero compreso tra 1 e 1000 che indica la mossa in cui ti trovi.
  • goalè un oggetto con xe yproprietà. Queste sono le coordinate dell'obiettivo. Vengono dati anche se l'obiettivo è fuori dal tuo FOV.
  • gridè una funzione che accetta argomenti xey, ad es grid(x,y). Restituisce:
    • -1per "sconosciuto" se gli argomenti non sono due numeri interi o se x,ynon si trova nel tuo FOV.
    • 0per "aria" se x,yè fuori limite o se la cella x,yè in aria.
    • 1per "muro" se la cella in x,yè un muro.
  • botsè un array dei tuoi 8 robot. I suoi elementi sono oggetti con proprietà x, ye hasWall:

    • xe ysono le coordinate del bot.
    • hasWallè truese il robot trasporta un muro e in falsecaso contrario.

    bots viene sempre ordinato normalmente, l'ennesimo indice corrisponde al numero di bot N.

  • ebotsè un array di oggetti con x, ye hasWallproprietà come bots. Ci sono solo i robot nemici nel tuo FOV ebots. Quindi avrebbe lunghezza 0 se non ci sono robot nemici nel tuo FOV. Viene ordinato in modo casuale.
  • getMem è una funzione senza argomenti che restituisce la tua memoria.
  • setMem è una funzione che accetta un argomento M. Se M è una stringa di 256 caratteri o meno, la memoria viene aggiornata a M, altrimenti non accade nulla.

L' consoleoggetto browser è disponibile solo per la voce Test.

Valore di ritorno

La tua funzione deve restituire un array di esattamente 8 numeri interi, ciascuno compreso tra 0 e 24. Il valore all'indice N è l'azione che il numero di bot N intraprenderà.

Tutti i tuoi robot non faranno nulla se la tua funzione:

  • Genera un errore di qualsiasi tipo. ( errore )
  • Richiede più di 20 millisecondi per l'esecuzione. ( timeout )
  • Non restituisce un array di 8 numeri interi compresi tra 0 e 24. (non valido )

Per comodità, il numero di errori, timeout e azioni non valide vengono visualizzati al termine della partita.

Ognuno dei numeri da 0 a 24 corrisponde a una particolare azione bot:

  • 0 è per non fare nulla.
  • 1-8 sono per lo spostamento.
  • 9-16 sono per afferrare.
  • 17-24 sono per il posizionamento.

Ognuno degli 8 valori per spostare, afferrare e posizionare corrisponde a una delle celle adiacenti del bot, come mostrato qui:

Quindi, ad esempio, 15è l'azione per afferrare la cella sotto il bot.

Le azioni del bot vengono gestite nell'ordine da bot 0 a bot 7. Ad esempio, se durante uno spostamento viene detto a bot 0 di posizionare una parete nella stessa cella d'aria a cui è stato detto di spostare 1 bot, la cella d'aria diventerà una parete prima del bot L'azione di 1 viene gestita e il bot 1 non avrà esito positivo.

Le azioni infruttuose non fanno nulla e si dice che abbiano fallito . I segnalini azione falliti vengono visualizzati anche al termine del gioco.

Regole

Potrei squalificare temporaneamente o permanentemente gli utenti o le risposte che non seguono queste regole. Le iscrizioni squalificate non sono idonee a vincere.

  • Quando si dichiarano variabili o funzioni, è necessario utilizzare la varparola chiave.
    ad es. var x = 10o var sum = function(a, b){ return a + b }
    Le cose dichiarate senza vardiventare globali e potrebbero interferire con il controller. Sono stati fatti dei passi affinché questa interferenza sia impossibile, ma farlo per assicurarsi.

  • Il tuo codice non dovrebbe funzionare lentamente o perdere tempo.
    È impossibile interrompere le funzioni JavaScript durante l'esecuzione, quindi il codice di ciascun giocatore viene eseguito fino al completamento. Se l'esecuzione del codice richiede molto tempo, tutti coloro che eseguono il tuo lettore noteranno e saranno infastiditi. Idealmente, le voci funzioneranno sempre bene entro il limite di 20ms.

  • È necessario utilizzare il codice compatibile con ECMAScript 5 nell'ultima versione di Firefox poiché è qui che lo eseguirò. Non utilizzare le funzionalità di ECMAScript 6 in quanto non è ancora supportato in molti browser.
  • Puoi rispondere fino a 3 volte, ma solo se ciascuna delle tue strategie è notevolmente diversa. Puoi modificare le risposte quanto desideri.
  • Non puoi tentare di avere alcun tipo di memoria se non attraverso l'uso di getMeme setMem.
  • Non puoi tentare di accedere o modificare il controller, il codice di altri giocatori o risorse esterne.
  • Non puoi tentare di modificare nulla incorporato in JavaScript.
  • Le risposte non devono essere deterministiche. Puoi usare Math.random.

Formato di risposta

#EntryName

Notes, etc.

<!-- language: lang-js -->

    //function body
    //probably on multiple lines

More notes, etc.

Il primo blocco di codice multilinea deve contenere il corpo della funzione.
Il nome della voce è limitato a 20 caratteri.

La tua voce apparirà nel controller con il titolo EntryName - Username [answer ID], più [DQ]se è squalificata.

vincente

Quando la domanda è stata sollevata per almeno 3 settimane e una volta che la risposta si è risolta, incoronerò il campione.

Userò la funzione di esecuzione automatica del controller . In un round di esecuzione automatica, ogni giocatore non squalificato gioca due partite l'una con l'altra, una come P1, una come P2 (un doppio round robin).

Eseguirò il maggior numero di colpi possibile nel giro di poche ore. Questo dipenderà da quanti invii ci saranno e da quanto tempo impiegheranno. Ma state tranquilli, mi impegno a ottenere una classifica finale accurata. Il giocatore con più vittorie è il campione e la sua risposta sarà accettata.

Userò Firefox su un laptop con Windows 8.1 a 64 bit, 4 GB di RAM e un processore quad-core da 1,6 GHz.

Premio

Scriverò e pubblicherò una sfida PPCG specificamente dedicata al campione. In qualche modo coinvolgerà il loro nome utente o avatar o qualcosa su di loro. Deciderò privatamente su quale sarà la sfida al termine di questo concorso. Lo scriverò al meglio delle mie possibilità e cercherò di farlo diventare una domanda di rete calda.

controllore

Esegui questo snippet o vai a questo JSFiddle per utilizzare il controller. Si inizia con giocatori casuali selezionati. L'ho provato a fondo solo su Firefox e Chrome.

<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>&nbsp;<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&nbsp;=&nbsp;<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>&nbsp;| 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>&nbsp;| 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>&nbsp; <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>

Questa domanda ha una sua chatroom. Pubblicherò le classifiche lì ogni pochi giorni.



3
Grazie ai pulsanti per regolare le dimensioni della griglia, posso eseguire lo Stack Snippet sul mio telefono :)
trichoplax,

3
Tanto amore (codegolf.stackexchange.com/questions/50768/) ma non è facile
edc65

3
Questo è affascinante da guardare.
DLosc,

1
@Stephen Sì. Punto 4 della regola: "Puoi modificare le risposte quanto desideri."
Calvin's Hobbies,

Risposte:


13

Cavaliere Nero

Il nome del bot deriva da un piano iniziale per poterlo muovere come un cavaliere di scacchi: più di due, uno, ecc., Che in alcuni casi sarebbe più veloce.

var moves = new Array(8),
    mem = getMem(), newMem = '';

var decodeMem = function(){
  //mmtxy
  for(var ind = 0; ind < 8; ind++){
    var sub = mem.substr(ind * 5, 5)
    bots[ind].lastMove = parseInt(sub[0], 36);
    bots[ind].last2Move = parseInt(sub[1], 36);
    bots[ind].timesStill = sub.charCodeAt(2) - 48;
    bots[ind].lastX = sub.charCodeAt(3) - 187;
    bots[ind].lastY = sub.charCodeAt(4) - 187;
  }
}
decodeMem();

var distanceTo = function(fromX, fromY, toX, toY){
  // Chebyshev distance
  return Math.max(Math.abs(fromX - toX),
                  Math.abs(fromY - toY));
}

var direction = function(from, to){ // Math.sign()
  var diff = to - from;
  return diff > 0 ? 1 : (diff < 0 ? -1 : 0);
}

var dirs = [
  [1, 2, 3],
  [4, 0, 5],
  [6, 7, 8]
];

var moveTo = function(from, to){
  var prioritiesWall = [
    [0],
    [1, 2, 4, 17, 18, 20, 19, 22, 23, 21, 3, 6, 5, 7, 24, 8],
    [2, 3, 1, 17, 19, 18, 23, 22, 24, 4, 5, 20, 21, 6, 8, 7],
    [3, 2, 5, 19, 18, 21, 17, 24, 23, 20, 1, 8, 4, 7, 22, 6],
    [4, 1, 6, 22, 17, 20, 21, 24, 19, 2, 7, 18, 23, 3, 8, 5],
    [5, 3, 8, 24, 19, 21, 20, 22, 17, 2, 7, 18, 23, 1, 6, 4],
    [6, 4, 7, 22, 20, 23, 17, 24, 18, 21, 1, 8, 2, 5, 19, 3],
    [7, 8, 6, 22, 24, 23, 18, 17, 19, 4, 5, 20, 21, 1, 3, 2],
    [8, 5, 7, 24, 21, 23, 19, 22, 18, 20, 3, 6, 2, 4, 17, 1]
  ];
  var prioritiesNoWall = [
    [9, 10, 11, 12, 13, 14, 15, 16, 0],
    [1, 2, 4, 9, 16, 10, 12, 3, 6, 11, 14, 5, 7, 13, 15, 8],
    [2, 3, 1, 10, 15, 14, 16, 4, 5, 12, 13, 9, 11, 6, 8, 7],
    [3, 2, 5, 11, 14, 10, 13, 1, 8, 9, 16, 4, 7, 12, 15, 6],
    [4, 1, 6, 12, 13, 16, 11, 2, 7, 10, 15, 9, 14, 3, 8, 5],
    [5, 3, 8, 13, 12, 14, 9, 2, 7, 10, 15, 11, 16, 1, 6, 4],
    [6, 4, 7, 14, 11, 12, 15, 1, 8, 9, 16, 2, 5, 10, 13, 3],
    [7, 8, 6, 15, 10, 9, 11, 4, 5, 12, 13, 14, 16, 1, 3, 2],
    [8, 5, 7, 16, 9, 13, 15, 3, 6, 11, 14, 2, 4, 10, 12, 1]
  ];

  var dir = dirs[direction(from.y, to.y) + 1][direction(from.x, to.x) + 1],
      method = from.hasWall ? prioritiesWall[dir] : prioritiesNoWall[dir];

  if(distanceTo(from.x, from.y, goal.x, goal.y) === 1){
    method.splice(1,2);
  }

  for(var i=0; i<method.length; i++){
    var attempt = method[i];
    if(checkMove(from, attempt)) return attempt;
  }
  return 0;
}

var numWalls = function(x, y, indexes){
  var allCoords = [
    [x - 1, y - 1],
    [x,     y - 1],
    [x + 1, y - 1],
    [x - 1, y    ],
    [x + 1, y    ],
    [x - 1, y + 1],
    [x,     y + 1],
    [x + 1, y + 1],
  ];
  var allTypes = allCoords.map(function(e){
    return grid(e[0], e[1]); // air = 0, wall = 1
  });
  var justWalls = allTypes.filter(function(e){
    return e === 1;
  }).length;

  return indexes ? allTypes : justWalls;
}

var checkMove = function(coords, moveCode){
  var x = coords.x, y = coords.y,
      baseX = [0, -1, 0, 1, -1, 1, -1, 0, 1],
      baseY = [0, -1, -1, -1, 0, 0, 1, 1, 1],
      targetX = x + baseX[(moveCode - 1) % 8 + 1],
      targetY = y + baseY[(moveCode - 1) % 8 + 1];

  if((targetX > 127 || targetX < 0 || targetY > 63 || targetY < 0) || // Don't bother if it's out of bounds
     (coords.timesStill > 2 && x == coords.lastX && y == coords.lastY && (moveCode == coords.lastMove || moveCode == coords.last2Move)))
    // Or is doing the same moves and not moving
    return false;

  var targetGrid = grid(targetX, targetY), enemyNear = false, couldStrandEnemy = false,
      eWallDirMove, hasNeighbor = numWalls(targetX, targetY) > 0;

  ebots.forEach(function(ebot){
    // Don't place a wall where an enemy can take it
    if(distanceTo(targetX, targetY, ebot.x, ebot.y) === 1 && !ebot.hasWall && (y != ebot.y || x != ebot.x))
      enemyNear = true;

    // Don't move if you can strand an enemy
    var eWallDir = numWalls(ebot.x, ebot.y, true).indexOf(1) + 1,
        wallX = ebot.x + baseX[eWallDir], wallY = ebot.y + baseY[eWallDir];

    if(!coords.hasWall && numWalls(ebot.x, ebot.y) === 1 &&
       distanceTo(x, y, wallX, wallY) === 1){
      eWallDirMove = dirs[direction(y, wallY) + 1][direction(x, wallX) + 1] + 8;
      couldStrandEnemy = true;
    }
  })

  if(targetX == goal.x && targetY == goal.y && targetGrid === 0){
    targetGrid = 2 // Don't place a wall in the goal
  } else {
    ebots.concat(bots).forEach(function(bot){
      // Ensure target cell doesn't have a bot in it
      if(bot.x == targetX && bot.y == targetY) targetGrid = 2;
    });
  }

  return ((moveCode < 9 && targetGrid !== 1 && hasNeighbor && !couldStrandEnemy) || // Move
          (moveCode > 8 && moveCode < 17 && targetGrid === 1 && !coords.hasWall && (!couldStrandEnemy || (couldStrandEnemy && eWallDirMove == moveCode))) || // Grab
          (moveCode > 16 && targetGrid === 0 && coords.hasWall && !enemyNear)) // Place
}

var goalClosest = {dist: Infinity}, rescuers = {};
bots.forEach(function(bot, index){

  // Check if bot is stranded
  bot.stranded = false;
  if(numWalls(bot.x, bot.y) / 8 == bot.hasWall){
    bot.stranded = true;
    rescuers[index] = -1;
  }
});

bots.forEach(function(bot, index){
  if(!bot.stranded){
    // Find which bot is closest to the goal
    var goalDist = distanceTo(bot.x, bot.y, goal.x, goal.y);

    if(goalDist < goalClosest.dist){
      goalClosest.dist = goalDist;
      goalClosest.index = index;
    }
  }
});

bots.forEach(function(bot, index){
  var destination = {
    x: 14 + (index % 4) * 32 + 3 * (index > 3),
    y: index > 3 ? 55 : 27
  }
  if(index == goalClosest.index){
    destination = goal;
  }

  moves[index] = moveTo(bot, destination);

  if(moves[index] == bot.lastMove || moves[index] == bot.last2Move) bot.timesStill++;

  newMem += moves[index].toString(36) +
    bot.lastMove.toString(36) +
    String.fromCharCode(bot.timesStill + 48) +
    String.fromCharCode(bot.x + 187) +
    String.fromCharCode(bot.y + 187);
});

setMem(newMem);

return moves;

Spiegazione

Determinare quale mossa fare per ciascun bot può essere suddivisa in due compiti principali: capire dove andare e come arrivarci.

Dove andare

Il compito di base di capire dove andare è facile: vai verso l'obiettivo se sei il più vicino o cerca di posizionarti il ​​più lontano possibile dai compagni di squadra. Passa prima attraverso ogni bot e determina se è bloccato (cioè non ha blocchi che lo circondano e non tiene in mano un muro, oppure è circondato da muri e contiene un muro). Quindi passa nuovamente in rassegna i robot per trovare il robot senza trefoli più vicino all'obiettivo. Tutti gli altri robot si fanno strada verso l'essere distanziati, con la fila inferiore sulla superficie dei blocchi ( y=55) e la fila superiore su y=27. Una volta che sa dove andare, lo passa alla moveTofunzione.

Come arrivare là

Decidere come arrivare a destinazione è molto più difficile perché i robot devono essere sempre adiacenti a un muro per muoversi. Per prima cosa capisce il codice di direzione (1–8) della destinazione rispetto alla sua posizione attuale. Ad esempio, se un bot si trovasse nell'angolo in basso a sinistra e volesse andare in alto a destra, userebbe il codice di direzione 3. Per ogni direzione, ho codificato un elenco di mosse, con il primo come l'ideale, in alto mossa -priority e l'ultima è l'ultima risorsa. Questo è separato dal fatto che il bot abbia o meno un muro, perché non è possibile utilizzare una mossa di luogo senza un muro o usare una mossa di presa mentre si ha già un muro.

Ovviamente, usare la mossa ideale non sempre funziona e si tradurrebbe in molte azioni fallite. È qui che checkMoveentra in gioco. Questa funzione controlla la potenziale mossa rispetto ad ogni requisito, per impedire al bot di spostarsi oltre i limiti o in un muro, ad esempio. Se un bot nemico vicino può essere bloccato (ha solo un muro adiacente che può essere preso dal bot), questa diventa la sua priorità, quindi la funzione tornerà falseper una mossa altrimenti legittima in modo da poter saltare alle mosse afferrare ed eliminare il nemico. La funzione impedisce diverse altre mosse stupide come posizionare un muro in porta o un altro robot.

La stringa di memoria

A volte il robot non sarà effettivamente bloccato, ma continuerà a provare la stessa mossa e non finirà per muoversi (di solito raccogliendo un muro e posandolo, raccogliendolo e posandolo, ecc.). Per evitarlo, usa la stringa di memoria per ricordare le sue ultime due mosse, le sue ultime posizioni xey, e quante volte è stata ferma. Ogni dato è codificato come un singolo carattere per una facile divisione. (La stringa deve contenere 256 caratteri , non byte, quindi l'utilizzo di caratteri Unicode multibyte non è un problema, come lo è con le tipiche sfide del golf.)

Ad esempio, supponiamo che un robot abbia afferrato il muro alla sua sinistra (codice 12) in questa svolta, lo abbia sostituito alla sua sinistra (codice 20) nella sua svolta precedente, ed è stato alle coordinate ( 107, 3) per le 16svolte precedenti . La stringa di memoria per questa istanza verrebbe codificata come segue:

  • ck: Gli ultimi due codici azione vengono convertiti in base36 per trasformare i numeri a due cifre in una singola lettera.
  • @: Il numero di volte in cui è stato ancora rappresentato come carattere ASCII con quel codice + 48 per saltare i caratteri non stampabili e quindi le prime nove volte mostrano ancora il numero effettivo ( String.fromCharCode(0 + 48)0).
  • Ħ¾: Le coordinate xey sono anche rappresentate come il carattere con quel valore, questa volta compensato dal valore alquanto arbitrario di 187 per evitare caratteri problematici.

Una tipica stringa di memoria durante il gioco potrebbe essere 53äÇØb7¼ðÌ00ßĉÖ7m±ĪÚ00ĝÌò00Ĝìò00ĖČò00ĈĬò, con un gruppo di cinque personaggi per ciascuno degli otto robot.


1
Se un giocatore è in una partita contro se stesso, allora il Giocatore 1 o il Giocatore 2 possono vincere, senza apparente pregiudizio. Questa risposta è un'eccezione, poiché il Giocatore 1 vince quasi sempre con un ampio margine. Non riesco a vedere un motivo per cui - è intrigante.
trichoplax,

@trichoplax Immagino sia perché P1 si sposta prima di P2, quindi P1 si incaglia P2 prima di poter fare lo stesso.
NinjaBearMonkey

4
La sfida è finita e i risultati sono arrivati ! Dopo 30 round, Black Knight ha ottenuto 204 vittorie e il successivo miglior candidato , Seekers , ha avuto solo 147. Congratulazioni NinjaBearMonkey ! La tua sfida specifica è in arrivo.
Calvin's Hobbies,

Assolutamente ninja! Grazie
edc65,

12

avamposti

Gli 8 robot prendono ciascuno un quadrato di 32 per 32 e corrono verso il centro di esso (io compenso leggermente i centri altrimenti finiscono per accoppiarsi e viaggiare verticalmente con un blocco di mura tra loro, quindi uno di loro si blocca).

Ogni bot rimarrà al centro del suo quadrato a meno che l'obiettivo non sia all'interno di 32 celle del suo rispettivo centro, nel qual caso correrà verso l'obiettivo e poi tornerà al suo centro.

Questo utilizza ancora il metodo Baseline per raggiungere il suo obiettivo (obiettivo o centro), quindi non si muove in diagonale. Solo un punto di partenza ...

var encodeAction = function(type, dx, dy) {
    var d
    if (dx === -1 && dy === -1) d = 1
    else if (dx === 0 && dy === -1) d = 2
    else if (dx === 1 && dy === -1) d = 3
    else if (dx === -1 && dy === 0) d = 4
    else if (dx === 1 && dy === 0) d = 5
    else if (dx === -1 && dy === 1) d = 6
    else if (dx === 0 && dy === 1) d = 7
    else if (dx === 1 && dy === 1) d = 8
    else return 0
    return 8 * type + d
}

var getNeighborCell = function(x, y, wallState) {
    if (x > 0 && y > 0 && grid(x - 1, y - 1) === wallState) return { x: x - 1, y: y - 1 }
    if (y > 0 && grid(x, y - 1) === wallState) return { x: x, y: y - 1 }
    if (x < 127 && y > 0 && grid(x + 1, y - 1) === wallState) return { x: x + 1, y: y - 1 }
    if (x > 0 && grid(x - 1, y) === wallState) return { x: x - 1, y: y }
    if (x < 127 && grid(x + 1, y) === wallState) return { x: x + 1, y: y }
    if (x > 0 && y < 63 && grid(x - 1, y + 1) === wallState) return { x: x - 1, y: y + 1 }
    if (y < 63 && grid(x, y + 1) === wallState) return { x: x, y: y + 1 }
    if (x < 127 && y < 63 && grid(x + 1, y + 1) === wallState) return { x: x + 1, y: y + 1 }
    return null
}

var moveBot = function(n) {
    var assignedX = (n % 4) * 32 + 14 + Math.floor(n/4) * 4
    var assignedY = (Math.floor(n / 4)) * 32 + 16
    if (Math.abs(goal.x - assignedX) < 33 && Math.abs(goal.y - assignedY) < 33) {
        assignedX = goal.x
        assignedY = goal.y
    }
    var b = bots[n], moveX = b.x !== assignedX, x = b.x, y = b.y, type
    if (moveX) {
        x += b.x < assignedX ? 1 : -1
    } else {
        y += b.y < assignedY ? 1 : -1
    }
    if (grid(x, y) === 1) {
        if (b.hasWall) {
            type = 2 //place
            var c = getNeighborCell(b.x, b.y, 0)
            if (!c) { //stuck holding wall with walls all around
                return 0
            }
            x = c.x
            y = c.y
        } else {
            type = 1 //grab
        }
    } else if (grid(x, y) === 0) {
        if (getNeighborCell(x, y, 1)) {
            type = 0 //move
        } else {
            if (b.hasWall) {
                type = 2 //place
                if (moveX) {
                    y += y > 0 ? -1 : 1
                } else {
                    x += x > 0 ? -1 : 1
                }
            } else {
                type = 1 //grab
                var c = getNeighborCell(b.x, b.y, 1)
                if (!c) { //stuck without wall in midair
                    return 0
                }
                x = c.x
                y = c.y
            }
        }
    } else {
        return 0 //should never get here
    }
    return encodeAction(type, x - b.x, y - b.y)
}

var actions = []
for (var i = 0; i < 8; i++) {
    actions[i] = moveBot(i)
}

return actions

1
So che questo è solo l'inizio, ma una cosa che ho notato mentre guardavo la (irregolare) battaglia con la linea di base: se l'obiettivo è alla portata di più centri, corrono tutti verso l'obiettivo. Potrebbe essere meglio scegliere solo quello più vicino e mantenere gli altri nella loro posizione "ideale"? Divertente da guardare, a proposito.
Reto Koradi,

Grazie! Sì, sarebbe sicuramente un miglioramento. C'è anche un lungo elenco di altri a cui pensare e una varietà di strategie diverse da usare. Non vedo l'ora di vedere quali strategie scelgono gli altri e come interagiscono ...
trichoplax,

9

Baseline

Questo è il controller flocc bot più semplice e perfettamente funzionante a cui potrei pensare. Sarà la mia unica risposta non squalificata e servirà da base per giudicare altre risposte. È tecnicamente in corsa per vincere il concorso, ma batterlo non dovrebbe essere difficile.

Qualsiasi codice qui può essere copiato e utilizzato in un'altra risposta, nessuna attribuzione richiesta.

var encodeAction = function(type, dx, dy) {
    var d
    if (dx === -1 && dy === -1) d = 1
    else if (dx === 0 && dy === -1) d = 2
    else if (dx === 1 && dy === -1) d = 3
    else if (dx === -1 && dy === 0) d = 4
    else if (dx === 1 && dy === 0) d = 5
    else if (dx === -1 && dy === 1) d = 6
    else if (dx === 0 && dy === 1) d = 7
    else if (dx === 1 && dy === 1) d = 8
    else return 0
    return 8 * type + d
}

var getNeighborCell = function(x, y, wallState) {
    if (x > 0 && y > 0 && grid(x - 1, y - 1) === wallState) return { x: x - 1, y: y - 1 }
    if (y > 0 && grid(x, y - 1) === wallState) return { x: x, y: y - 1 }
    if (x < 127 && y > 0 && grid(x + 1, y - 1) === wallState) return { x: x + 1, y: y - 1 }
    if (x > 0 && grid(x - 1, y) === wallState) return { x: x - 1, y: y }
    if (x < 127 && grid(x + 1, y) === wallState) return { x: x + 1, y: y }
    if (x > 0 && y < 63 && grid(x - 1, y + 1) === wallState) return { x: x - 1, y: y + 1 }
    if (y < 63 && grid(x, y + 1) === wallState) return { x: x, y: y + 1 }
    if (x < 127 && y < 63 && grid(x + 1, y + 1) === wallState) return { x: x + 1, y: y + 1 }
    return null
}

var moveBot = function(n) {
    var b = bots[n], moveX = b.x !== goal.x, x = b.x, y = b.y, type
    if (moveX) {
        x += b.x < goal.x ? 1 : -1
    } else {
        y += b.y < goal.y ? 1 : -1
    }
    if (grid(x, y) === 1) {
        if (b.hasWall) {
            type = 2 //place
            var c = getNeighborCell(b.x, b.y, 0)
            if (!c) { //stuck holding wall with walls all around
                return 0
            }
            x = c.x
            y = c.y
        } else {
            type = 1 //grab
        }
    } else if (grid(x, y) === 0) {
        if (getNeighborCell(x, y, 1)) {
            type = 0 //move
        } else {
            if (b.hasWall) {
                type = 2 //place
                if (moveX) {
                    y += y > 0 ? -1 : 1
                } else {
                    x += x > 0 ? -1 : 1
                }
            } else {
                type = 1 //grab
                var c = getNeighborCell(b.x, b.y, 1)
                if (!c) { //stuck without wall in midair
                    return 0
                }
                x = c.x
                y = c.y
            }
        }
    } else {
        return 0 //should never get here
    }
    return encodeAction(type, x - b.x, y - b.y)
}

var actions = []
for (var i = 0; i < 8; i++) {
    actions[i] = moveBot(i)
}

return actions

Ciascuno degli 8 robot segue indipendentemente lo stesso metodo di base. Tendono a raggrupparsi insieme per questo motivo, a meno che non vengano separati da qualcosa di esterno. I robot non si preoccupano mai di dove siano i compagni di squadra o i nemici, cercano solo di spostarsi verso l'obiettivo. Si muovono solo ortogonalmente, prima abbinando la loro x con l'obiettivo x, poi la loro y. Non muoversi mai in diagonale significa che perdono molto tempo in viaggio.

L'algoritmo di movimento di ciascun bot è il seguente:

If my X is not equal to the goal's X
    P = position to my left or right that is closer to the goal  
    Make a note that I'm trying to move horizontal  
Else  
    P = position above or below me that is closer to the goal  
    Make a note that I'm trying to move vertical  

If P is a wall  
    If I'm holding a wall  
        Place my wall in any neighboring air cell  
    Else  
        Grab the wall at P  
Else if P is air  
    If P has a wall neighboring it (i.e. if I can move to P)  
        Move to P  
    Else  
        If I'm holding a wall  
            If I'm trying to move horizontal  
                Place my wall above or below P  
            Else if I'm trying to move vertical  
                Place my wall to the left or right of P  
        Else  
            Grab wall from any neighboring wall cell   

6

Giocatore di squadra

Al momento, questa presentazione è tutt'altro che perfetta. Ha una strategia simile a quella degli Avamposti, ma solo 6 robot sono "in aria". Gli altri 2 robot forniscono loro muri se vengono rubati. Modifica: i robot sostenitori ora funzionano molto meglio.

var outside = function(x,y) {
    return x < 0 || x > 127 || y < 0 || y > 127
}

var distance = function(x1, y1, x2, y2){
  return Math.sqrt(Math.pow(x1-x2, 2) + Math.pow(y1-y2, 2));
}

var isStuck = function(bot) {
    if (bot.hasWall) {
        for (var i=-1; i<=1; i++) {
            for (var j=-1; j<=1; j++) {
                if ((i != 0 || j != 0) && grid(bot.x+i,bot.y+j) == 0 && !outside(bot.x+i,bot.y+j))
                    return false
            }
        }
        return true
    }
    for (var i=-1; i<=1; i++) {
        for (var j=-1; j<=1; j++) {
            if (grid(bot.x+i, bot.y+j) == 1)
                return false
        }
    }
    return true
}

var isPlayer = function(x,y) {
    for (var i = 0; i < bots.length; i++) {
        if (bots[i].x == x && bots[i].y == y)
            return true
    }
    for (var i = 0; i < ebots.length; i++) {
        if (ebots[i].x == x && ebots[i].y == y)
            return true
    }
    return false
}

var encodeAction = function(type, dx, dy) {
    var d
    if (dx === -1 && dy === -1) d = 1
    else if (dx === 0 && dy === -1) d = 2
    else if (dx === 1 && dy === -1) d = 3
    else if (dx === -1 && dy === 0) d = 4
    else if (dx === 1 && dy === 0) d = 5
    else if (dx === -1 && dy === 1) d = 6
    else if (dx === 0 && dy === 1) d = 7
    else if (dx === 1 && dy === 1) d = 8
    else return 0
    return 8 * type + d
}

var surrounding = function(x,y) {
    var cell = {hasStone:false, cells: []}
    for (var i=-1; i<=1; i++) {
        for(var j=-1; j<=1; j++) {
            if ((i != 0 || j != 0) && !outside(x+i,y+j)) {
                cell.cells.push({x:x+i, y:y+j})
                if (grid(x+i,y+j) == 1) {
                    cell.hasStone = true
                }
            }
        }
    }
    return cell
}


var hunt = function(i, destination) {
    destination = destination || {x: 31+((i-2)%3)*32, y: 20+((i-2)%2)*21}, bot = bots[i]
    if (i < 5 && i > 1) {
        destination.x -= 2
    }
    if (bot.isStuck) {
        return 0
    }
    if ((p1 && destination.x >= move + i) || (!p1 && 127 - destination.x > move - i)) {
        destination.y = bot.y
    }
    if (i == bestBotId && move > 50) {
        destination.x = goal.x
        destination.y = goal.y
    }
    var dx = destination.x > bot.x ? 1 : destination.x == bot.x ? 0 : -1, newX = bot.x + dx
    var dy = destination.y > bot.y ? 1 : destination.y == bot.y ? 0 : -1, newY = bot.y + dy
    var surr = surrounding(newX, newY), botSurr = surrounding(bot.x, bot.y)
    if (grid(newX, newY) == 0) {
        if (surr.hasStone) {
            return encodeAction(0, dx, dy)
        } else {
            if (bot.hasWall) {
                for (var i=0; i<surr.cells.length; i++) {
                    var cell = surr.cells[i];
                    if (Math.abs(cell.x - bot.x) <= 1 && Math.abs(cell.y - bot.y) <= 1 && grid(cell.x, cell.y) == 0 && !isPlayer(cell.x, cell.y)) {
                        return encodeAction(2, cell.x - bot.x, cell.y - bot.y)
                    }
                }
            } else {
                if (bot.walls.length == 1) {
                    return encodeAction(1, bot.walls[0].x - bot.x, bot.walls[0].y - bot.y)
                } else {
                    for (var i=0; i<bot.walls.length; i++) {
                        var wall = bot.walls[i], canUseWall = true
                        for (var j=0; j<bots.length; j++) {
                            if (bots[j].walls.length == 1 && bots[j].walls[0].x == wall.x && bots[j].walls[0].y == wall.y) {
                                canUseWall = false
                            }
                        }
                        if (canUseWall) {
                            return encodeAction(1, wall.x - bot.x, wall.y - bot.y)
                        }
                    }
                }
            }
        }
    } else {
        if (bot.hasWall) {
            for (var i=0; i<botSurr.cells.length; i++) {
                var cell = botSurr.cells[i];
                if (grid(cell.x, cell.y) == 0 && !isPlayer(cell.x, cell.y) && !outside(cell.x, cell.y)) {
                    return encodeAction(2, cell.x - bot.x, cell.y - bot.y)
                }
            }
        } else {
            return encodeAction(1, dx, dy)
        }
    }
    return 0 //hopefully never happens
}

var help = function(i) {
    if (bots[i].isStuck) {
        return 0
    }
    var bot = bots[i], destination = helpDestinations[i]
    if (destination.stuckBot == -1) {
        if (bot.walls.length >= 2 || (bot.hasWall && bot.walls.length == 1)) {
            var stuckId = -1
            for (var j = 0; j < bots.length; j++) {
                if (j != helpDestinations[(i+1)%2].stuckBot && bots[j].isStuck)
                    stuckId = j
            }
            if (stuckId != -1) {
                destination.stuckBot = stuckId
                destination.x = bots[stuckId].x
                destination.y = bots[stuckId].y
                return 0
            } else {
                return hunt(i, destination)
            }
        } else if (bot.x == destination.x && bot.y == destination.y) {
            if (move % 2 == 0)
                destination.y += 1
            else
                destination.x -= 1
            return hunt(i, destination)
        } else {
            return hunt(i, destination)
        }
    } else if (bots[destination.stuckBot].isStuck) {
        if (bot.walls.length < 2 && !(bot.hasWall && bot.walls.length == 1)) {
            destination.stuckBot = -1
            destination.x = i == 0 ? 42 : 85
            destination.y = 55
            return hunt(i, destination)
        }
        var dx = destination.x > bot.x ? 1 : destination.x == bot.x ? 0 : -1, newX = bot.x + dx
        var dy = destination.y > bot.y ? 1 : destination.y == bot.y ? 0 : -1, newY = bot.y + dy
        var surr = surrounding(newX, newY), botSurr = surrounding(bot.x, bot.y), surrWalls = 0
        for (var i = 0; i < surr.cells.length; i++) {
            var cell = surr.cells[i]
            if (grid(cell.x,cell.y) == 1)
                surrWalls++
        }
        if (grid(newX, newY) == 0) {
            if (surrWalls >= 2 || (surr.hasWall && bot.hasWall)) {
                return encodeAction(0, dx, dy)
            } else {
                if (bot.hasWall) {
                    for (var i=0; i<surr.cells.length; i++) {
                        var cell = surr.cells[i];
                        if (Math.abs(cell.x - bot.x) <= 1 && Math.abs(cell.y - bot.y) <= 1 && grid(cell.x, cell.y) == 0 && !isPlayer(cell.x, cell.y)) {
                            return encodeAction(2, cell.x - bot.x, cell.y - bot.y)
                        }
                    }
                } else {
                    if (bot.walls.length == 1) {
                        return encodeAction(1, bot.walls[0].x - bot.x, bot.walls[0].y - bot.y)
                    } else {
                        for (var i=0; i<bot.walls.length; i++) {
                            var wall = bot.walls[i], canUseWall = true
                            for (var j=0; j<bots.length; j++) {
                                if (bots[j].walls.length == 1 && bots[j].walls[0].x == wall.x && bots[j].walls[0].y == wall.y) {
                                    canUseWall = false
                                }
                            }
                            for (var j=0; j<surr.cells.length; j++) {
                                if (surr.cells[j].x == wall.x && surr.cells[j].y == wall.y)
                                    canUseWall = false
                            }
                            if (canUseWall) {
                                return encodeAction(1, wall.x - bot.x, wall.y - bot.y)
                            }
                        }
                    }
                }
            }
        } else {
            if (bot.hasWall) {
                for (var i=0; i<botSurr.cells.length; i++) {
                    var cell = botSurr.cells[i];
                    if (grid(cell.x, cell.y) == 0 && !isPlayer(cell.x, cell.y)) {
                        return encodeAction(2, cell.x - bot.x, cell.y - bot.y)
                    }
                }
            } else {
                return encodeAction(1, dx, dy)
            }
        }
    } else {
        destination.stuckBot = -1
        destination.x = i == 0 ? 42 : 85
        destination.y = 55
        return hunt(i, destination)
    }
    return 0 //hopefully never happens
}

var moves = new Array(8)    
var mem = getMem(), helpDestinations = []
if (mem.length == 0) {
    mem = "42,55,-1 85,55,-1"
}
mem = mem.split(" ")
for (var i = 0; i < mem.length; i++) {
    var cell = mem[i].split(",")
    helpDestinations.push({x: parseInt(cell[0]), y: parseInt(cell[1]), stuckBot: parseInt(cell[2])})
}

for (var i = 0; i < 8; i++) {
    var bot = bots[i]
    var surr = surrounding(bot.x, bot.y)
    bot.walls = []
    for (var j = 0; j < surr.cells.length; j++) {
        if (grid(surr.cells[j].x, surr.cells[j].y) == 1) {
            bot.walls.push(surr.cells[j])
        }
    }
}

bots.forEach(function(bot, index) {
    if(isStuck(bot)) {
        bot.isStuck = true
    }
})

var bestDistance = 1000
var bestBotId = -1
for (var i=2; i<8; i++) {
    var dist = distance(bots[i].x, bots[i].y, goal.x, goal.y)
    if (dist < bestDistance && !bots[i].isStuck) {
        bestDistance = dist
        bestBotId = i
    }
}

for (var i=0; i<8; i++) {
    if (i < 2) {
        moves[i] = help(i)
    } else {
        moves[i] = hunt(i)  
    }
}

setMem(helpDestinations[0].x + "," + helpDestinations[0].y + "," + helpDestinations[0].stuckBot + " " + helpDestinations[1].x + "," + helpDestinations[1].y + "," + helpDestinations[1].stuckBot)

return moves

L'idea del sostenitore (simpatica) sembra difficile da attuare.
edc65,

@ edc65 In pratica si sta muovendo solo con 2 muri invece di uno. Ma la comunicazione tra i due robot di supporto e la ricerca di nuovi muri era piuttosto difficile da implementare :)
CommonGuy,

6

cercatori

Stll lavori in corso. Ho molte idee, ma quasi nessuna di esse funziona.

Soprattutto, grosso problema con azioni fallite. Risolto!

var action=[], myGrid=[], goalSort=[], i, j, curBot, curAction, goalSeek;

var check = function(x,y) {
  return (myGrid[[x,y]] || (myGrid[[x,y]] = grid(x,y)))|0;
};

var setGrid = function(x,y,v) {
  myGrid[[x,y]] = v + '';
};

var orGrid = function(x,y,v) {
  myGrid[[x,y]] |= v;
};

var encodeDir = function(dx, dy) {
    return dx < 0 && dy < 0 ? 1
    : dx === 0 && dy < 0 ? 2
    : dx > 0 && dy < 0 ? 3
    : dx < 0 && dy === 0 ? 4
    : dx > 0 && dy === 0 ? 5
    : dx < 0 && dy > 0 ? 6
    : dx === 0 && dy > 0 ? 7
    : dx > 0 && dy > 0 ? 8
    : 0;
};

var distance = function(p1, p2) {
  return Math.max(Math.abs(p1.x-p2.x),Math.abs(p1.y-p2.y));
};

var cellNearWall = function(x,y)
{
  var r = check(x,y) == 1 ? 0
  : check(x-1,y-1) == 1 ? 1
  : check(x,y-1) == 1 ? 2
  : check(x+1,y-1) == 1 ? 3
  : check(x-1,y) == 1 ? 4
  : check(x+1,y) == 1 ? 5
  : check(x-1,y+1) == 1 ? 6
  : check(x,y+1) == 1 ? 7
  : check(x+1,y+1) == 1 ? 8
  : 0;
  return r;
};

var cellNearBot = function(x,y,m)
{
  return check(x-1,y-1) & m ? 1
  : check(x,y-1) & m ? 2
  : check(x+1,y-1) & m ? 3
  : check(x-1,y) & m ? 4
  : check(x+1,y) & m ? 5
  : check(x-1,y+1) & m ? 6
  : check(x,y+1) & m ? 7
  : check(x+1,y+1) & m ? 8
  : 0;
};


var tryGrabWall = function(x, y)
{
  var dx, dy, r = 8;
  for(dy = -1; dy < 2; ++dy)
  {
    for(dx = -1; dx < 2; ++dx)
    {
      if (dx|dy)
      {
        ++r;
        if (check(x+dx, y+dy) == 1)
        {
          setGrid(x+dx, y+dy, 0); // remember that the wall is not there anymore
          return r;
        }
      }
    }
  }
  return 0;
};

var tryDropWall= function(x, y)
{
  var dx, dy, r = 16;
  for(dy = -1; dy < 2; ++dy)
  {
    for(dx = -1; dx < 2; ++dx)
    {
      if (dx|dy)
      {
        ++r;
        if (x+dx>=0 & x+dx < 128 & y+dy >= 0 & y+dy < 64 && check(x+dx, y+dy) == 0)
        {
          setGrid(x+dx, y+dy, 1); // remember that the wall is there 
          return r;
        }
      }
    }
  }
  return 0;
};


var approach = function(bot, target)
{
  var dx, dy, tx, ty, r = 0, wallPos;

  var checkDrop = function(dx,dy)
  {
    var x = bot.x+dx, y = bot.y+dy;
    if (check(x,y) == 0 && cellNearBot(x,y,8) == 0)
    {
      setGrid(x, y, 1);
      return 16 + encodeDir(dx, dy);
    }
  };

  dy = target.y - bot.y;
  dy = dy < 0 ? -1 : dy > 0 ? 1 : 0;
  dx = target.x - bot.x;
  dx = dx < 0 ? -1 : dx > 0 ? 1 : 0;
  tx = bot.x+dx;
  ty = bot.y+dy;

  if ((dx|dy) === 0)
  {
    if (!bot.hasWall) {
      return tryGrabWall(bot.x, bot.y);
    }
    return 0;
  }


  if (cellNearWall(tx,ty))
  {
    setGrid(tx, ty, 2);
    return encodeDir(dx, dy);
  }

  if (dx === 0)
  {
    if (cellNearWall(bot.x-1,ty))
    {
      setGrid(bot.x-1, ty, 2);
      return encodeDir(-1, dy);
    }
    if (cellNearWall(bot.x+1,ty))
    {
      setGrid(bot.x+1, ty, 2);
      return encodeDir(1, dy);
    }
    if (bot.hasWall) 
    {
      if (wallPos = checkDrop(1,dy)) { return wallPos; }
      if (wallPos = checkDrop(-1,dy)) { return wallPos; }
      if (wallPos = checkDrop(1,0)) { return wallPos; }
      if (wallPos = checkDrop(-1,0)) { return wallPos; }
    }
  }
  else if (dy === 0) 
  {
    if (cellNearWall(tx,bot.y-1))
    {
      setGrid(tx, bot.y-1, 2);
      return encodeDir(dx, -1);
    }
    if (cellNearWall(tx,bot.y+1))
    {
      setGrid(tx, bot.y+1, 2);
      return encodeDir(dx, 1);
    }
    if (bot.hasWall) 
    {
      if (wallPos = checkDrop(dx,1)) { return wallPos; }
      if (wallPos = checkDrop(dx,-1)) { return wallPos; }
      if (wallPos = checkDrop(0,1)) { return wallPos; }
      if (wallPos = checkDrop(0,-1)) { return wallPos; }
    }
  }
  else
  {
    if (cellNearWall(tx,bot.y))
    {
      setGrid(tx, bot.y, 2);
      return encodeDir(dx, 0);
    }
    if (cellNearWall(bot.x,ty))
    {
      setGrid(bot.x, ty, 2);
      return encodeDir(0,dy);
    }
    if (bot.hasWall) {
      if (wallPos = checkDrop(dx,0)) { return wallPos; }
      if (wallPos = checkDrop(0,dy)) { return wallPos; }
      if (wallPos = checkDrop(dx,dy)) { return wallPos; }
    }
  }

  if (!bot.hasWall)
  {
  if (check(tx, ty) == 1)
  {
      setGrid(tx, ty, 0); // remember that the wall is not there anymore
      return 8 + encodeDir(dx, dy);
    };
    return tryGrabWall(bot.x, bot.y);
  }
  else
  {
    return tryDropWall(bot.x, bot.y);
  }
};

for (i=0; curBot=ebots[i]; i++)
{
  setGrid(curBot.x, curBot.y, curBot.hasWall ? 4 : 8);
}

var goalDistance=[]

for (i=0; curBot=bots[i]; i++)
{
  orGrid(curBot.x, curBot.y, 2);
  goalDistance[i] = distance(curBot, goal);
}
var sorted = goalDistance.slice().sort(function(a,b){return a-b})
var ranks = goalDistance.slice().map(function(v){ return sorted.indexOf(v)});

var tt = p1 
? [ { x:32, y:20 },{ x:32, y:55 },{ x:64, y:20 },{ x:64, y:55 },
   { x:96, y:20 },{ x:96, y:55 },{ x:16, y:30 },{ x:112, y:30 }]
: [ { x:96, y:20 },{ x:96, y:55 },{ x:64, y:20 },{ x:64, y:55 },
   { x:32, y:20 },{ x:32, y:55 },{ x:112, y:30 },{ x:16, y:30 }]

var goalSeek = 3;

for (i=0; curBot=bots[i]; i++)
{
  if (ranks[i] < goalSeek)
  {
    curAction = approach(curBot, goal);
    if (curAction == 0) goalSeek += 1;
  }
  else
    curAction = approach(curBot, tt[i]);

  action[i] = curAction;
}

return action;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.