Intro
Ceci est un roi de la colline interactive concours lequel le contrôleur est entièrement contenu dans un extrait de pile au bas de la question. Le contrôleur lit automatiquement les réponses et joue aux jeux. Tout le monde peut le lancer à tout moment, directement dans son navigateur.
Les mécanismes de ce concours sont très similaires à ceux de Red vs. Blue - Pixel Team Battlebots . Sauf que le jeu en cours, bien que toujours basé sur une grille, est totalement différent. Chaque jeu est 1 contre 1 et il n'y a pas d'équipes. Chaque inscription se bat pour elle-même et un seul sera le champion final.
Le contrôleur utilise JavaScript. JavaScript étant le seul langage de script côté client pris en charge par la plupart des navigateurs, toutes les réponses doivent également être écrites en JavaScript .
Dans cette spécification, le texte en italique est utilisé pour indiquer le terme formel pour un mécanisme de jeu ou une propriété. Ces termes sont utilisés dans l’ensemble pour aider à maintenir une manière cohérente et claire de faire référence aux différentes parties du jeu.
Gameplay
Les bases
Chaque réponse à cette question représente un joueur . Un jeu est une compétition entre deux joueurs, P1 et P2 . Chaque joueur contrôle un troupeau de 8 bots , numérotés de 0 à 7. Jeux a lieu dans la grille , un 128 × 64 cellules arène dont 8 lignes de fond commencent comme des murs (les « blocs ») et d' autres lignes de départ comme l' air . Les cellules situées en dehors des limites de la grille sont considérées comme de l'air.
La coordonnée x de la grille va de 0 à gauche à 127 à droite et y de 0 en haut à 63 en bas.
Exemple de grille de départ:
Les robots restent toujours alignés sur les cellules de la grille et plusieurs robots peuvent occuper la même cellule. Les robots ne peuvent occuper que des cellules d'air. Les robots de P1 commencent toujours dans une ligne 0-7 à l'extrême gauche de la rangée au-dessus des murs et les robots de P2 commencent toujours dans une ligne 7-0 à l'extrême droite.
Les voisins d'un bot ou d'une cellule sont les 8 cellules directement orthogonales et diagonales.
Le champ de vision ( FOV ) d'un robot est le carré de la cellule de 13 x 13 centrée sur un robot. Une cellule ou un bot ennemi est dit être dans le FOV d'un joueur s'il est dans le FOV d'au moins un des robots du joueur.
Mouvements & Actions
Au cours d'une partie, chaque joueur peut se déplacer 1000 fois. P1 se déplace en premier, puis P2, puis P1 et ainsi de suite jusqu’à ce que 2 000 mouvements aient été effectués. La partie se termine.
Au cours d'un mouvement, chaque joueur reçoit des informations sur l'état du jeu, les cellules de la grille et les robots ennemis de son champ de vision, et l'utilise pour décider d'une action à entreprendre pour chacun de ses robots.
L'action par défaut est ne rien faire , le bot ne se déplaçant pas et n'interagissant pas avec la grille.
Les autres actions sont déplacer , saisir et placer :
Un bot peut se déplacer vers l’une des cellules voisines C si:
- C n'est pas hors limites,
- C est l'air (c'est-à-dire pas un mur),
- et au moins un des voisins de C est un mur.
En cas de succès, le bot passera à C.
Un bot peut saisir l' une de ses cellules voisines C si:
- C n'est pas hors limites,
- C est un mur,
- et le bot ne porte pas déjà un mur.
En cas de succès, C deviendra de l’air et le bot aura maintenant un mur.
Un bot peut placer une de ses cellules voisines C si:
- C n'est pas hors limites,
- C est l'air,
- aucun des deux joueurs n'occupe C,
- et le bot porte un mur.
En cas de succès, C deviendra un mur et le bot ne portera plus de mur.
Les actions infructueuses aboutissent à ne rien faire.
Une cellule occupée par au moins un bot porteur de mur porte un petit carré de couleur. Les robots commencent sans murs.
Mémoire
Au cours d'un déplacement, un joueur peut accéder et modifier sa mémoire , une chaîne initialement vide qui dure tout au long du jeu et peut être utilisée pour stocker des données stratégiques.
Objectif
La cellule dans le réticule jaune est le but , qui commence dans une position aléatoire. Chaque joueur a un score qui commence à 0. Lorsque le bot d'un joueur se déplace vers le but, le score de ce joueur augmente de 1 et le but est repositionné au hasard avant le tour suivant. Le joueur avec le score le plus élevé à la fin d'une partie gagne. Il y a égalité si les scores sont égaux.
Si plusieurs robots se rendent au but pendant un coup, le joueur ne gagne toujours qu'un point.
Si le but est au même endroit depuis 500 coups, il est repositionné de manière aléatoire. Chaque fois que l'objectif est positionné de manière aléatoire, il est garanti qu'il ne sera pas placé sur une cellule occupée par un bot.
Que programmer
Ecrivez un corps pour cette fonction:
function myMove(p1, id, eid, move, goal, grid, bots, ebots, getMem, setMem) {
//body goes here
}
Il sera appelé une fois à chaque fois que votre joueur bouge et doit rendre les actions que vous souhaitez que chacun de vos robots effectue pendant ce mouvement.
Vous pouvez utiliser le code de base comme point de départ.
Paramètres
p1
est un bool qui esttrue
si vous êtes P1 etfalse
si vous êtes P2id
est un entier qui correspond à l'ID de réponse de votre réponse.
- Vous pouvez trouver l'ID d'une réponse en cliquant sur le lien "Partager" situé en dessous et en recherchant le numéro immédiatement après
a/
dans l'URL.- L'ID de l'entrée de test est -1.
eid
est un entier qui est l'ID de réponse de la réponse de votre ennemi.move
est un entier de 1 à 1000 indiquant le mouvement sur lequel vous vous trouvez.goal
est un objet avecx
ety
propriétés. Ce sont les coordonnées du but. Ils sont donnés même si le but est hors de votre champ de vision.grid
est une fonction qui prend en arguments x et y, par exemplegrid(x,y)
. Il retourne:
-1
pour 'inconnu' si les arguments ne sont pas deux entiers ou six,y
n'est pas dans votre champ de vision.0
pour 'air' six,y
est hors limites ou si la cellule àx,y
est est air.1
pour 'mur' si la cellule àx,y
est un mur.
bots
est un tableau de vos 8 robots. Ses éléments sont des objets avec des propriétésx
,y
ethasWall
:
x
ety
sont les coordonnées du bot.hasWall
esttrue
si le bot porte un mur etfalse
sinon.
bots
est toujours ordonné normalement, le Nième index correspond au numéro de bot N.ebots
est un tableau d'objets avecx
,y
et deshasWall
propriétés tout commebots
. Seuls les robots ennemis de votre champ de vision sont présentsebots
. Donc, il aurait une longueur de 0 s'il n'y avait pas de robots ennemis dans votre FOV. C'est ordonné au hasard.getMem
est une fonction sans argument qui retourne votre mémoire.setMem
est une fonction qui prend un argument M. Si M est une chaîne de 256 caractères ou moins, votre mémoire est mise à jour en M, sinon rien ne se produit.
L' console
objet de navigateur est disponible uniquement pour l'entrée de test.
Valeur de retour
Votre fonction doit renvoyer un tableau d’exactement 8 entiers, chacun compris entre 0 et 24. La valeur à l’indice N est l’action que le nombre de bot N va entreprendre.
Tous vos robots ne feront rien si votre fonction:
- Lance une erreur de toute nature. ( erreur )
- Prend plus de 20 millisecondes à exécuter. ( timeout )
- Ne retourne pas un tableau de 8 nombres entiers allant de 0 à 24. ( mal formé )
Pour plus de commodité, le nombre d'erreurs, de délais d'expiration et d'actions malformées est affiché à la fin d'un jeu.
Chacun des nombres de 0 à 24 correspond à une action de bot particulière:
- 0 est pour ne rien faire.
- 1-8 sont pour le déménagement.
- 9-16 sont pour saisir.
- 17-24 sont pour le placement.
Chacune des 8 valeurs pour déplacer, saisir et placer correspond à l'une des cellules voisines du bot, comme indiqué ci-dessous:
Ainsi, par exemple, 15
l'action consiste à saisir la cellule sous le bot.
Les actions de bot sont traitées dans l'ordre bot 0 à bot 7. Par exemple, si lors d'un mouvement, on dit à bot 0 de placer un mur dans la même cellule à air, il est dit à bot 1 de s'y déplacer, la cellule à air deviendra un mur avant L'action de 1 est gérée et le bot 1 échouera.
Les actions infructueuses deviennent des ratés et sont réputées avoir échoué . Les compteurs d'actions ayant échoué sont également affichés à la fin du jeu.
Règles
Je peux disqualifier temporairement ou définitivement des utilisateurs ou des réponses qui ne suivent pas ces règles. Les participations disqualifiées ne sont pas admissibles à gagner.
Lors de la déclaration de variables ou de fonctions, vous devez utiliser le
var
mot clé.
Par exemple,var x = 10
ouvar sum = function(a, b){ return a + b }
Les choses déclarées sansvar
devenir globales et pourraient interférer avec le contrôleur. Des mesures ont été prises pour que cette ingérence soit impossible, mais faites-le pour vous en assurer.Votre code ne doit pas être lent ni perdre du temps.
Il est impossible d'arrêter les fonctions JavaScript en cours d'exécution, le code de chaque joueur est donc exécuté à fond. Si votre code prend beaucoup de temps à s'exécuter, tous ceux qui exécutent votre lecteur le remarqueront et en seront agacés. Idéalement, les entrées fonctionneront toujours dans la limite de 20 ms.- Vous devez utiliser un code compatible avec ECMAScript 5 dans la dernière version de Firefox, car c'est ici que je l'exécuterai. N'utilisez pas les fonctionnalités d'ECMAScript 6 car elles ne sont pas encore prises en charge par de nombreux navigateurs.
- Vous pouvez répondre jusqu'à 3 fois, mais seulement si chacune de vos stratégies est très différente. Vous pouvez modifier les réponses autant que vous le souhaitez.
- Vous ne pouvez pas essayer d’avoir une quelconque mémoire sauf avec
getMem
etsetMem
. - Vous ne pouvez pas tenter d'accéder ou de modifier le contrôleur, le code d'un autre joueur ou des ressources externes.
- Vous ne pouvez pas tenter de modifier quoi que ce soit intégré à JavaScript.
- Les réponses ne doivent pas nécessairement être déterministes. Vous pouvez utiliser
Math.random
.
Format de réponse
#EntryName
Notes, etc.
<!-- language: lang-js -->
//function body
//probably on multiple lines
More notes, etc.
Le premier bloc de code multiligne doit contenir votre corps de fonction.
Le nom de l'entrée est limité à 20 caractères.
Votre entrée apparaîtra dans le contrôleur avec le titre EntryName - Username [answer ID]
, plus [DQ]
si elle est disqualifiée.
Gagnant
Quand la question sera posée pendant au moins 3 semaines et que la réponse sera réglée, je couronnerai le champion.
Je vais utiliser la fonction d' exécution automatique du contrôleur . Dans un tour en autorun, chaque joueur non disqualifié joue deux parties avec une autre, une en tant que P1, une en tant que P2 (un double round robin).
Je vais autoruner autant de tours que possible en l'espace de quelques heures. Cela dépendra du nombre de soumissions et de leur temps fastidieux. Mais rassurez-vous, je suis déterminé à obtenir un classement final précis. Le joueur avec le plus de victoires est le champion et sa réponse sera acceptée.
J'utiliserai Firefox sur un ordinateur portable avec Windows 8.1 64 bits, 4 Go de RAM et un processeur quad-core à 1,6 GHz.
Prix
Je vais écrire et poster un challenge PPCG spécifiquement dédié au champion. Cela impliquera en quelque sorte leur nom d'utilisateur ou leur avatar ou quelque chose à leur sujet. Je déciderai en privé de ce que sera le défi lorsque ce concours sera terminé. Je vais l'écrire au mieux de mes capacités et essayer de faire en sorte que cela devienne une question de réseau à chaud.
Manette
Exécutez cet extrait ou accédez à ce JSFiddle pour utiliser le contrôleur. Cela commence avec des joueurs choisis au hasard. Je ne l'ai que soigneusement testé dans Firefox et 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> <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>
Cette question a sa propre salle de discussion. J'y posterai des classements tous les quelques jours.