Rojo contra Azul - Pixel Team Battlebots


133

Este concurso ha terminado oficialmente. ¡El equipo azul ganó!

Arranqué automáticamente dos series de 50 batallas y, sorprendentemente, Blue ganó las 100. Mirando las estadísticas, está claro que las entradas cooperativas de PhiNotPi y Sp3000 fueron los verdaderos héroes. ¡Buen trabajo ustedes dos! De hecho, si descalificas a todos los demás miembros del Equipo Azul , los Sphibots aún luchan muy bien . Algunas personas del Equipo Rojo estaban planeando derribar a los Sphibots, pero este esfuerzo pareció agotarse. Lo siento equipo rojo.

El concurso ha terminado oficialmente, pero eso no significa que ya no puedas responder, solo significa que nunca volveré a declarar al ganador oficial. Ambos equipos son bienvenidos para seguir enviando bots, solo por diversión. El controlador permanecerá activo y seguirá funcionando mientras no lo rompan las entradas futuras.


Este es un concurso del rey de la colina , pero en lugar de que todos luchen entre sí, habrá dos equipos que competirán: Rojo y Azul. Solo uno será el ganador.

El equipo en el que está depende de su número de identificación de usuario PPCG . Para encontrar esto, haga clic en su avatar en la parte superior de la pantalla (debe iniciar sesión) y mire la URL de la página que se abre. El número siguiente users/es su número de identificación:

https://codegolf.stackexchange.com/users/[id number]/[display name]

Por ejemplo, mi número de identificación de usuario PPCG es 26997:

https://codegolf.stackexchange.com/users/26997/calvins-hobbies

Tenga en cuenta que este número es diferente para diferentes sitios de Stack Exchange.

Si su identificación es un número par , entonces usted está en el equipo Rojo .
Si su identificación es un número impar , entonces usted está en el equipo Azul .
No hay forma de cambiar de equipo.

Debes trabajar con tu equipo para tratar de derrotar al otro equipo en una especie de batalla real donde cada usuario controla un "píxel" del color de su equipo en la cuadrícula de 128 × 128 que es el campo de batalla. Los píxeles pueden moverse, comunicarse con sus compañeros de equipo y eliminar los píxeles del otro equipo. Se saldría de control si alguien pudiera crear cualquier número de píxeles, por lo que cada usuario solo puede enviar una respuesta a esta pregunta.

Este fragmento de pila (una versión reducida de este violín [ pantalla completa ]) es el controlador de todo el concurso. Lee automáticamente los envíos, se asegura de que sean válidos y organiza batallas entre los equipos. Lo hace directamente en su navegador en cualquier momento que desee, utilizando JavaScript . Dado que JavaScript es el único lenguaje de secuencias de comandos del lado del cliente que admite la mayoría de los navegadores, todas las presentaciones deben escribirse también en JavaScript.

function toggleDebug(){debug=$("#debug").is(":checked")}function rnd(e){return Math.floor(Math.random()*e)}function shuffle(e){for(var t,a,r=e.length;r;t=rnd(r),a=e[--r],e[r]=e[t],e[t]=a);return e}function maskedEval(e,t){var a={};for(i in this)a[i]=void 0;for(i in t)t.hasOwnProperty(i)&&(a[i]=t[i]);return new Function("with(this) { "+e+";}").call(a)}function createBattle(e,t,a,r){function n(){var e=rnd(i.length),t=i[e];return i.splice(e,1),t}var l={};l.width=l.height=128,l.totalMoves=2048,l.radius=16,l.msgMaxLength=64,l.timeLimit=15,l.move=0,l.redToMove=a,l.animated=r,l.running=!1,l.over=!1;for(var o=0,i=new Array(l.width*l.height),d=0;d<l.height;d++)for(var s=0;s<l.width;s++)i[o++]={x:s,y:d};l.redTeam=shuffle(e.slice()),l.redMsgs={},l.redKills={};for(var o=0;o<l.redTeam.length;o++){var u=n();l.redTeam[o].x=u.x,l.redTeam[o].y=u.y,l.redMsgs[l.redTeam[o].id]="",l.redKills[l.redTeam[o].id]=0}l.blueTeam=shuffle(t.slice()),l.blueMsgs={},l.blueKills={};for(var o=0;o<l.blueTeam.length;o++){var u=n();l.blueTeam[o].x=u.x,l.blueTeam[o].y=u.y,l.blueMsgs[l.blueTeam[o].id]="",l.blueKills[l.blueTeam[o].id]=0}return l}function drawBattle(e){function t(e){var t=3*e.x,a=3*e.y;ctx.fillRect(t,a,3,3),showNames.is(":checked")&&ctx.fillText(e.title,t+5,a+12)}function a(t){ctx.beginPath(),ctx.arc(3*t.x,3*t.y,3*e.radius,0,2*Math.PI),ctx.closePath(),ctx.fill()}e.animated&&(ctx.clearRect(0,0,canvas.width,canvas.height),showCircles.is(":checked")&&(ctx.fillStyle="rgba(255, 0, 0, 0.1)",e.redTeam.forEach(a),ctx.fillStyle="rgba(0, 0, 255, 0.1)",e.blueTeam.forEach(a)),ctx.fillStyle="red",e.redTeam.forEach(t),ctx.fillStyle="blue",e.blueTeam.forEach(t),moveCounter.text((e.move+1).toString()))}function movePlayer(e,t,a,r,n,l,o,i){function d(a){t.id!==a.id&&Math.sqrt(Math.pow(t.x-a.x,2)+Math.pow(t.y-a.y,2))<e.radius&&(u.push({x:a.x,y:a.y,id:a.id}),debug&&console.log(a.title+" is near"))}debug&&(console.log("--- Moving "+t.title+" ---"),console.log("position before move = ("+t.x.toString()+", "+t.y.toString()+")"));var s={};s.move=a,s.x=t.x,s.y=t.y,s.tCount=r.length,s.eCount=n.length,s.setMsg=function(a){"string"==typeof a&&(l[t.id]=a.length>e.msgMaxLength?a.substring(0,e.msgMaxLength):a,debug&&console.log('set message to "'+l[t.id]+'"'))},s.getMsg=function(e){var t=l.hasOwnProperty(e)?l[e]:void 0;return debug&&console.log('got message "'+t+'" from player with id '+e.toString()),t};var u=[];r.forEach(d),s.tNear=u,u=[],n.forEach(d),s.eNear=u,-1===t.id&&(s.console=console);var c=0,g=performance.now();try{c=maskedEval(t.code,s)}catch(v){c=0,debug&&(console.log("encountered error:"),console.log(v))}g=performance.now()-g,debug&&console.log("time taken = "+g.toString()+"ms"),g>e.timeLimit&&(c=0,debug&&console.log("went over the time limit of "+e.timeLimit+"ms"));var m=t.x,h=t.y;switch(c){case 1:e.redToMove?++m:++h;break;case 2:e.redToMove?--m:--h;break;case 3:++m,--h;break;case 4:--m,--h;break;case 5:--m,++h;break;case 6:++m,++h}m>=0&&m<e.width&&h>=0&&h<e.height&&(t.x=m,t.y=h),debug&&console.log("move direction = "+c);for(var f=0;f<n.length;f++)t.x===n[f].x&&t.y===n[f].y&&(debug&&console.log("took out "+n[f].title),++i[t.id],o[n[f].id]="X",n.splice(f--,1))}function advanceBattle(e){debug&&console.log("====== "+(e.redToMove?"Red ":"Blue ")+e.move.toString()+" ======");var t,a,r,n,l;e.redToMove?(t=e.redTeam,a=e.blueTeam,r=e.redMsgs,n=e.blueMsgs,l=e.redKills):(t=e.blueTeam,a=e.redTeam,r=e.blueMsgs,n=e.redMsgs,l=e.blueKills),t.forEach(function(o){movePlayer(e,o,Math.floor(e.move/2)+1,t,a,r,n,l)}),drawBattle(e);var o;return 0===a.length?(o=e.redToMove?1:-1,e.over=!0):++e.move>=e.totalMoves&&(o=e.redTeam.length>e.blueTeam.length?1:e.redTeam.length<e.blueTeam.length?-1:0,e.over=!0),e.redToMove=!e.redToMove,debug&&"undefined"!=typeof o&&console.log("win status = "+o.toString()),o}function newBattle(){if(0===redTeam.length||0===blueTeam.length)return void alert("Each team must have at least one player.");"undefined"!=typeof interval&&clearInterval(interval);var e=parseInt($("#delay").val());return isNaN(e)||0>e?void alert("Delay must be a non-negative integer."):(debug&&console.log("Created new battle with delay "+e.toString()),battle=createBattle(redTeam,blueTeam,$("#redMovesFirst").is(":checked"),!0),drawBattle(battle),void moveCounter.text("0").css("color","black"))}function reportKills(e,t){for(var a="Red Kills:\n",r=0;r<redTeam.length;r++)a+=e[redTeam[r].id].toString()+" by "+redTeam[r].title+"\n";a+="\nBlue Kills:\n";for(var r=0;r<blueTeam.length;r++)a+=t[blueTeam[r].id].toString()+" by "+blueTeam[r].title+"\n";return a}function intervalCallback(){var e=advanceBattle(battle);"undefined"!=typeof e&&(clearInterval(interval),battle.running=!1,alert([0===e?"Tie!":e>0?"Red Wins!":"Blue Wins!","Red remaining: "+battle.redTeam.length,"Blue remaining: "+battle.blueTeam.length,"\n"].join("\n")+reportKills(battle.redKills,battle.blueKills)))}function run(){if("undefined"!=typeof battle&&!battle.running&&!battle.over){battle.running=!0;var e=parseInt($("#delay").val());if(isNaN(e)||0>e)return void alert("Delay must be a non-negative integer.");interval=setInterval(intervalCallback,e)}}function pause(){"undefined"!=typeof battle&&(battle.running=!1),"undefined"!=typeof interval&&clearInterval(interval)}function step(){"undefined"==typeof battle||battle.running||battle.over||intervalCallback()}function autorunBattles(){function e(e){for(var t,i=createBattle(redTeam,blueTeam,e,!1);!i.over;)if(t=advanceBattle(i),"undefined"!=typeof t){i.over=!0,1===t?++a:-1===t?++n:++r;for(var d in i.redKills)i.redKills.hasOwnProperty(d)&&(l[d]+=i.redKills[d]);for(var d in i.blueKills)i.blueKills.hasOwnProperty(d)&&(o[d]+=i.blueKills[d])}}if(pause(),battle=void 0,0===redTeam.length||0===blueTeam.length)return void alert("Each team must have at least one player.");var t=parseInt($("#N").val());if(isNaN(t)||0>t)return void alert("N must be a non-negative integer.");console.log("Autorunning "+t.toString()+" battles");for(var a=0,r=0,n=0,l={},o={},i=0;i<redTeam.length;i++)l[redTeam[i].id]=0;for(var i=0;i<blueTeam.length;i++)o[blueTeam[i].id]=0;for(var i=0;t>i;i++)console.log("Battle "+i.toString()),e(i%2===0);alert([a===n?"Tie overall!":a>n?"Red wins overall!":"Blue wins overall!","Red wins: "+a.toString(),"Blue wins: "+n.toString(),"Ties: "+r.toString(),"\n"].join("\n")+reportKills(l,o))}function changeSelect(e){var t=e?redTeam:blueTeam,a=$(e?"#redSelect":"#blueSelect").val(),r=$(e?"#redCode":"#blueCode"),n=$(e?"#redLink":"#blueLink");null!==a&&a>-1?(r.text(t[a].code),n.attr("href",t[a].link)):(r.text(""),n.attr("href","javascript:;"))}function loadEntries(){function e(e,t){url="https://api.stackexchange.com/2.2/questions/"+qid.toString()+"/answers?page="+e.toString()+"&pagesize=100&order=asc&sort=creation&site=codegolf&filter=!JDuPcYJfXobC6I9Y-*EgYWAe3jP_HxmEee",$.get(url,t)}function t(d){d.items.forEach(function(e){function t(e,t){t.append(" ").append($("<a>").text(e.owner.display_name).attr("href",e.link))}function n(e){return $("<textarea>").html(e).text()}var d=e.owner.user_id%2===0,s=d?redTeam:blueTeam;if(e.owner.display_name=n(e.owner.display_name),e.hasOwnProperty("last_edit_date")&&e.last_edit_date-e.creation_date>r||dq.indexOf(e.owner.user_id)>-1||l.indexOf(e.owner.user_id)>-1)return void t(e,o);l.push(e.owner.user_id);var u=a.exec(e.body);if(null===u||u.length<=1)return void t(e,i);var c={};c.id=e.owner.user_id,c.title=e.owner.display_name+" ["+e.owner.user_id.toString()+"]",c.code=n(u[1]),c.link=e.link;var g=$(d?"#redSelect":"#blueSelect");g.append($("<option>").text(c.title).val(s.length)),s.push(c)}),d.has_more?e(++n,t):($("#loadStatus").hide(),$("#redCount").text(redTeam.length.toString()),$("#blueCount").text(blueTeam.length.toString()),0===o.html().length&&o.html(" none"),0===i.html().length&&i.html(" none"))}var a=/<pre><code>((?:\n|.)*?)\n<\/code><\/pre>/,r=28800,n=1,l=[],o=$("#disqualified"),i=$("#invalid");pause(),battle=void 0,redTeam=[],blueTeam=[],$("#loadStatus").show(),$("#redSelect").empty(),$("#redCode").empty(),$("#redLink").attr("href","javascript:;"),$("#blueSelect").empty(),$("#blueCode").empty(),$("#blueLink").attr("href","javascript:;");var d=$("#testbot").val();if(d.length>0){debug&&console.log("Using test entry");var s={id:-1,title:"TEST ENTRY [-1]",link:"javascript:;",code:d};$("#testbotIsRed").is(":checked")?(redTeam.push(s),$("#redSelect").append($("<option>").text(s.title).val(0))):(blueTeam.push(s),$("#blueSelect").append($("<option>").text(s.title).val(0)))}e(1,t)}var qid=48353,dq=[],ctx,moveCounter,showNames,showCircles,debug=!1,battle,redTeam,blueTeam,interval;$(document).ready(function(){ctx=$("#canvas")[0].getContext("2d"),moveCounter=$("#moveCounter"),showNames=$("#showNames"),showCircles=$("#showCircles"),loadEntries()});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><style>html *{font-family: Consolas, Arial, sans-serif;}select{width: 100%; margin: 12px 0 0 0;}button, select, input{font-size: 100%;}input{text-align: right;}textarea{font-family: "Courier New", monospace;}textarea[readonly]{background-color: #eee; width: 100%;}canvas{margin: 12px 0 0 0; border: 2px solid gray;}.redWrapper, .blueWrapper{width: 30%;}.redWrapper{float: left;}.blueWrapper{float: right;}.arenaWrapper{width: 40%; display: inline-block;}.redTeam, .blueTeam, .arena{padding: 12px;}.arena{text-align: center;}.redTeam, .blueTeam{border-style: solid; border-width: medium;}.redTeam{border-color: red; background-color: #fee;}.blueTeam{border-color: blue; background-color: #eef;}.redTitle, .blueTitle, .arenaTitle{text-align: center; font-size: 200%;}.redTitle, .blueTitle{font-weight: bold;}.redTitle{color: red;}.blueTitle{color: blue;}.control{margin: 12px 0 0 0;}.count{font-size: 75%; margin: 0 0 12px 0;}.footnotes{font-size: 75%; clear: both; padding: 12px;}</style><div id='loadStatus'> Loading entries...</div><div> <div class='redWrapper'> <div class='redTeam'> <div class='redTitle'> Red Team </div><select id='redSelect' size='20' onchange='changeSelect(true)'> </select> <div class='count'> <span id='redCount'></span> players </div>Code: <br><textarea id='redCode' rows='12' readonly></textarea> <br><a id='redLink' href='javascript:;'> Answer Link </a> </div></div><div class='arenaWrapper'> <div class='arena'> <div class='arenaTitle'> Battlefield </div><canvas id='canvas' width='384' height='384'> Your browser does not support the canvas tag. </canvas> <div>Move <span id='moveCounter'>0</span></div><br><div> <div class='control'> <input id='showNames' type='checkbox'>show names <input id='showCircles' type='checkbox'>show circles </div><div class='control'> <input id='redMovesFirst' type='checkbox'>red moves first </div><div class='control'> <input id='delay' type='text' size='4' value='20'> millisecond delay </div><div class='control'> <button type='button' onclick='newBattle()'> New Battle </button> <button type='button' onclick='run()'> Run </button> <button type='button' onclick='pause()'> Pause </button> <button type='button' onclick='step()'> Step </button> </div><hr class='control'> <div class='control'> <button type='button' onclick='autorunBattles()'> Autorun N Battles </button> N&nbsp;=&nbsp;<input id='N' type='text' size='4' value='16'> </div><div class='footnotes'> Autoruns may hang browser tab until complete. </div></div></div></div><div class='blueWrapper'> <div class='blueTeam'> <div class='blueTitle'> Blue Team </div><select id='blueSelect' size='20' onchange='changeSelect(false)'> </select> <div class='count'> <span id='blueCount'></span> players </div>Code: <br><textarea id='blueCode' rows='12' readonly></textarea> <br><a id='blueLink' href='javascript:;'> Answer Link </a> </div></div></div><div class='footnotes'> Test Entry: (id&nbsp;=&nbsp;-1) <input id='testbotIsRed' type='checkbox'>On Red Team <br><textarea id='testbot' rows='1' cols='32'></textarea> <br><button type='button' onclick='loadEntries()'> Reload with test entry </button> <br><br>This was designed and tested in Google Chrome. It might not work in other browsers. <br>Disqualified entries:<span id='disqualified'></span> <br>Could not find code block:<span id='invalid'></span> <br><input id='debug' type='checkbox' onclick='toggleDebug()'>Debug messages <br></div>

Para mayor visibilidad, el campo de batalla del Snippet se escala en un factor de 3, por lo que son 384 × 384 píxeles reales y los "píxeles" son 3 × 3.

Pixel Team Battlebots - Descripción general

Jugadores

Cada respuesta válida a esta pregunta representa un jugador . (Para obtener detalles sobre la validez, consulte "Reglas y descalificaciones" .) Cada jugador tiene control sobre una sola celda de 1 × 1 (también conocido como píxel) en el campo de batalla de 128 × 128 celdas . Los jugadores del equipo rojo tienen píxeles rojos y los jugadores del equipo azul tienen píxeles azules.

Batallas

Una batalla es una pelea entre todos los jugadores de ambos equipos, incluso si los equipos no tienen el mismo número de jugadores. Una batalla comienza con cada jugador colocado en una posición aleatoria en el campo de batalla, es decir, cualquier coordenada entera desde (0,0) en la parte superior izquierda, hasta (127,127) en la parte inferior derecha. Se garantiza que no habrá dos jugadores que comiencen en la misma posición.

Movimientos

Cada batalla se divide en 2048 movimientos . Solo un equipo realmente puede mover a sus jugadores durante cada movimiento. Ese equipo alterna de rojo a azul, por lo que cada equipo realiza 1024 movimientos en total (a menos que el juego termine antes).

El equipo que se mueve primero es una opción que debe configurar en el controlador.
Cuando las batallas se ejecutan automáticamente, el equipo que se mueve primero se alterna en cada batalla.

Movimientos de jugador

Cuando un equipo se mueve, todos los jugadores de ese equipo deben moverse. Estas llamadas se realizan en un orden completamente aleatorio para cada movimiento. Cuando se les llama, cada jugador recibe datos sobre el estado de la batalla para que puedan decidir qué camino tomar.

Todos los movimientos están a solo un píxel de distancia. Las ojeras en estos diagramas marcan a qué posiciones se puede mover cada jugador de color (los cuadrados):

Diagrama de movimientos del equipo rojo Diagrama de movimientos del equipo azul

Ambos colores pueden moverse en diagonal en cualquier dirección o permanecer quietos, pero solo los jugadores rojos pueden moverse hacia la derecha y hacia la izquierda, y solo los jugadores azules pueden moverse hacia abajo y hacia arriba. Gracias Phi y otros.

Si un jugador intenta moverse fuera de los límites del campo de batalla, o tarda demasiado en decidir qué camino tomar, o si tiene algún tipo de error, se quedará quieto automáticamente.

Además de moverse, durante un turno, un jugador puede leer mensajes escritos por sus compañeros de equipo y escribir mensajes que a su vez pueden leerse. Esto permite una forma cruda de comunicación en equipo.

El código que envía como respuesta es la lógica que determina la forma de mover su reproductor y qué mensajes leer y escribir (consulte "Cómo responder" ).

Eliminando jugadores enemigos

Cuando un jugador se mueve a la misma celda que un jugador del equipo contrario, ese jugador contrario se retira inmediatamente de la batalla. El jugador que acaba de moverse continúa de manera normal. ¡Este es el único mecanismo que elimina a los jugadores de la batalla y dominarlo es la clave para ganar!

Si hay varios jugadores enemigos en la celda a la que acaba de moverse un jugador, entonces todos los jugadores enemigos son eliminados. No pasa nada si dos jugadores del mismo equipo ocupan la misma celda.

Ganar una batalla

Una batalla termina una vez que se han realizado todos los movimientos de 2048 o cuando a un equipo no le quedan jugadores. El equipo con el mayor número de jugadores sobrevivientes gana. Es un empate si ambos equipos tienen el mismo número de jugadores sobrevivientes.

Cómo responder

En su respuesta, debe proporcionar el código JavaScript que decide de qué manera se moverá su píxel cuando se le solicite.

En el primer ejemplo de código sangrado en su respuesta (los prefijados con 4 espacios), escriba un cuerpo para esta función:

function moveMe(move, x, y, tCount, eCount, tNear, eNear, setMsg, getMsg) {
    //the body goes here
}

No hay necesidad de jugar golf con su código.

Que devolver

El valor de retorno de la función determina de qué manera se mueve su píxel:

0permanecer quieto
1para moverse hacia la derecha para el equipo Rojo, hacia abajo para que el equipo Azul se
2mueva hacia la izquierda para el equipo Rojo, hacia arriba para que el equipo Azul se
3mueva diagonalmente hacia arriba y
4hacia la derecha para moverse en diagonal hacia arriba y
5hacia la izquierda para moverse en diagonal hacia abajo y hacia la izquierda
6para moverse en diagonal abajo y a la derecha

Como un diagrama:

mover diagrama de valores de retorno

Su píxel permanecerá quieto de forma predeterminada si su código hace alguna de estas cosas:

  • Devuelve cualquier cosa además de un entero de 0 a 6.
  • Intenta mover píxeles fuera de los límites del campo de batalla.
  • Tarda más de 15 milisegundos en ejecutarse.
  • Lanza cualquier tipo de excepción.

Su entrada no necesita ser determinista; usar Math.randomestá bien.

Los parametros

Los primeros 7 parámetros de función moveMebrindan información sobre el estado de la batalla:

  • move es un número entero que comienza en 1 y se incrementa después de cada movimiento hasta que sea 1024 en el último movimiento de su equipo.
  • x es su posición x actual, un número entero de 0 (más a la izquierda) a 127 (más a la derecha).
  • y es su posición y actual, un número entero de 0 (más arriba) a 127 (más abajo).
  • tCount es el número total actual de jugadores supervivientes en tu equipo.
  • eCount es el número total actual de jugadores sobrevivientes en el equipo enemigo.
  • tNeares una lista de los jugadores supervivientes actuales en su equipo que están a menos de 16 píxeles de distancia (distancia euclidiana). Cada elemento de tNeares un objeto con x, yy idpropiedades:
    • x es la posición x del otro jugador
    • y es la posición y del otro jugador
    • id es el número de identificación de usuario PPCG del otro jugador (como un entero)
  • eNeares exactamente como, tNearexcepto que es una lista de jugadores enemigos cercanos, no compañeros de equipo.

Los círculos en el fragmento son de cada jugador tNeary eNearrango.

Mensajes

Los últimos 2 parámetros setMsgy getMsgtienen propósitos ligeramente diferentes.

A lo largo de una batalla, cada jugador tiene una cadena de hasta 64 personajes que pueden manipular durante cada movimiento para almacenar datos y potencialmente comunicarse con sus compañeros de equipo. La secuencia de cada jugador comienza como la secuencia vacía. Cuando un jugador es eliminado de la batalla, su cadena se establece en "X".

  • setMsg es una función de un argumento que establece su cadena a la cadena que se pasa.
    • Si el valor pasado no es una cadena, entonces su cadena no cambia.
    • Si el valor es una cadena con más de 64 caracteres, solo se conservan los primeros 64.
  • getMsg es una función de un argumento que toma el número de identificación de usuario PPCG (como un entero) de alguien en su equipo y devuelve su cadena.
    • Ese jugador puede estar en cualquier lugar de la cuadrícula. No necesitan estar en su radio de 16 píxeles.
    • undefined se devuelve si no se encuentra la ID dada.

Presentación de ejemplo

Este jugador se mueve hacia arriba y hacia la derecha si hay un enemigo a la izquierda, o hacia abajo y a la izquierda si su compañero de equipo con ID 123 lo dice, pero por lo demás se queda quieto:

for (var i = 0; i < eNear.length; i++) {
    if (eNear[i].x === x - 1)
        return 3
}
if (getMsg(123) === 'move down and left')
    return 5
return 0

Tenga en cuenta que este bloque de código es todo lo que se requiere. La definición de la función y los corchetes no deben estar presentes.

Reglas y descalificaciones

Si un usuario no cumple con las reglas que se enumeran a continuación, puedo marcarlo como descalificado y el controlador ignorará automáticamente sus respuestas. Confío en que la mayoría de los usuarios aquí no romperán intencionalmente las reglas y solo habrá algunas descalificaciones temporales por causas accidentales.

Reglas importantes

  1. Solo puede editar su respuesta durante la ventana de 8 horas directamente después de publicarla.
    El controlador descalificará automáticamente las respuestas que se editen después de 8 horas desde el momento en que se publicaron. Esta regla es para evitar que las respuestas iniciales optimicen continuamente su enfoque, posiblemente robando ideas de respuestas posteriores. Su equipo tiene que conformarse con las respuestas con las que comenzó.

    No puede eliminar y volver a publicar su respuesta sin un permiso especial. Daré esto si alguien edita tu publicación inadvertidamente después de las 8 horas o algo así, pero no solo porque encontraste un error.

    Si elimina su publicación y elige recuperarla, la regla de edición aún se aplica. (El controlador no puede ver las respuestas eliminadas).

  2. Al declarar una nueva variable de JavaScript, debe usar la varpalabra clave.
    Esto se debe a que una variable declarada sin se varconvierte en global en lugar de local, por lo que sería fácil meterse accidentalmente (o intencionalmente) con el controlador o comunicarse libremente con otros jugadores. Tiene que estar claro que no estás tratando de hacer trampa.

    Al declarar funciones, es mejor usar la varpalabra clave también. es decir, usar en var f = function(...) {...}lugar de function f(...) {...}. No estoy completamente seguro de por qué, pero a veces parece hacer la diferencia.

  3. Su código no debe ejecutarse durante un período de tiempo excesivo.
    Si su código tarda más de 15 milisegundos en ejecutarse, su píxel no se moverá en absoluto. Sin embargo, dado que es difícil en JavaScript detener las funciones a mitad de la ejecución, todos los scripts de los jugadores se ejecutan hasta su finalización en cada movimiento, y el tiempo se verifica después. Esto significa que si su código requiere algo de tiempo, todos los que ejecuten el controlador lo notarán y se molestarán.

Descalificaciones automáticas

El controlador descalificó automáticamente las entradas por estos motivos:

  • El usuario ya ha respondido.
  • Las modificaciones se realizaron más de 8 horas después de la creación.
  • El usuario está marcado específicamente como descalificado.

Otras reglas

En su código no puede ...

  • intenta acceder o modificar el controlador u otro código de jugador.
  • Intente modificar cualquier cosa integrada en JavaScript.
  • intenta comunicarte con otros jugadores excepto mediante el uso de getMsgy setMsg.
  • hacer consultas web
  • hacer cosas maliciosas de otra manera.

Estaré atento a otros comportamientos antideportivos, como robar código literalmente de otras respuestas o usar títeres de calcetín para meterse con el otro equipo.

Puede colaborar y planificar con su equipo, pero mantenga el concurso amigable y ético.

Si cree que alguien debe ser descalificado o cree que solucionó el motivo por el cual fue descalificado, deje un comentario aquí para mí o en el chat específico de la pregunta . No estoy participando en el concurso.

Formato de respuesta sugerido

#[team color] Team - [entry title]

    //function body
    //probably on multiple lines

Explanations, notes, etc.

El título de la entrada es un nombre opcional que puede dar si lo desea. El controlador no hace nada con él.

Puntuación

Este concurso finalizará oficialmente el 19 de abril de 2015. Ese día (alrededor de las 11 pm UTC) ejecutaré automáticamente al menos 100 batallas (posiblemente muchas más dependiendo de cuánto tiempo duran las batallas). El equipo que gane más será el ganador general. Si es un empate o muy cerca, correré más batallas hasta que quede claro que un equipo tiene la ventaja.

(Puede responder después de que se decida el ganador, pero no cambiaré el resultado oficial).

Los ejecutaré en la última versión de Google Chrome en una computadora portátil con Windows 8.1 de 64 bits, 4 GB de ram y un procesador de cuatro núcleos a 1.6GHz. Asegúrese de que su JavaScript funcione en Chrome.

La victoria se trata principalmente de la gloria del equipo, pero aceptaré la respuesta más votada en el equipo ganador.

A lo largo del concurso, tenga en cuenta que el aspecto basado en el equipo y el hecho de que se ejecuta completamente en un fragmento de pila son muy experimentales. Tengo muchas esperanzas, pero no puedo decir con certeza qué tan bien funcionarán las cosas.

Consejos:

  • Puede probar entradas antes de responder. Edite el cuadro de texto "Entrada de prueba" cerca de la parte inferior del Fragmento de pila y haga clic en "Volver a cargar con entrada de prueba". Si no está vacío, se convierte en un jugador del equipo especificado.
  • Las respuestas se ejecutan en un ámbito enmascarado, por lo que cosas como alerty console.logno funcionarán. El consoleobjeto solo se puede usar en la entrada de prueba.
  • Marque "Mensajes de depuración" en la parte inferior del Fragmento de pila y mire la consola de su navegador (F12). Se imprime mucha información útil cuando las batallas se están ejecutando.
  • Puede usar la publicación Meta Sandbox como una especie de área de ensayo. Las respuestas allí son, por supuesto, diferentes a las de aquí, y el controlador allí puede estar desactualizado.
  • Dado que no se trata de una aplicación Stack oficial , el controlador puede dejar de cargar respuestas por usted si la reinicia más de 300 veces en un día.

La "secuela" de este desafío: Block Building Bot Flocks!

enlaces rápidos

Fiddle Controller    Pantalla completa    Chat general Chat    rojo    (¿Chat azul?)    SandboxPost


51
Hiciste un trabajo realmente increíble al armar todo esto.
Alex A.

66
Todos, utilice el chat para comentarios no cruciales.
Hobbies de Calvin

44
El equipo rojo está coordinando en esta sala de chat: chat.stackexchange.com/rooms/22548/…
Adam Davis

55
Ayúdame, estoy absolutamente enamorado de esto. Corre la voz a todos los desarrolladores que conozcas.
Hylianpuffball

3
@HelkaHomba Hiya! Solo quería hacerle saber que las modificaciones de la Comunidad en algunas de las respuestas las descalificaron.
Stephen

Respuestas:


52

Equipo azul - SphiNotPi3000

// Char 0: top or bottom ("T" or "B")
// Char 1, 2: x/y coords
// Char 3, move polarity
// Char 4: offset (as codepoint - 128)

var twin = 21487;
var myself = 2867;
var formpos = "T";

var tochar = String.fromCharCode;
var movestat = (move % 2).toString();

var inbox = getMsg(twin);

// Spoofing the message of a deceased partner
if (inbox == "X"){
    inbox = "B" + tochar(x) + tochar(y+1) + ((move + 1) % 2).toString() + tochar(0);
}

var selfsafe = [9,10,10,10,10,10,10];

// Remove useless edge moves
if (x == 0){
    selfsafe[4] = 0;
    selfsafe[5] = 0;
}
if (x == 127){
    selfsafe[3] = 0;
    selfsafe[6] = 0;
}
if (y == 0){
    selfsafe[2] = 0;
    selfsafe[3] = 0;
    selfsafe[4] = 0;
}
if (y == 127){
    selfsafe[1] = 0;
    selfsafe[6] = 0;
    selfsafe[5] = 0;
}

var selfdisp = [[0,0],[0,1],[0,-1],[1,-1],[-1,-1],[-1,1],[1,1]];

if (inbox == "") {
    // First move, pick anywhere safe

    for (j = 0; j < 7; j++) {
        for (var i = 0; i < eNear.length; i++){
            var enemy = eNear[i];
            var dx = enemy.x - x - selfdisp[j][0];
            var dy = enemy.y - y - selfdisp[j][1];

            if (dx * dx == 1 && dy >= -1 && dy <= 1) {
                selfsafe[j] = 0;
            }
        }

        if (selfsafe[j]) {
            var strpos = tochar(x + selfdisp[j][0]) + tochar(y + selfdisp[j][0]);
            var offset = tochar(Math.floor(Math.random() * 256));
            setMsg(formpos + strpos + movestat + offset);
            return j;
        }
    }

} else {
    var twinformpos = inbox.charAt(0);
    var twinx = inbox.charAt(1).charCodeAt();
    var twiny = inbox.charAt(2).charCodeAt();
    var twinmovestat = inbox.charAt(3);
    var offset = inbox.charAt(4);

    formpos = twinformpos == "T" ? "B" : "T";
    var targetx = twinx;
    var targety = formpos == "T" ? (twiny - 1) : (twiny + 1);

    // If true, then this bot is either the second one to move or is not in position.  Move into position.
    if (twinmovestat == movestat || x != targetx || y != targety) {
        var bestmove = 0;

        for (var j = 0; j < 7; j++) {
            for (var i = 0; i < eNear.length; i++){
                var enemy = eNear[i];
                var dx = enemy.x - x - selfdisp[j][0];
                var dy = enemy.y - y - selfdisp[j][1];

                if (dx * dx == 1 && dy >= -1 && dy <= 1) {
                    selfsafe[j] = 0;
                }
                if (dx == 0 && dy == 0){
                    selfsafe[j] *= 2;
                }
            }

            selfsafe[j] -= Math.abs(x + selfdisp[j][0] - targetx) + Math.abs(y + selfdisp[j][1] - targety);

            if (selfsafe[j] > selfsafe[bestmove]) {
                bestmove = j;
            }
        }

        var strpos = tochar(x + selfdisp[bestmove][0]) + tochar(y + selfdisp[bestmove][1]);
        setMsg(formpos + strpos + movestat + offset);
        return bestmove;

    } else {
        // In formation, and is the leader this turn

        var topy = formpos == "T" ? y : (y - 1);
        var topx = x;
        var safe = [1,1,1,1,1,1,1,1,1];
        var disp = [[0,0],[0,1],[0,-1],[1,-1],[-1,-1],[-1,1],[1,1],[1,0],[-1,0]];
        var otherpos = formpos == "T" ? "B" : "T";

        // Avoid dangerous squares and always kill if safe to do so
        for (var j = 0; j < 9; j++){
            var ntopx = topx + disp[j][0];
            var ntopy = topy + disp[j][1];

            if (ntopx < 0 || ntopx > 127 || ntopy < 0 || ntopy > 126){
                safe[j] = 0;
                continue;
            }

            for (var i = 0; i < eNear.length; i++){
                var enemy = eNear[i];
                var dx = enemy.x - ntopx;
                var dy = enemy.y - ntopy;

                if(dx * dx == 1 && dy >= -1 && dy <= 2){
                    safe[j] = 0;
                    continue;
                }

                if(dx == 0 && dy >= 0 && dy <= 1){
                    // Kill!
                    var strpos = tochar(x + disp[j][0]) + tochar(y + disp[j][1]);

                    if (j > 6) {
                        setMsg(otherpos + strpos + movestat + offset);
                        if (formpos == "T"){return 13 - j;}
                        return j - 4;
                    }

                    setMsg(formpos + strpos + movestat + offset);
                    return j;
                }
            }
        }

        var pref = [];

        for (var i = 0; i < eNear.length; i++){
            var enemy = eNear[i];
            var dy = enemy.y - topy;
            var dx = enemy.x - topx;

            if (dy < 0 && dx == 0){ pref=[2,4,3,8,7,1,5,6,0]; }
            if (dy > 0 && dx == 0){ pref=[1,5,6,7,8,2,4,3,0]; }
            if (dy == 0 && dx > 0){ pref=[7,6,3,1,2,5,4,8,0]; }
            if (dy == 0 && dx < 0){ pref=[8,5,4,1,2,6,3,7,0]; }
            if (dy < 0 && dx < 0){ pref=[4,8,5,1,0,2,6,7,3]; }
            if (dy > 0 && dx < 0){ pref=[5,8,4,2,0,1,3,7,6]; }
            if (dy < 0 && dx > 0){ pref=[3,7,6,1,0,2,5,8,4]; }
            if (dy > 0 && dx > 0){ pref=[6,7,3,2,0,1,4,8,5]; }

            for (var k = 0; k < pref.length; k++)
            {
                if (safe[pref[k]]){
                    var strpos = tochar(x + disp[pref[k]][0]) + tochar(y + disp[pref[k]][1]);

                    if (pref[k] > 6) {
                        setMsg(otherpos + strpos + movestat + offset);
                        if(formpos == "T"){return 13 - pref[k];}
                        return pref[k] - 4;
                    }

                    setMsg(formpos + strpos + movestat + offset);
                    return pref[k];
                }
            }
        }

        var offsetint = offset.charCodeAt();
        var offsetmove = move - 128 + offsetint;

        if (offsetmove % 900 < 30) {
            var targetx = 64 - (offsetmove % 30);
            var targety = 64 - (offsetmove % 30);
        } else if (offsetmove % 900 < 90) {
            var targetx = 34 + ((offsetmove - 30) % 60);
            var targety = 34;
        } else if (offsetmove % 900 < 150) {
            var targetx = 94;
            var targety = 34 + ((offsetmove - 30) % 60);
        } else if (offsetmove % 900 < 210) {
            var targetx = 94 - ((offsetmove - 30) % 60);
            var targety = 94;
        } else if (offsetmove % 900 < 270) {
            var targetx = 34;
            var targety = 94 - ((offsetmove - 30) % 60);
        } else if (offsetmove % 900 < 300) {
            var targetx = 34 + (offsetmove % 30);
            var targety = 34 + (offsetmove % 30);
        } else if (offsetmove % 900 < 360) {
            var targetx = 64 + (offsetmove % 60);
            var targety = 64 - (offsetmove % 60);
        } else if (offsetmove % 900 < 480) {
            var targetx = 124;
            var targety = 4 + (offsetmove % 120);
        } else if (offsetmove % 900 < 600) {
            var targetx = 124 - (offsetmove % 120);
            var targety = 124;
        } else if (offsetmove % 900 < 720) {
            var targetx = 4;
            var targety = 124 - (offsetmove % 120);
        } else if (offsetmove % 900 < 840) {
            var targetx = 4 + (offsetmove % 120);
            var targety = 4;
        } else {
            var targetx = 124 - (offsetmove % 60);
            var targety = 4 + (offsetmove % 60);
        }

        if (offsetint % 4 == 1) {
            var temp = targetx;
            var targetx = 127 - targety;
            var targety = temp;
        } else if (offsetint % 4 == 2) {
            var targetx = 127 - targetx;
            var targety = 127 - targety;
        } else if (offsetint % 4 == 3) {
            var temp = targetx;
            var targetx = targety;
            var targety = 127 - temp;
        }

        if ((offsetint >> 3) % 2) {
            var targetx = 127 - targetx;
        }

        var bestmove = 0;

        for (var j = 0; j < 9; j++) {
            safe[j] -= Math.abs(topx + disp[j][0] - targetx) + Math.abs(topy + disp[j][1] - targety);

            if (safe[j] > safe[bestmove]) {
                bestmove = j;
            }
        }

        var strpos = tochar(x + disp[bestmove][0]) + tochar(y + disp[bestmove][1]);

        if (bestmove > 6) {
            setMsg(otherpos + strpos + movestat + offset);
            if (formpos == "T"){return 13 - bestmove;}
            return bestmove - 4;
        }

        setMsg(formpos + strpos + movestat + offset);
        return bestmove;
    }
}

Este bot forma un par con el bot de Sp3000 .

La idea básica es que dos bots, colocados adyacentes entre sí, ayudan a cubrir las debilidades del otro, de modo que ninguno de los bot tiene un lado expuesto. Esto ayuda a proteger de las amenazas y a limitar las opciones de escape del objetivo.

Al comienzo del juego, navegan uno hacia el otro y forman un par. Este par luego se mueve como una sola unidad, con un bot liderando al otro. Los dos bots tienen un código casi idéntico, lo que les permite intercambiar posiciones y roles cuando sea necesario.

Cuando está inactivo, los bots se mueven por el tablero en busca de enemigos. Una vez que ven a un enemigo, se maniobran cuidadosamente en las posiciones correctas para atacar. Una característica muy clara es la capacidad de la formación de moverse en línea recta horizontalmente, lograda al hacer que los bots alternen lugares.


99
¡Oh querido! Tan pronto como forman un par, es una pérdida automática para el rojo.
Minos

@Minos Bastante, sí :)
theonlygusti

Pensé en escribir un bot similar para rojo, pero no lo había hecho antes, ahora tengo que idear una estrategia que pueda vencer al dúo.
Nit

Para el registro, he visto que hay un lugar donde varno se usa en esta publicación y Sp3000. Asignan ja 0 de inmediato y no interfiere en absoluto con el controlador, por lo que afortunadamente no es un problema en este caso.
Aficiones de Calvin

47

Equipo azul - SphiNotPi3000

// Char 0: top or bottom ("T" or "B")
// Char 1, 2: x/y coords
// Char 3, move polarity
// Char 4: offset (as codepoint - 128)

var myself = 21487;
var twin = 2867;
var formpos = "B";

var tochar = String.fromCharCode;
var movestat = (move % 2).toString();

var inbox = getMsg(twin);

// Spoofing the message of a deceased partner
if (inbox == "X"){
    inbox = "B" + tochar(x) + tochar(y+1) + ((move + 1) % 2).toString() + tochar(0);
}

var selfsafe = [9,10,10,10,10,10,10];

// Remove useless edge moves
if (x == 0){
    selfsafe[4] = 0;
    selfsafe[5] = 0;
}
if (x == 127){
    selfsafe[3] = 0;
    selfsafe[6] = 0;
}
if (y == 0){
    selfsafe[2] = 0;
    selfsafe[3] = 0;
    selfsafe[4] = 0;
}
if (y == 127){
    selfsafe[1] = 0;
    selfsafe[6] = 0;
    selfsafe[5] = 0;
}

var selfdisp = [[0,0],[0,1],[0,-1],[1,-1],[-1,-1],[-1,1],[1,1]];

if (inbox == "") {
    // First move, pick anywhere safe

    for (j = 0; j < 7; j++) {
        for (var i = 0; i < eNear.length; i++){
            var enemy = eNear[i];
            var dx = enemy.x - x - selfdisp[j][0];
            var dy = enemy.y - y - selfdisp[j][1];

            if (dx * dx == 1 && dy >= -1 && dy <= 1) {
                selfsafe[j] = 0;
            }
        }

        if (selfsafe[j]) {
            var strpos = tochar(x + selfdisp[j][0]) + tochar(y + selfdisp[j][0]);
            var offset = tochar(Math.floor(Math.random() * 256));
            setMsg(formpos + strpos + movestat + offset);
            return j;
        }
    }

} else {
    var twinformpos = inbox.charAt(0);
    var twinx = inbox.charAt(1).charCodeAt();
    var twiny = inbox.charAt(2).charCodeAt();
    var twinmovestat = inbox.charAt(3);
    var offset = inbox.charAt(4);

    formpos = twinformpos == "T" ? "B" : "T";
    var targetx = twinx;
    var targety = formpos == "T" ? (twiny - 1) : (twiny + 1);

    // If true, then this bot is either the second one to move or is not in position.  Move into position.
    if (twinmovestat == movestat || x != targetx || y != targety) {
        var bestmove = 0;

        for (var j = 0; j < 7; j++) {
            for (var i = 0; i < eNear.length; i++){
                var enemy = eNear[i];
                var dx = enemy.x - x - selfdisp[j][0];
                var dy = enemy.y - y - selfdisp[j][1];

                if (dx * dx == 1 && dy >= -1 && dy <= 1) {
                    selfsafe[j] = 0;
                }
                if (dx == 0 && dy == 0){
                    selfsafe[j] *= 2;
                }
            }

            selfsafe[j] -= Math.abs(x + selfdisp[j][0] - targetx) + Math.abs(y + selfdisp[j][1] - targety);

            if (selfsafe[j] > selfsafe[bestmove]) {
                bestmove = j;
            }
        }

        var strpos = tochar(x + selfdisp[bestmove][0]) + tochar(y + selfdisp[bestmove][1]);
        setMsg(formpos + strpos + movestat + offset);
        return bestmove;

    } else {
        // In formation, and is the leader this turn

        var topy = formpos == "T" ? y : (y - 1);
        var topx = x;
        var safe = [1,1,1,1,1,1,1,1,1];
        var disp = [[0,0],[0,1],[0,-1],[1,-1],[-1,-1],[-1,1],[1,1],[1,0],[-1,0]];
        var otherpos = formpos == "T" ? "B" : "T";

        // Avoid dangerous squares and always kill if safe to do so
        for (var j = 0; j < 9; j++){
            var ntopx = topx + disp[j][0];
            var ntopy = topy + disp[j][1];

            if (ntopx < 0 || ntopx > 127 || ntopy < 0 || ntopy > 126){
                safe[j] = 0;
                continue;
            }

            for (var i = 0; i < eNear.length; i++){
                var enemy = eNear[i];
                var dx = enemy.x - ntopx;
                var dy = enemy.y - ntopy;

                if(dx * dx == 1 && dy >= -1 && dy <= 2){
                    safe[j] = 0;
                    continue;
                }

                if(dx == 0 && dy >= 0 && dy <= 1){
                    // Kill!
                    var strpos = tochar(x + disp[j][0]) + tochar(y + disp[j][1]);

                    if (j > 6) {
                        setMsg(otherpos + strpos + movestat + offset);
                        if (formpos == "T"){return 13 - j;}
                        return j - 4;
                    }

                    setMsg(formpos + strpos + movestat + offset);
                    return j;
                }
            }
        }

        var pref = [];

        for (var i = 0; i < eNear.length; i++){
            var enemy = eNear[i];
            var dy = enemy.y - topy;
            var dx = enemy.x - topx;

            if (dy < 0 && dx == 0){ pref=[2,4,3,8,7,1,5,6,0]; }
            if (dy > 0 && dx == 0){ pref=[1,5,6,7,8,2,4,3,0]; }
            if (dy == 0 && dx > 0){ pref=[7,6,3,1,2,5,4,8,0]; }
            if (dy == 0 && dx < 0){ pref=[8,5,4,1,2,6,3,7,0]; }
            if (dy < 0 && dx < 0){ pref=[4,8,5,1,0,2,6,7,3]; }
            if (dy > 0 && dx < 0){ pref=[5,8,4,2,0,1,3,7,6]; }
            if (dy < 0 && dx > 0){ pref=[3,7,6,1,0,2,5,8,4]; }
            if (dy > 0 && dx > 0){ pref=[6,7,3,2,0,1,4,8,5]; }

            for (var k = 0; k < pref.length; k++)
            {
                if (safe[pref[k]]){
                    var strpos = tochar(x + disp[pref[k]][0]) + tochar(y + disp[pref[k]][1]);

                    if (pref[k] > 6) {
                        setMsg(otherpos + strpos + movestat + offset);
                        if(formpos == "T"){return 13 - pref[k];}
                        return pref[k] - 4;
                    }

                    setMsg(formpos + strpos + movestat + offset);
                    return pref[k];
                }
            }
        }

        var offsetint = offset.charCodeAt();
        var offsetmove = move - 128 + offsetint;

        if (offsetmove % 900 < 30) {
            var targetx = 64 - (offsetmove % 30);
            var targety = 64 - (offsetmove % 30);
        } else if (offsetmove % 900 < 90) {
            var targetx = 34 + ((offsetmove - 30) % 60);
            var targety = 34;
        } else if (offsetmove % 900 < 150) {
            var targetx = 94;
            var targety = 34 + ((offsetmove - 30) % 60);
        } else if (offsetmove % 900 < 210) {
            var targetx = 94 - ((offsetmove - 30) % 60);
            var targety = 94;
        } else if (offsetmove % 900 < 270) {
            var targetx = 34;
            var targety = 94 - ((offsetmove - 30) % 60);
        } else if (offsetmove % 900 < 300) {
            var targetx = 34 + (offsetmove % 30);
            var targety = 34 + (offsetmove % 30);
        } else if (offsetmove % 900 < 360) {
            var targetx = 64 + (offsetmove % 60);
            var targety = 64 - (offsetmove % 60);
        } else if (offsetmove % 900 < 480) {
            var targetx = 124;
            var targety = 4 + (offsetmove % 120);
        } else if (offsetmove % 900 < 600) {
            var targetx = 124 - (offsetmove % 120);
            var targety = 124;
        } else if (offsetmove % 900 < 720) {
            var targetx = 4;
            var targety = 124 - (offsetmove % 120);
        } else if (offsetmove % 900 < 840) {
            var targetx = 4 + (offsetmove % 120);
            var targety = 4;
        } else {
            var targetx = 124 - (offsetmove % 60);
            var targety = 4 + (offsetmove % 60);
        }

        if (offsetint % 4 == 1) {
            var temp = targetx;
            var targetx = 127 - targety;
            var targety = temp;
        } else if (offsetint % 4 == 2) {
            var targetx = 127 - targetx;
            var targety = 127 - targety;
        } else if (offsetint % 4 == 3) {
            var temp = targetx;
            var targetx = targety;
            var targety = 127 - temp;
        }

        if ((offsetint >> 3) % 2) {
            var targetx = 127 - targetx;
        }

        var bestmove = 0;

        for (var j = 0; j < 9; j++) {
            safe[j] -= Math.abs(topx + disp[j][0] - targetx) + Math.abs(topy + disp[j][1] - targety);

            if (safe[j] > safe[bestmove]) {
                bestmove = j;
            }
        }

        var strpos = tochar(x + disp[bestmove][0]) + tochar(y + disp[bestmove][1]);

        if (bestmove > 6) {
            setMsg(otherpos + strpos + movestat + offset);
            if (formpos == "T"){return 13 - bestmove;}
            return bestmove - 4;
        }

        setMsg(formpos + strpos + movestat + offset);
        return bestmove;
    }
}

Este bot forma un par con el bot de PhiNotPi . Vea la publicación de Phi para una breve explicación de nuestra estrategia.


¡Ay! Buena ..
DoubleDouble

21

Equipo Rojo - SeekerBot

var myself = 38926;
var messages = getMsg(myself).split(';');
var minimalDistanceToFriend = 2;
var chosenMove = null;
var newDistanceToFriend = null;
var minimalVerticalDistanceToEnemy = null, minimalHorizontalDistanceToEnemy = null;
var closestFriend = null;
var closestEnemy = null;
var possibleVictims = [];
var possibleMoves = [
    {newX: x, newY: y},
    {newX: x + 1, newY: y},
    {newX: x - 1, newY: y},
    {newX: x + 1, newY: y - 1},
    {newX: x - 1, newY: y - 1},
    {newX: x - 1, newY: y + 1},
    {newX: x + 1, newY: y + 1}
];

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

var iAmInDanger = function(meX, meY, himX, himY) {
    return (Math.abs(meY - himY) === 1 && Math.abs(meX - himX) <= 1);
};

var iCanKillHim = function(meX, meY, himX, himY) {
    return (Math.abs(meX - himX) === 1 && Math.abs(meY - himY) <= 1);
};

var setMessage = function() {
    messages[0] = ("000" + x).substr(-3, 3);
    messages[1] = ("000" + y).substr(-3, 3);
    setMsg(messages.join(';'));
}

for (i = 0; i < possibleMoves.length; i++) {
    if (possibleMoves[i].newX < 0 || possibleMoves[i].newY < 0 || possibleMoves[i].newX > 127 || possibleMoves[i].newY > 127) {
        possibleMoves[i] = null;
    }
}

for (var i = 0; i < eNear.length; i++) {
    if (closestEnemy === null || calculateDistance(x, y, closestEnemy.x, closestEnemy.y) > calculateDistance(x, y, eNear[i].x, eNear[i].y)) {
        closestEnemy = eNear[i];
    }
    if (Math.abs(x - eNear[i].x) <= 2 && Math.abs(y - eNear[i].y) <= 2) {
        possibleVictims.push(eNear[i]);
    }
}

for (i = 0; i < tNear.length; i++) {
    if (closestFriend === null || calculateDistance(x, y, closestFriend.x, closestFriend.y) > calculateDistance(x, y, tNear[i].x, tNear[i].y)) {
        closestFriend = tNear[i];
    }
}    

for (i = 0; i < possibleMoves.length; i++) {
    for (var j = 0; j < possibleVictims.length; j++) {
        if (possibleMoves[i] !== null && iAmInDanger(possibleMoves[i].newX, possibleMoves[i].newY, possibleVictims[j].x, possibleVictims[j].y)) {
            possibleMoves[i] = null;
        }
    }
}

for (i = 0; i < possibleMoves.length; i++) {
    for (j = 0; j < possibleVictims.length; j++) {
        if (possibleMoves[i] !== null && possibleMoves[i].newX === possibleVictims[j].x && possibleMoves[i].newY === possibleVictims[j].y) {
            messages[2] = 0;
            setMessage();
            return i;
        }
    }
}

if (possibleVictims.length > 0) {
    if (iAmInDanger(x, y, possibleVictims[0].x, possibleVictims[0].y)) {
        if (closestFriend !== null) {
            for (i = 0; i < possibleMoves.length; i++) {
                if (possibleMoves[i] !== null) {
                    var distance = calculateDistance(possibleMoves[i].newX, possibleMoves[i].newY, closestFriend.x, closestFriend.y);
                    if (newDistanceToFriend === null || (distance < newDistanceToFriend && distance >= minimalDistanceToFriend)) {
                        newDistanceToFriend = distance;
                        chosenMove = i;
                    }
                }
            }
            messages[2] = 0;
            setMessage();
            return chosenMove;
        }
        else {
            var aggressiveMoves = [];
            var randomMoves = [];

            for (i = 0; i < possibleMoves.length; i++) {
                if (possibleMoves[i] !== null) {
                    if (iCanKillHim(possibleMoves[i].newX, possibleMoves[i].newY, possibleVictims[0].x, possibleVictims[0].y)) {
                        aggressiveMoves.push(i);
                    }
                    randomMoves.push(i);
                }
            }
            var approachCount = messages[2] || 0;
            if (approachCount < 5 && aggressiveMoves.length > 0) {
                messages[2] = approachCount + 1;
                chosenMove = aggressiveMoves[Math.floor(Math.random() * aggressiveMoves.length)];
                setMessage();
                return chosenMove;
            } 
            else {
                chosenMove = randomMoves[Math.floor(Math.random() * randomMoves.length)];
                setMessage();
                return chosenMove;
            }
        }
    }
}

if (closestEnemy != null) {
    for (i = 1; i < possibleMoves.length; i++) {
        if (possibleMoves[i] !== null) {
            var verticalDistance = Math.abs(possibleMoves[i].newY - closestEnemy.y);
            var horizontalDistance = Math.abs(possibleMoves[i].newX - closestEnemy.x);
            if (minimalVerticalDistanceToEnemy === null || verticalDistance <= minimalVerticalDistanceToEnemy) {
                if (minimalVerticalDistanceToEnemy !== null && verticalDistance === minimalVerticalDistanceToEnemy) {
                    if (minimalHorizontalDistanceToEnemy === null || horizontalDistance <= minimalHorizontalDistanceToEnemy) {
                        minimalHorizontalDistanceToEnemy = horizontalDistance;
                        chosenMove = i;
                    }
                }
                else {
                    minimalVerticalDistanceToEnemy = verticalDistance;
                    minimalHorizontalDistanceToEnemy = horizontalDistance;
                    chosenMove = i;
                }                                        
            }
        }            
    }
    messages[2] = 0;
    setMessage();
    return chosenMove;
}

var seekStatus = messages[3] || 0;
var seekCount = messages[4] || 0;
seekStatus = parseInt(seekStatus, 10);
seekCount = parseInt(seekCount, 10);

switch (seekStatus) {
    case 0:
        if (x < 16) {
            seekCount = 0;
            if (y > 111) {
                seekStatus = 4;
            }
            else {
                seekStatus = 1;
            }                
        }
        else {
            chosenMove = 2;
        }
        break;
    case 1:
        seekCount++;
        if (y > 111 || seekCount > 31) {
            seekStatus = 2;
        }            
        else {
            if (seekCount % 2 === 0) {
                chosenMove = 5;
            }
            else {
                chosenMove = 6;
            }
        }
        break;
    case 2:
        if (x > 111) {
            seekCount = 0;
            if (y > 111) {
                seekStatus = 4;
            }
            else {
                seekStatus = 3;
            }                   
        }
        else {
            chosenMove = 1;
        }
        break;
    case 3:
        seekCount++;
        if (y > 111 || seekCount > 31) {
            seekStatus = 0;
        }
        else {
            if (seekCount % 2 === 0) {
                chosenMove = 5;
            }
            else {
                chosenMove = 6;
            }
        }
        break;
    case 4:
        seekCount++;
        if (y < 16) {
            if (x > 63) {
                seekStatus = 0;
            }
            else {
                seekStatus = 2;
            }
        }
        else {
            if (seekCount % 2 === 0) {
                chosenMove = 3;
            }
            else {
                chosenMove = 4;
            }
        }
        break;
}

messages[2] = 0;
messages[3] = seekStatus;
messages[4] = seekCount;    

setMessage();
return chosenMove;

La máxima prioridad de SeekerBot es la supervivencia. Por lo tanto, solo considerará movimientos que no lo pondrán en peligro de ser asesinado en el siguiente turno (siempre que existan tales movimientos).

Cuando no hay oponentes a la vista, se moverá en un patrón sobre el campo de batalla, lo que asegurará que la mayor parte del terreno esté regularmente a la distancia de visualización.

Si SeekerBot ve a un enemigo, se moverá hacia él. Si puede matar a un enemigo, lo hará siempre que el movimiento se salve.

Si no puede matar a un enemigo pero el enemigo está en posición de matarlo en su próximo turno, SeekerBot intentará atraer al enemigo hacia un amigo (si hay uno visible). Si no hay ningún miembro del equipo a la vista, intentará moverse a una posición en la que pueda matar al enemigo en el próximo turno. Si esto no funciona 5 veces seguidas, cambiará de táctica y comenzará a moverse en un patrón aleatorio, posiblemente acercándose nuevamente al enemigo en la próxima ronda.

Para lo que vale, usará los primeros 7 caracteres del mensaje para gritar su propia posición en el formato "x; y" (donde x e y están rellenados con ceros).

Ciertamente no es el código más limpio, pero parece hacer lo que esperaba de él.



2
Has llevado al equipo rojo a ganar cada vez que lo corro. Será interesante ver qué hacen los dos nuevos robots azules una vez que se unen.
Adam Davis

Es muy divertido ver esta masacre del blues :)
TheNumberOne

@AdamDavis Esos dos robots azules que coordinan es una locura; ¡Todos los juegos que he visto hasta ahora han goleado!
theonlygusti

12

Equipo rojo - Groomba

// v009
// I exist, therefore I am identifiable and have motivation
var myself = 1686;
var motive = [ 4,4, 4,-1, 4,3, 3,-1, 
               3,3, 3,1, 1,1, 6,1,
               6,6, 6,-2, 6,5, 5,-2,
               5,5, 5,2, 2,2, 4,2]; 
var killzone = [4,2,5, 3,1,6];

// Default move is to not move.  Then we consider each task in lowest
// to highest priority.  Each task only modifies the move if it needs to.
var move = 0;
var vector = 0;
var step = 0;

// Restore internal state from message
var selfMessage;
selfMessage = getMsg(myself);
if(selfMessage === undefined || selfMessage.length > 2) // first run or bigger than 99, let's make some defaults!
{
   // vector, step - let the default above stand
}
else
{
   vector = Math.floor(parseInt(selfMessage)/2) % 16;
   step = parseInt(selfMessage) % 2;
}

// 1) Move according to motivation
move = motive[vector*2 + step];
step = (step + 1) % 2;

if(move == -1)
{
   move = Math.floor(Math.random() * 2) + 3;
}

if(move == -2)
{
   move = Math.floor(Math.random() * 2) + 5;
}

// 2) When interacting with a wall, rebound but alter the angle 
//    slightly so as to prevent trivial counterattack strategies
// If we are close to a wall and headed towards that wall, randomly
// choose another vector to follow.
if((y < 8 && (vector > 14 || vector < 6)) ||
   (y > 120 && (vector > 6 && vector < 14)) ||
   (x < 8 && (vector > 10 || vector < 2)) ||
   (x > 120 && (vector > 2 && vector < 10)))
{
   vector = Math.floor(Math.random() * 16);
}

// When an enemy is within view, move beside them

if(eNear.length > 0) // I only look at the first enemy in the array.
{
    enemy = eNear[0];
    if(enemy.x == x) // Don't want to be directly on top or below
    {
       if(enemy.y > y) // If they are below move angular down
       {
           move = (x > 63) ? 5 : 6;
       }
       else
       {
           move = (x > 63) ? 4 : 3;
       }
       move = 1;
    }
    else if(enemy.y > y)
    {
       if(enemy.x > x)
       {
           move = 6;
       }
       else
       {
           move = 5;
       }
       vector = 10;
    }
    else if(enemy.y != y)
    {
       if(enemy.x > x)
       {
           move = 3;
       }
       else
       {
           move = 4;
       }
        vector = 2;
    }
    else
    {
        if(enemy.x > x)
        {
            move = 1;
            vector = 6
        }
        else
        {
            move = 2;
            vector = 14;
        }
    }
}

// 3) When an enemy is one space away, act or react.
//    A) If it can be consumed, consume
//    B) If it can consume us next turn, evade
//    C) If we can reposition ourselves to consume next turn, reposition

var enemy;
var difx;
var dify;

// Evade
for(var i=0; i<eNear.length; i++) {
    enemy = eNear[i];
    if(enemy.x == x && enemy.y == y + 1)
    {
       if(x>63)
       {
           move = 5;
       }
       else
       {
           move = 6;
       }
    }
    if(enemy.x == x && enemy.y == y - 1)
    {
       if(x>63)
       {
           move = 4;
       }
       else
       {
           move = 3;
       }
    }
}

// Kill
for(var i=0; i<eNear.length; i++) {
    enemy = eNear[i];
    difx = enemy.x - x + 1;
    dify = enemy.y - y + 1;
    if((difx == 0 || difx == 2) && (dify > -1 && dify < 3))
    {
       move = killzone[Math.floor(difx/2) * 3 + dify];
    }
}

// 4) Encode the current surroundings and internal state
var value = vector*2+step
var message = value.toString();
setMsg(message);

// Return move
return move;

Notas en los comentarios.


3
No utilice self. Esa variable está reservada para señalar window.self. Use I(mayúscula i) en su lugar. O me. O incluso myself.
Ismael Miguel

11

Equipo rojo - Lazy Slayer

var moves={
    '-1':{'-1':4,'0':0,'1':3},
    '0':{'-1':2,'0':0,'1':1},
    '1':{'-1':5,'0':0,'1':6}
},$id=14732,to,enemies='';

for(var k in eNear)
{
    enemies+=String.fromCharCode(eNear[k].x+32)+String.fromCharCode(eNear[k].y+32);
}

enemies=enemies.replace('"','\\"');

for(var k in eNear)
{
    to=undefined;
    switch( eNear[k].x - x )
    {
        case -1:
        case 1:
            to=moves[eNear[k].y - y][eNear[k].x - x];
            break;
        case 0:
            to=moves[-(eNear[k].y - y)][0];
            break;
    }
    if(to!==undefined)
    {
        setMsg('"a":1,"o":['+x+','+y+'],"m":'+(to||0)+',"e":"'+enemies+'"');
        return to;
    }
}

var msg;

for(var k in tNear)
{
    if(msg = getMsg(tNear[k].id))
    {
        try
        {
            var m=JSON.parse('{'+msg+'}');
            if(m && m[$id])
            {
                if(m[$id].a === 1)
                {
                    if(!m[$id].x || !m[$id].y)
                    {
                        setMsg('"a":1,"o":['+x+','+y+'],"m":'+m[$id].m+',"id":'+m[$id].id+'}');
                        return m[$id].m;
                    }
                    else
                    {
                        setMsg('"a":1,"o":['+x+','+y+'],"m":{"x":'+m[$id].x+',"y":'+m[$id].y+'},"id":'+m[$id].id+',"e":"'+enemies+'"');
                        return moves[m[$id].x][m[$id].y];
                    }
                }
                else if(m[$id].a === 0)
                {
                    setMsg('"a":0,"o":['+x+','+y+'],"m":0,"id":'+m[$id].id+',"e":"'+enemies+'"');
                    return moves[m[$id].x||0][m[$id].y||0];
                }
            }
        }
        catch(e){}
    }
}

setMsg('"a":0,"o":['+x+','+y+'],"m":0,"e":"'+enemies+'"');
return 0;

Esto es lo más básico que pude conseguir. Esto ya no es 100% básico.

Solo se mueve SI SE REQUIERE .

Si un usuario envía un mensaje con 2 números entre -1y 1(por ejemplo:) '1,0', separados por una coma, se moverá allí. Confía totalmente en sus compañeros de equipo.

Esto ahora se comunica a través de JSON. Tiene una estructura muy básica:

  • getMsg:
    • a: determina la acción:
      • 0: detener
      • 1: mover
    • m: el movimiento para enviar
      • {x: n, y: n}: Objeto con x e y, entre -1 y 1
      • valor bruto que se devolverá con el número representado en la cuadrícula.
  • setMsg:
    • a: indica si se movió o si se detuvo;
    • o: una matriz con mi antigua posición;
    • m: el movimiento sin procesar devuelto por el código;
    • id: si se respetó una orden, esta tendrá la identificación del culpable;
    • e: lista con todas las posiciones enemigas. Cada posición está sesgada por 32, para evitar caracteres no imprimibles. Use string.charCodeAt (i) -32 para obtener la posición enemiga. Esta será una cadena con una longitud uniforme. Cada enemigo tendrá 2 caracteres.

Un ejemplo de un mensaje para controlarlo:

"14732":{"a":1,"m":3}

Que enviará:

"a":1,"o":[x,y],"m":3,"id":id,"e":""

También es un poco egoísta y no te ayudará y ahora él es útil como un faro estacionario.

Si este mensaje es incorrecto (el formato no es correcto), intente agregar en "}lugar de }.


Esto fue editado después del límite de 6 horas y luego se extendió a 8.

Ya no está roto y permanecerá como la versión final.


2
Como alguien del equipo rojo, creo que una cosa crucial que deberíamos incluir es siempre establecer un mensaje con su estado actual y rodearlo de alguna forma acordada de un objeto (esto debe incluir en qué movimiento se configuró, de lo contrario los bots ganaron ' No sé qué estado está desactualizado). Esto permitirá que otros bots posteriores se den cuenta de algo más que su propio entorno, posiblemente de todo el tablero, y tomen mejores decisiones.
Nit

@Nit Estoy de acuerdo contigo, y es por eso que tomé la decisión de usar JSON para comunicarme. Tengo 5 horas y 22m para hacer cambios. alguna idea mas?
Ismael Miguel

1
Creo que los primeros necesitan ser escáneres. Solo necesitamos cuatro para barrer de lado a lado para ensanchar toda la placa (32 ancho de escaneo efectivo cubre 1/4 de la placa). Muévase de lado a lado, establezca los N malos más cercanos usando una cadena binaria o comprimida, y evite a los malos, o busque y mate a los malos usando una estrategia razonable para evitar que los maten (nunca los deje en su esquina, ni arriba ni abajo ¿tú?).
Adam Davis

1
@IsmaelMiguel Nope. Espero enviar uno pronto también, pero no saber que Javascript me está ralentizando.
Adam Davis

3
Si no está roto, elimine los viejos comentarios obsoletos para reducir el desorden.
Nit

10

Equipo rojo - El cobarde

var bounds = 128;
var movements = [[0,0], [-1,-1],[1,-1],[-1,0],[1,0],[-1,1],[1,1]];

var distanceTo = function(x, y, pixel)
{
    var a = x - pixel.x;
    var b = y - pixel.y;
    return Math.sqrt( a*a + b*b );
}

var isDiagonallyAdjacent = function(x, y, pixel)
{
    return (Math.abs(pixel.x - x) == 1 && Math.abs(pixel.y - y) == 1);
}

var canAttackMe = function(x, y, pixel)
{
    if(x == pixel.x && Math.abs(pixel.y - y) == 1)
    {
        return true;
    }
    else
    {
        return isDiagonallyAdjacent(x, y, pixel);
    }
}

var canIAttack = function(x, y, pixel)
{
    if(y == pixel.y && Math.abs(pixel.x - x) == 1)
    {
        return true;
    }
    else
    {
        return isDiagonallyAdjacent(x, y, pixel);
    }
}

var isPositionSafe = function(x2, y2, enemies)
{
    var safe = true;
    for(var i in enemies)
    {
        if(canAttackMe(x2, y2, enemies[i]))
        {
            safe = false;
            break;
        }
    }
    return safe;
}

var moveTo = function(x, y, x2, y2)
{
    if(x2 < x)
    {
        if(y2 < y) return 4;
        else if(y2 > y) return 5;
        else return 2;
    }
    else if(x2 > x)
    {
        if(y2 < y) return 3;
        else if(y2 > y) return 6;
        else return 1;
    }
    else
    {
        if(y2 < y)
        {
            if(x2 < bounds)
            {
                return 3;
            }
            return 4;
        }
        else if(y2 > y)
        {
            if(x2 >= 0)
            {
                return 5;
            }
            return 6;
        }
    }
    return 0;
}

var getMovement = function(i)
{
    var m = [[0, 0], [1, 0], [-1, 0], [1, -1], [-1, -1], [-1, 1], [1, 1]];
    return m[i];
}

if(eNear.length == 0)
{
    // Move at random
    //return Math.floor((Math.random() * 6) + 1);
    return 0;
}
else 
{
    var safePositions = [];
    var isSafePosition = function(x2, y2)
    {
        for(var i in safePositions)
        {
            if(safePositions[i][0]==x2 && safePositions[i][0]==y2)
            {
                return true;
            }
        }
        return false;
    }

    for(var i in movements)
    {
        var x2 = x + movements[i][0];
        var y2 = y + movements[i][1];
        if(x2 >= 0 && x2 < bounds && y2 >= 0 && y2 < bounds
            && isPositionSafe(x2, y2, eNear))
        {
            safePositions.push([x + movements[i][0], y + movements[i][1]]);
        }
    }

    var dangerousPixels = [];
    var attackablePixels = [];
    var kamikazePixels = [];

    for(var ei in eNear)
    {
        var e = eNear[ei];
        var attackable = canIAttack(x, y, e);
        var dangerous = canAttackMe(x, y, e);
        if( attackable )
        {
            if(isSafePosition(e.x, e.y))
            {
                attackablePixels.push(e);
            }
            else
            {
                kamikazePixels.push(e);
            }
        }
        else if(dangerous)
        {
            dangerousPixels.push(e);
        }
    }
    if(attackablePixels.length == eNear.length)
    {
        return moveTo(attackablePixels[0].x, attackablePixels[0].y);
    }
    if(attackablePixels.length > 0 && tNear.length >= eNear.length)
    {
        // Attack only if we have greater numbers
        // Attack one of them at random
        var i = Math.floor(Math.random() * attackablePixels.length);
        return moveTo(x, y, attackablePixels[i].x, attackablePixels[i].y);
    }
    else if(dangerousPixels.length > 0 && safePositions.length > 0)
    {
        // Flee
        var i = Math.floor(Math.random() * safePositions.length);
        return moveTo(x, y, safePositions[i][0], safePositions[i][1]);

    }
    else if(dangerousPixels.length > 0 && safePositions.length == 0 && kamikazePixels.length > 0)
    {
        var i = Math.floor(Math.random() * kamikazePixels.length);
        return moveTo(x, y, kamikazePixels[i].x, kamikazePixels[i].y);
    }
    else 
    {
        var nearest = null;
        var nearestDist = Infinity;
        for(var ei in eNear)
        {
            var e = eNear[ei];
            var d = distanceTo(x, y, e);
            if(nearest === null || d < nearestDist)
            {
                nearestDist = d;
                nearest = e;
            }
        }

        if(tNear.length >= eNear.length)
        {
            // Attack the nearest
            return moveTo(x, y, nearest.x, nearest.y);
        }
        else
        {
            // Get Away from the nearest
            var n = moveTo(x, y, nearest.x, nearest.y);
            var m = getMovement(n);
            var x2 = x-m[0];
            var y2 = y-m[1];
            if(x2 < 0 || x2 >= bounds) x2 = x + m[0];
            if(y2 < 0 || y2 >= bounds) y2 = y + m[1];
            return moveTo(x, y, x2, y2);
        }
    }
}

Este bot permanece quieto para evitar ser detectado tanto como sea posible. Cuando uno o más enemigos están a la vista, pueden suceder varias cosas:

  • Si hay más enemigos que el bot y sus aliados a la vista, intenta alejarse del enemigo más cercano.
  • Si hay más amigos a la vista que enemigos, la superioridad numérica le da valor al robot e intenta avanzar y atacar al enemigo.
  • Si puede matar a un enemigo junto a él, lo intentará, independientemente de cuántos robots enemigos y enemigos haya, siempre tratando de terminar en una celda que no pueda ser atacada por otro bot.
  • Si todos los enemigos están protegidos por otros enemigos, intenta huir.
  • Si no puede ir a ninguna parte porque todas las posiciones pueden ser atacadas, entra en modo kamikaze e intenta al menos llevar a alguien con él a la tumba.

No se comunica con nadie, en caso de que alguien pueda escucharlo e ir tras él.

Puede que no sea el bot más útil para el equipo, pero fue divertido verlo tratando de alejarse de todos.


Vale, me encanta tu bot. La mía es todo lo contrario (busca enemigos y luego corre hacia el centro), por lo que tienen una interacción fantástica donde la mía podría intentar burlarse de la tuya y arrastrarla hacia el centro, pero luego, si la tuya ve a alguien, se asusta y corre de vuelta a la esquina, mientras que el mío lo persigue.
Hylianpuffball

¡Gracias! Me resulta divertido verlo interactuar con los demás. Pero encontré un par de errores con respecto a los límites y cómo rebota, pero es demasiado tarde para corregirlos ... Entonces, no es tan bueno como me gustaría que fuera.
rorlork

9

Equipo azul - águila

var move_valid = function(x, y, move){
    var move_x = {0:0, 1:0, 2:0, 3:1, 4:-1, 5:-1, 6:1};
    var move_y = {0:0, 1:1, 2:-1, 3:-1, 4:-1, 5:1, 6:1};
    var xx = x + move_x[move];
    var yy = y + move_y[move];
    return (1 <= xx && xx <= 125 && 1 <= yy && yy <= 125);
}
var sign = function(x){
    if (x === 0) return 0;
    else if (x > 0) return 1;
    else return -1;
}

if (eNear.length === 0) {
    if (getMsg(29577).length > 0) {
        var last_move = parseInt(getMsg(29577).charAt(0))
        if (last_move !== 0 && 
            move_valid(x, y, last_move) &&
            Math.random() > 0.03) return last_move;
    }

    var moves = [1, 2, 3, 4, 5, 6];
    var valid_moves = [];
    for (var move of moves){if (move_valid(x, y, move)) valid_moves.push(move);}
    if (valid_moves.length === 0) valid_moves.push(0);
    var move = moves[Math.floor(Math.random()*moves.length)];
    setMsg(move.toString());
    return move;
} else {
    var enemy = eNear[0];
    var dist = Math.max(Math.abs(x- enemy.x), Math.abs(y - enemy.y))
    var dir_x = sign(enemy.x - x);
    var dir_y = sign(enemy.y - y);
    var dir_to_move = {1: {1: 6, 0: -1, "-1": 3}, 0: {1: 1, 0: 1, "-1": 2}, "-1": {1: 5, 0: -1, "-1": 4}};
    var move = dir_to_move[dir_x][dir_y];
    var fight_count = 0;
    if (getMsg(29577).length > 1) {
        fight_count = parseInt(getMsg(29577).substring(1));
    }
    fight_count += 1;
    if (fight_count > 100){
        if (fight_count > 110) fight_count = 0;
        move = dir_to_move[-dir_x][dir_x !== 0 ? -dir_y : (Math.random() > 0.5 ? 1 : -1)];
        setMsg(move.toString() + fight_count.toString());
        return move;
    } else {
        if (dist > 2) {
            // Move towards enemy
            if (move === -1) move = dir_to_move[dir_x][Math.random() > 0.5 ? 1 : -1]
            setMsg(move.toString() + fight_count.toString());
            return move;
        } else if (dist === 2) {
            if (Math.abs(x - enemy.x) < 2) {
                // go one down if === 0
                // go diagonal, if ===1
                // move is already correct  
            } else if (Math.abs(y - enemy.y) === 2) {
                // dist_x == dist_y
                move = dir_to_move[0][dir_y];
            } else if (Math.abs(y - enemy.y) === 1) {
                move = dir_to_move[dir_x][-dir_y];
            } else {
                // dist_y == 0, dist_x == 2
                move = dir_to_move[0][Math.random() > 0.5 ? 1 : -1]
            }
            setMsg(move.toString() + fight_count.toString());
            return move;
        } else if (dist === 1) {
            if (move !== -1) {
                // Kill
                setMsg(move.toString() + fight_count.toString());
                return move;
            } else {
                // Run away
                var move = dir_to_move[-dir_x][Math.random() > 0.5 ? 1 : -1]
                setMsg(move.toString() + fight_count.toString());
                return move;
            }
        }
    }
    return 0;
}

Estoy bastante feliz con mi bot en este momento. Tiene las siguientes tácticas:

  • Si no hay enemigos cerca, muévete en una dirección aleatoria. Si golpeo una pared o después de unos 33 movimientos, cambio de dirección.
  • Si veo un enemigo, me muevo hacia él. (Con cuidado de no moverme a un campo, donde el enemigo puede matarme). Una vez que esté lo suficientemente cerca, muévete hacia él desde arriba o abajo y mata.

7

Equipo azul - Enemyeater

for (var i = 0; i < eNear.length; i++) {
    var enemy = eNear[i];
    var rx = enemy.x - x;
    var ry = enemy.y - y;
    if (rx == -1) {
        if (ry == 1) {
            return 4;
        }
        return 5;
    }
    if (rx == 0) {
        if (ry == 1) {
            return 2;
        }
        return 1;
    }
    if (rx == 1) {
        if (ry == 1) {
            return 3;
        }
        return 6;
    }
}
return Math.floor(Math.random() * 7);

Este pequeño píxel busca enimens a su alrededor e intenta comérselo, si no hay píxel alrededor se mueve en una dirección aleatoria. Tengo muchas ganas de ver qué se les ocurre a otras personas.


Lo siento, la última vez que codifiqué JavaScript fue como hace 2 años.
Loovjo

2
Math.floorno Math.float!
Jakube

1
@Jakube Or (Math.random() * 6) & 6or (Math.random() * 6) << 0or (Math.random() * 6) >> 0 (útil para codegolf).
Ismael Miguel

¿No necesitas hacer Math.random() * 7? He intentado algunas pruebas, y parece que tu bot no va a la parte inferior derecha. IIRC Math.random()es inclusivo 0 y exclusivo 1, lo que significa que en * 6realidad nunca es 6.
Destrictor

1
Lo siento a todos, apesta en JavaScript.
Loovjo

7

Equipo rojo - Cargador rojo nervioso

var direction = 3;
if (getMsg(14314) === ''){
    setMsg('3');
}
if (getMsg(14314) === '3'){
    direction = 6;
    setMsg('6');
}
else if (getMsg(14314) === '4'){
    direction = 5;
    setMsg('5');
}
else if (getMsg(14314) === '5'){
    direction = 4;
    setMsg('4');
}
else if (getMsg(14314) === '6'){
    direction = 3;
    setMsg('3');
}
if(x === 0){
    setMsg('3');
}
else if(x === 127){
    setMsg('5');
}
return direction;

El cargador rojo solo se mueve hacia la izquierda y hacia la derecha, con la esperanza de explotar la incapacidad del equipo azul para moverse en esas direcciones. Después de alcanzar una pared, se da la vuelta y carga en la dirección opuesta, con la esperanza de destruir ciegamente cualquier robot que se encuentre en su camino.

EDITAR: Red Charger acaba de beber un galón de bebida energética y ahora no puede dejar de temblar, también espera usar esto para su ventaja. Es demasiado cafeinado para escuchar a sus compañeros de equipo, pero está gritando cada uno de sus movimientos.


6

Equipo azul - LazySoldier

try {
    var state = getMsg(38671);
    if(state == null) {
       state = {direction:x==0?1:-1};
    } else {
       state = JSON.parse(state);
    }

    var choice = 0;    

    var escape=function(dx,dy) {
    if(dx==-1) {
       return y>0?4:5;
    } else if (dx==1) {
       return y>0?3:6;
    } else return 0;
    };

    var eat=function(dx,dy) {
       var b={'-1,-1':4, '0,-1':2,'1,-1':3,'-1,1':5,'0,1':1,'1,1':6};
       k=dx+','+dy;
       if(b[k]) {
       return b[k];
       } else return 0;
    };

    for(var i=0;i<eNear.length;i++) {
        var enemy = eNear[i];
        var dx=enemy.x-x;
        var dy=enemy.y-y;
        if(dy==0 && (dx==-1||dx==1)) {
            choice = escape(dx,dy);
            break;
        } else if(dy==-1 || dy==1) {
            choice = eat(dx,dy);
            break;
        }
    }

    if(x==0 || x==127) {
        state.direction=-state.direction;
    }

    if(choice == 0) {
       choice=state.direction==-1?2:1;
    }

    setMsg(JSON.stringify(state));
    return choice;

} catch(e) {
    if(console && console.error) {
        console.error(e);
    }
    return 0;
}

¿Cuántos bytes tiene normalmente el mensaje JSON? Solo se pueden almacenar los primeros 64 caracteres del mensaje.
PhiNotPi

.. Olvidé esa limitación :(
dieter

Supongo que dependerá de la cantidad de oponentes, ya que la cadena json incluye las posiciones de los eminems cercanos
dieta

Estoy cambiando el formato ahora mismo
dieter

1
Debe poner eso JSON.parseen un bloque try / catch o algo así ... está causando demasiados errores.
12Me21

6

Equipo Azul - Asesino en Masa

var i, j, enemies = [];
var DIRECTIONS = [4, 2, 3, 5, 1, 6];

// initialize 5x5 surroundings
for (i = 0; i < 5; i++) { 
    enemies[i] = [];
    for (j = 0; j < 5; j++) {
        enemies[i][j] = 0;
    }
}

// get amounts of enemies there
for (i = 0; i < eNear.length; i++) {
    var xOff = eNear[i].x - x + 2;
    var yOff = eNear[i].y - y + 2;
    if (xOff >= 0 && xOff <= 4 && yOff >= 0 && yOff <= 4) {
        enemies[yOff][xOff]++;
    }
}

// get maximum amount of direct neighbours, where I can move
var max = 0, index = -1;
// check the triple above
for (i = 0; i < 3; i++) { 
    if (enemies[1][i+1] > max) {
        max = enemies[1][i+1];
        index = i;
    }
}
// check the triple below
for (i = 0; i < 3; i++) { 
    if (enemies[3][i+1] > max) {
        max = enemies[3][i+1];
        index = i + 3;
    }
}

// if there is any reachable enemy, stomp on where the biggest amount of them is 
if (max > 0) {
    return DIRECTIONS[index];
}

// otherwise, if enemy is near (though unreachable), try to move that I am above or below him
var unreachable = [];
unreachable[4] = enemies[0][1] + enemies[2][1]; // NW (north west)
unreachable[3] = enemies[0][3] + enemies[2][3]; // NE
unreachable[5] = enemies[4][1] + enemies[2][1]; // SW
unreachable[6] = enemies[4][3] + enemies[2][3]; // SE
unreachable[2] = enemies[0][2];                 // N
unreachable[1] = enemies[4][2];                 // S

max = 0, index = 0;
for (i = 1; i <= 6; i++) {
    if (unreachable[i] > max) {
        max = unreachable[i];
        index = i;
    }
}

if (max > 0) {
    return index;
}

// if no one is near, let's move randomly
return Math.round(Math.random() * 6);

Supongo una táctica bastante sencilla. Cuento enemigos directamente accesibles por mí (supongo que habrá toneladas de ellos :)) y mato la mayor cantidad. Si no hay ninguno, al menos intentaré protegerme subiendo o bajando la mayor cantidad de enemigos con la esperanza de matarlos en el siguiente paso.

Dejé de tener en cuenta los muros, así que simplemente los ignoré. Es bastante largo de todos modos.

No pude probar / ejecutar este código, por lo que habrá muchos errores.


5

Equipo azul - WatchDog

var me = 38403;
var currentOwner = parseInt(getMsg(me));
var deltas = {1:{x:0,y:1},2:{x:0,y:-1},3:{x:1,y:-1},4:{x:-1,y:-1},5:{x:-1,y:1},6:{x:1,y:1}};
var check_danger = function(ennemi){
    for(var i in deltas){
        if(Math.abs(ennemi.x-x-deltas[i].x)<3 && Math.abs(ennemi.y-y-deltas[i].y)<2){
            delete deltas[i];
        }
    }
}
if(eNear.length > 0){
    for(var i in eNear){
        check_danger(eNear[i]);
    }
}
for(var i in deltas){
    if(x+deltas[i].x>126 || x+deltas[i].x<1 || y+deltas[i].y>126 || y+deltas[i].y<1)
        delete deltas[i];
}
if(!isNaN(currentOwner) && getMsg(currentOwner)!='X'){
    var Owner;
    if(tNear.length > 0){
        for(var i in tNear){
            if(tNear[i].id == currentOwner)
                Owner=tNear[i];
        }
    }
    if(Owner){
        var min=32;
        var choosen;
        var keys = Object.keys(deltas);
        if(keys.length>0){
            for(var i in deltas){
                var value = Math.abs(Owner.x-x-deltas[i].x)+Math.abs(Owner.y-y-deltas[i].y);
                if(value<min){
                    min=value;
                    choosen=i;
                }
            }
            if(min>0)
                return parseInt(choosen);
        }
    }
}
if(tNear.length > 0){
    setMsg(""+tNear[0].id);
}
var keys = Object.keys(deltas);
if(keys.length>0){
    if(eNear.length>0){
        var max=0;
        var choosen;
        for(var i in deltas){
            var value = Math.abs(eNear[0].x-x-deltas[i].x)+Math.abs(eNear[0].y-y-deltas[i].y);
            if(value>max){
                max=value;
                choosen=i;
            }
        }
        if(max>5)
            return parseInt(choosen);
    }
}
var deltas = {1:{x:0,y:1},2:{x:0,y:-1},3:{x:1,y:-1},4:{x:-1,y:-1},5:{x:-1,y:1},6:{x:1,y:1}};
if(eNear.length>0){
    var min=32;
    var choosen;
    for(var i in deltas){
        var value = Math.abs(eNear[0].x-x-deltas[i].x)+Math.abs(eNear[0].y-y-deltas[i].y);
        if(value<min){
            min=value;
            choosen=i;
        }
    }
    if(min==0)
        return parseInt(choosen);
}
return parseInt(keys[Math.floor(keys.length*Math.random())]);

Se mueve al azar hasta que agarra a un aliado, si es así, lo sigue. Intenta evitar ser asesinado, y matar si puede. Perdón por el horrible código, fui directo y olvidé la refactorización. Intentaré imprimir la legibilidad si tengo tiempo :)


5

Equipo rojo - Comandante buscador

var myself = 29354;

//Adjust eNear to account for any friendly information, using Lazy Slayer format

//Automatically add Lazy Slayer to list, even if out of range
var mytNear = [{
    id: 14732
}].concat(tNear);

var myeNear = [].concat(eNear);
var commandable = [];
var orders = [];

for (var i = 0; i < mytNear.length; i++) {
    try {
        var msg = getMsg(mytNear[i].id);
        var enemies = undefined;
        if (msg.indexOf('"m":') !== -1) {
            commandable.push(mytNear[i]);
        }
        if (msg.indexOf(myself) !== -1) {
            var j = msg.indexOf(myself)+(myself+' ').length;
            for (; j < msg.length; j++) {
                var order = parseInt(msg.substr(j,1));
                if (order) {
                    orders.push(order);
                    break;
                }
            }
        }
        if (msg.indexOf('"e":') !== -1) {
            var enemies = msg.substr(msg.indexOf('"e":')+5).split('"')[0];
            if(!enemies) continue;
            if(enemies.charCodeAt(j) > (32+127)) {
                for (var j = 0; j < enemies.length-1; j+=2) {
                    myeNear.push({
                        x: enemies.charCodeAt(j)-174,
                        y: enemies.charCodeAt(j+1)-174,
                    });
                }
            } else {
                for (var j = 0; j < enemies.length-1; j+=2) {
                    myeNear.push({
                        x: enemies.charCodeAt(j)-32,
                        y: enemies.charCodeAt(j+1)-32,
                    });
                }
            }
        }
    } catch (e) {}
}

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

var iAmInDanger = function(meX, meY, himX, himY) {
    return (Math.abs(meY - himY) === 1 && Math.abs(meX - himX) <= 1);
};

var iCanKillHim = function(meX, meY, himX, himY) {
    return (Math.abs(meX - himX) === 1 && Math.abs(meY - himY) <= 1);
};

var getMove = function(x, y, tNear, eNear, messages) {
    var minimalDistanceToFriend = 2;
    var chosenMove = null;
    var newDistanceToFriend = null;
    var minimalVerticalDistanceToEnemy = null,
        minimalHorizontalDistanceToEnemy = null;
    var closestFriend = null;
    var closestEnemy = null;
    var possibleVictims = [];
    var possibleMoves = [{
        newX: x,
        newY: y
    }, {
        newX: x + 1,
        newY: y
    }, {
        newX: x - 1,
        newY: y
    }, {
        newX: x + 1,
        newY: y - 1
    }, {
        newX: x - 1,
        newY: y - 1
    }, {
        newX: x - 1,
        newY: y + 1
    }, {
        newX: x + 1,
        newY: y + 1
    }];

    for (i = 0; i < possibleMoves.length; i++) {
        if (possibleMoves[i].newX < 0 || possibleMoves[i].newY < 0 || possibleMoves[i].newX > 127 || possibleMoves[i].newY > 127) {
            possibleMoves[i] = null;
        }
    }

    for (var i = 0; i < eNear.length; i++) {
        if (closestEnemy === null || calculateDistance(x, y, closestEnemy.x, closestEnemy.y) > calculateDistance(x, y, eNear[i].x, eNear[i].y)) {
            closestEnemy = eNear[i];
        }
        if (Math.abs(x - eNear[i].x) <= 2 && Math.abs(y - eNear[i].y) <= 2) {
            possibleVictims.push(eNear[i]);
        }
    }

    for (i = 0; i < tNear.length; i++) {
        if (closestFriend === null || calculateDistance(x, y, closestFriend.x, closestFriend.y) > calculateDistance(x, y, tNear[i].x, tNear[i].y)) {
            closestFriend = tNear[i];
        }
    }

    //If moving to the spot would put me in danger, don't do it
    for (i = 0; i < possibleMoves.length; i++) {
        for (var j = 0; j < possibleVictims.length; j++) {
            if (possibleMoves[i] !== null && iAmInDanger(possibleMoves[i].newX, possibleMoves[i].newY, possibleVictims[j].x, possibleVictims[j].y)) {
                possibleMoves[i] = null;
            }
        }
    }

    //If moving to the spot kills an enemy, do it now
    for (i = 0; i < possibleMoves.length; i++) {
        for (j = 0; j < possibleVictims.length; j++) {
            if (possibleMoves[i] !== null && possibleMoves[i].newX === possibleVictims[j].x && possibleMoves[i].newY === possibleVictims[j].y) {
                messages[2] = 0;
                return i;
            }
        }
    }

    //Enemy in sight
    if (possibleVictims.length > 0) {
        //This can only occur when they are in my blind spot
        if (iAmInDanger(x, y, possibleVictims[0].x, possibleVictims[0].y)) {
            if (closestFriend !== null) {
                for (i = 0; i < possibleMoves.length; i++) {
                    if (possibleMoves[i] !== null) {
                        var distance = calculateDistance(possibleMoves[i].newX, possibleMoves[i].newY, closestFriend.x, closestFriend.y);
                        if (newDistanceToFriend === null || (distance < newDistanceToFriend && distance >= minimalDistanceToFriend)) {
                            newDistanceToFriend = distance;
                            chosenMove = i;
                        }
                    }
                }
                messages[2] = 0;
                setMessage();
                return chosenMove;
            } else {
                var aggressiveMoves = [];
                var randomMoves = [];

                for (i = 0; i < possibleMoves.length; i++) {
                    if (possibleMoves[i] !== null) {
                        if (iCanKillHim(possibleMoves[i].newX, possibleMoves[i].newY, possibleVictims[0].x, possibleVictims[0].y)) {
                            aggressiveMoves.push(i);
                        }
                        randomMoves.push(i);
                    }
                }
                var approachCount = messages[2] || 0;
                if (approachCount < 5 && aggressiveMoves.length > 0) {
                    messages[2] = approachCount + 1;
                    chosenMove = aggressiveMoves[Math.floor(Math.random() * aggressiveMoves.length)];
                    return chosenMove;
                } else {
                    chosenMove = randomMoves[Math.floor(Math.random() * randomMoves.length)];
                    return chosenMove;
                }
            }
        }

    }

    //Move towards closest enemy
    if (closestEnemy != null) {
        for (i = 1; i < possibleMoves.length; i++) {
            if (possibleMoves[i] !== null) {
                var verticalDistance = Math.abs(possibleMoves[i].newY - closestEnemy.y);
                var horizontalDistance = Math.abs(possibleMoves[i].newX - closestEnemy.x);
                if (minimalVerticalDistanceToEnemy === null || verticalDistance <= minimalVerticalDistanceToEnemy) {
                    if (minimalVerticalDistanceToEnemy !== null && verticalDistance === minimalVerticalDistanceToEnemy) {
                        if (minimalHorizontalDistanceToEnemy === null || horizontalDistance <= minimalHorizontalDistanceToEnemy) {
                            minimalHorizontalDistanceToEnemy = horizontalDistance;
                            chosenMove = i;
                        }
                    } else {
                        minimalVerticalDistanceToEnemy = verticalDistance;
                        minimalHorizontalDistanceToEnemy = horizontalDistance;
                        chosenMove = i;
                    }
                }
            }
        }
        messages[2] = 0;
        return chosenMove;
    }

    //Take the order
    for (var i = 0; i < orders.length; i++) {
        var order = orders[i].m || orders[i];
        if (possibleMoves[order]) {
            return orders;
        }
    }

    var seekStatus = messages[3] || 0;
    var seekCount = messages[4] || 0;
    seekStatus = parseInt(seekStatus, 10);
    seekCount = parseInt(seekCount, 10);

    switch (seekStatus) {
        case 0:
            if (x < 16) {
                seekCount = 0;
                if (y > 111) {
                    seekStatus = 4;
                } else {
                    seekStatus = 1;
                }
            } else {
                chosenMove = 2;
            }
            break;
        case 1:
            seekCount++;
            if (y > 111 || seekCount > 31) {
                seekStatus = 2;
            } else {
                if (seekCount % 2 === 0) {
                    chosenMove = 5;
                } else {
                    chosenMove = 6;
                }
            }
            break;
        case 2:
            if (x > 111) {
                seekCount = 0;
                if (y > 111) {
                    seekStatus = 4;
                } else {
                    seekStatus = 3;
                }
            } else {
                chosenMove = 1;
            }
            break;
        case 3:
            seekCount++;
            if (y > 111 || seekCount > 31) {
                seekStatus = 0;
            } else {
                if (seekCount % 2 === 0) {
                    chosenMove = 5;
                } else {
                    chosenMove = 6;
                }
            }
            break;
        case 4:
            seekCount++;
            if (y < 16) {
                if (x > 63) {
                    seekStatus = 0;
                } else {
                    seekStatus = 2;
                }
            } else {
                if (seekCount % 2 === 0) {
                    chosenMove = 3;
                } else {
                    chosenMove = 4;
                }
            }
            break;
    }

    messages[2] = 0;
    messages[3] = seekStatus;
    messages[4] = seekCount;
    return chosenMove;
}

var messageObj = JSON.parse('{'+getMsg(myself)+'}');
if (!messageObj.$) {
    messageObj = {$:0};
}
var approachCount = (messageObj.$ & 7);
var seekStatus = ((messageObj.$ >> 3) & 7);
var seekCount = ((messageObj.$ >> 6));
var messages = [x, y, approachCount, seekStatus, seekCount];
var myMove = getMove(x, y, mytNear, myeNear, messages);
var msg = '"$":'+(messages[2] + (messages[3]<<3) + (messages[4]<<6)+',"m":'+myMove);
orders.length = 0;

//Issue commands to my allies
for (var i = 0; i < commandable.length; i++) {
    var ally = commandable[i];
    var command = getMove(ally.x, ally.y, tNear, myeNear, messages);
    var cmdStr = ',"'+ally.id+'":{"m":"'+command+'","a":1,"id":'+myself+'}'
    if (msg.length + cmdStr.length < 64) {
        msg += cmdStr;
    }
}

if (msg.length+9 < 64) {
    //Add my list of enemies
    var enemies = "";
    for(var i = 0; i < myeNear; i++) {
        if (msg.length+enemies.length+9 > 64) {
            break;
        }
        enemies+=String.fromCharCode(eNear[i].x+174)+String.fromCharCode(eNear[i].y+174);
    }
    msg += ',"e":"'+enemies+'"';
}

setMsg(msg);
return myMove;

Esta es una copia de Minos 'SeekerBot con algunas modificaciones.

  • Memoria interna comprimida para una mejor distribución de mensajes. "$":[seekmode]

  • Lee las posiciones enemigas de los aliados usando el formato JSON de Lazy Slayer "e":"[positions]"; acepta [positions]compensado por ambos 32y174

  • Informa las posiciones enemigas en el formato JSON de Lazy Slayer, "e":"[positions]"compensado por174

  • Reporta el último movimiento con "m":[move]para indicar que este bot puede ser comandado

  • Emite comandos a otros bots usando "[ally_id]":{"m":[move],"a":1,"id":29354}. El comando usa el mismo algoritmo buscador excepto en la ubicación del aliado. Si otros bots escuchan estas órdenes, deben agruparse y cazar en un paquete. Las órdenes solo se dan si el mensaje de aliado incluye"m":

  • Sigue los comandos de otros bots, como: "29354":[move]o "29354":{"m":[move]. Los comandos solo se siguen cuando no hay enemigos dentro del alcance y ningún otro aliado informa enemigos


Yo recomendaría incrementar las coordenadas por 174 en lugar de 32. Algunos mensajes que enviaba Lazy asesino eran como: ""a":0,"o":[122,70],"m":0,"e":"f"". También puedes unirte a nosotros en el chat si quieres.
TheNumberOne

Por desgracia, no tengo tiempo. Volveré a ver más tarde esta noche, pero eso será todo. He actualizado la publicación para usar la codificación 174, tanto para publicar como para analizar.
Wasmoo

5

Equipo Rojo - BouncerBot

function getDir(diff){
  return (diff < 0) ? -1 : ((diff > 0) ? 1 : 0);
}
function randInt(max){
  return Math.ceil(Math.random() * max);
}
var me = 29750;
var moves = [
  [4,3,3],
  [2,0,1],
  [5,5,6]
]; // Directions: -1 = up/left, 1 = down/right, 0 = none
if(x === 0){
  moves[0] = [3,3,3];
  moves[2] = [6,6,6];
} else if(x == 127){
  moves[0] = [4,4,4];
  moves[2] = [5,5,5];
}
for(var i in eNear){
  var xDiff = eNear[i].x - x,
      yDiff = eNear[i].y - y;
  if(xDiff >= -1 && xDiff <= 1 && yDiff >= -1 && yDiff <= 1){
    // If the enemy is directly adjacent, attack
    setMsg('');
    return moves[yDiff + 1][xDiff + 1];
  }
}
if(eNear.length > 0){
  var xDiff = eNear[0].x - x,
      yDiff = eNear[0].y - y;
  // If it can't attack, move toward the enemy.
  if(Math.abs(yDiff) == 2){
    if(xDiff >= -2 && xDiff <= 0) return 1;
    else if(xDiff == 2 || xDiff === 1) return 2;
  }
  return moves[getDir(yDiff) + 1][getDir(xDiff) + 1];
}
var msg = getMsg(me) || '',
    newDir = parseInt(msg);
if(msg === ''){
  newDir = randInt(4) + 2;
}
var isEndgame = move > 512;
     if(x === 0 || (isEndgame && x < 11)) newDir = (msg == 4) ? 3 : 6;
else if(x == 127 || (isEndgame && x > 116)) newDir = (msg == 3) ? 4 : 5;
else if((!isEndgame && y < 11) || y === 0) newDir = (msg == 4) ? 5 : 6;
else if((!isEndgame && y > 116) || y == 127) newDir = (msg == 5) ? 4 : 3;
if(newDir != msg) setMsg(newDir.toString());
return newDir;

Mi bot rebota de pared a pared (no exactamente, por lo que cubre diferentes terrenos) en busca de enemigos. Si tiene uno en su rango, ataca, los arrastra hacia una pared e intenta sacarlos (piense en un gorila en un club).


5

Equipo rojo - SideKick

var possibleMoves = [
      {newX: x, newY: y, value: 1},
      {newX: x, newY: y + 1, value: 1},
      {newX: x, newY: y - 1, value: 1},
      {newX: x + 1, newY: y - 1, value: 1},
      {newX: x - 1, newY: y - 1, value: 1},
      {newX: x - 1, newY: y + 1, value: 1},
      {newX: x + 1, newY: y + 1, value: 1}
];

var isDeadly = function(myX, myY, eX, eY) {
      return (Math.abs(myY - eY) === 1 && Math.abs(myX - eX) <= 1);
}

//stay near helpful friends!
if (tNear.length > 0) {
      for (var i = 0; i < tNear.length; i++) {
      if (Math.abs(tNear[i].x - x) > 2) {
            if (tNear[i].x > x) {
                  possibleMoves[3].value = possibleMoves[3].value + 5;
                  possibleMoves[1].value = possibleMoves[1].value + 5;
                  possibleMoves[6].value = possibleMoves[6].value + 5;
            } else {
                  possibleMoves[4].value = possibleMoves[4].value + 5;
                  possibleMoves[2].value = possibleMoves[2].value + 5;
                  possibleMoves[5].value = possibleMoves[5].value + 5;
            }
      }
      if (Math.abs(tNear[i].y - y) > 2) {
            if (tNear[i].y > y) {
                  possibleMoves[5].value = possibleMoves[5].value + 5;
                  possibleMoves[6].value = possibleMoves[6].value + 5;
            } else {
                  possibleMoves[4].value = possibleMoves[4].value + 5;
                  possibleMoves[3].value = possibleMoves[3].value + 5;
            }
      }
      }
}
//chase those enemies!
if (eNear.length > 0) {
      for (var i = 0; i < eNear.length; i++) {
      if (Math.abs(eNear[i].x - x) > 2) {
            if (eNear[i].x > x) {
                  possibleMoves[3].value = possibleMoves[3].value + 5;
                  possibleMoves[1].value = possibleMoves[1].value + 5;
                  possibleMoves[6].value = possibleMoves[6].value + 5;
            } else {
                  possibleMoves[4].value = possibleMoves[4].value + 5;
                  possibleMoves[2].value = possibleMoves[2].value + 5;
                  possibleMoves[5].value = possibleMoves[5].value + 5;
            }
      }
      if (Math.abs(eNear[i].y - y) > 2) {
            if (eNear[i].y > y) {
                  possibleMoves[5].value = possibleMoves[5].value + 5;
                  possibleMoves[6].value = possibleMoves[6].value + 5;
            } else {
                  possibleMoves[4].value = possibleMoves[4].value + 5;
                  possibleMoves[3].value = possibleMoves[3].value + 5;
            }
      }
      }
}

//walls
if (x === 127){
       possibleMoves[3] = null;
       possibleMoves[1] = null;
       possibleMoves[6] = null;
}
if (x === 0){
       possibleMoves[4] = null;
       possibleMoves[2] = null;
       possibleMoves[5] = null;
}
if (y === 0){
       possibleMoves[3] = null;
       possibleMoves[4] = null;
}
if (y === 127){
       possibleMoves[5] = null;
       possibleMoves[6] = null;
}

//deadly enemies
for (var i = 0; i < eNear.length; i++) {
      for (var j = 0; j < possibleMoves.length; j++) {
            if (possibleMoves[j] !== null && isDeadly(possibleMoves[j].newX, possibleMoves[j].newY, eNear[i].x, eNear[i].y)) {
                  possibleMoves[j] = null;
            }
      }
}

var bestMoves = [];
for (var i = 0; i < possibleMoves.length; i++)
{
      if (possibleMoves[i] !== null) {
            if (bestMoves.length === 0 || possibleMoves[i].value > possibleMoves[bestMoves[0]].value) {
                  bestMoves = [i];
            }
            else if (possibleMoves[i].value === possibleMoves[bestMoves[0]].value) {
                  bestMoves.push(i);
            }
      }
}
var returnValue = bestMoves[Math.floor(Math.random()*(bestMoves.length))];

return returnValue;

Le gusta seguir a sus compañeros, ¡qué bueno que hay muchos!


Es divertido notar que cuando esto se asocia con el bot de Wasmoo, a veces puede vencer al dúo azul.
Nit

1
@Nit, no lo he presenciado; pero supongo que el mío se convierte en una distracción para que Wasmoo los mate? Ojalá pudiera agregarle ahora; Intentaría predecir varios giros por delante y ver qué tipo de suicidio: las tácticas podrían funcionar contra el dúo.
DoubleDouble

5

Equipo azul - imán indeciso

var Mul = 4;
var Mu = 2;
var Mur = 3;
var Mdl = 5;
var Md = 1;
var Mdr = 6;
var Ms = 0;
var M = [Ms,Md,Mu,Mur,Mul,Mdl,Mdr];
var C =  [Mul,Mur,Mdl,Mdr];
var Mc = [{x:0,y:0},{x:0,y:1},{x:0,y:-1},{x:1,y:-1},{x:-1,y:-1},{x:-1,y:1},{x:1,y:1}];
/* If one or more enemies */
var nearEnemies = 0;
for(var i=0;i<eNear.length;i++){
    if(Math.abs(eNear[i].x-x)+Math.abs(eNear[i].y-y)<5){
        nearEnemies++;
    }
}
if(nearEnemies >0){
    //First check whether I can beat the enemy
    for(var i=0;i<eNear.length;i++){
        for(var j=0;j<7;j++){
            if(x+Mc[j].x == eNear[i].x && y+Mc[j].y == eNear[i].y){
                return j;
            }
        }
    }

    // Else advanced tactics
    function inRangeOfNEnemies(mx,my,eNear){
        var n=0;
        for(var i=0;i<eNear.length;i++){
            if( Math.abs(my-eNear[i].y)<=1 && Math.abs(mx-eNear[i].x)==1 ){
                n=n+1;
            }

        }
        return n;
    }

    //check all all possible moves:
    var moveDangerousness = new Array(7);;
    for(var i=0;i<7;i++)moveDangerousness[i]=1/(Math.abs(x+Mc[i].x-64)+Math.abs(y+Mc[i].y-64)+1);
    //calculate dangerouseness
    for(var i=0;i<7;i++){
        moveDangerousness[i] += inRangeOfNEnemies(x+Mc[i].x,y+Mc[i].y,eNear);
    }
    //mind walls
    for(var i=0;i<7;i++){
        if(x+Mc[i].x<0 ||  x+Mc[i].x>127 || y+Mc[i].y<0 ||  y+Mc[i].y>127 ){
            moveDangerousness[i] = 9999;
        }   
    }

    var leastDangerous = moveDangerousness.indexOf(Math.min.apply(Math,moveDangerousness));
    return leastDangerous;
} else if (eNear.length>3){ //run away from enemies
    var xmean = 0;
    var ymean = 0;
    for(var i=0;i<eNear.length;i++){
        xmean += eNear[i].x*1.0/eNear.length;
        ymean += eNear[i].y*1.0/eNear.length;       
    }
    var dx = x-xmean;
    var dy = y-ymean;
    if(dx >0){
        if(dy>0){
            return Mdr;
        } else {
            return Mur;
        }
    } else {
        if(dy>0){
            return Mdl;
        } else {
            return Mul;
        }
    }

} else {//* if there are no enemies *//
    //walk pattern until you find friend, then folloow friend
    var dx = 999; var dy = 999;
    if(tNear.length>0){
        for(var i=0;i<tNear.length;i++){
            if(Math.abs(dx)+Math.abs(dy) > Math.abs(tNear[i].x-x)+Math.abs(tNear[i].y-y)){
                dx = tNear[i].x-x;
                dy = tNear[i].y-y;
            }
        }
    } else {
        dx = 64-x+10*(Math.random()-0.5);
        dy = 64-y+10*(Math.random()-0.5);
    }

    if(dx >0){
        if(dy>0){
            return Mdr;
        } else {
            return Mur;
        }
    } else {
        if(dy>0){
            return Mdl;
        } else {
            return Mul;
        }
    }
}

Tiene múltiples estrategias: si puede vencer a un enemigo inmediatamente, lo hará, y huirá de los grupos de enemigos si están lo suficientemente lejos, de lo contrario luchará. Aparte de eso, solo está buscando miembros del equipo e intentando seguirlos.


4

Equipo azul - Recuperar [38953]

var me = 38953;
var msg = getMsg(me);
var register = msg ? JSON.parse(msg) : {};
var prevDanger = 0;
var danger;

var eScope = eNear;
var myX = x;
var myY = y;
var put = setMsg;
var get = getMsg;

function kill(){
  var move = -1;
  if(!eScope){return -1;}

  eScope.forEach(function(e){
    if(move > -1){return move;}

    var xDist = Math.abs(e.x-myX);
    var yDist = Math.abs(e.y-myY);

    if(xDist < 2 && yDist < 2){
      if(e.x == myX){
        if(e.y == myY-1){move = 2;}
        else if(e.y == myY+1){move = 1;}
      }
      else if(e.x == myX-1){
        if(e.y == myY-1){move = 4;}
        else if(e.y == myY+1){move = 5;}
      }
      else if(e.x == myX+1){
        if(e.y == myY-1){move = 3;}
        else if(e.y == myY+1){move = 6;}
      }
    }
  });

  return move;
}

function live(){
  var move = -1;
  if(!eScope){return -1;}
  var topHalf = (myY <= 64);

  eScope.forEach(function(e){
    if(move > 0){return move;} //0 on purpose; we might find a better escape

    var xDist = Math.abs(e.x-myX);
    var yDist = Math.abs(e.y-myY);

    if(xDist + yDist < 5){move = 0;}  //uh oh!  Stand still!

    if(e.y == myY){
      if(e.x == myX-1){move = (topHalf ? 5 : 4);}
      else if(e.x == myX+1){move = (topHalf ? 6 : 3);}
    }
  });

  return move;
}

function evalDanger(){
  danger = 0;

  if(register){prevDanger = register.d;}

  eScope.forEach(function(e){
    var xDist = Math.abs(e.x-myX);
    var yDist = Math.abs(e.y-myY);
    danger += ((1/yDist) * (1/xDist));
  });

  register.d = danger;
  put(JSON.stringify(register));
  return danger;
}

function distract(){
  //run to the edge if safe, to the middle if not
  var safe = (danger <= prevDanger && danger < .01);

  var topHalf = myY <= 64;
  var leftSide = myX <= 64;

  //lazy init to 'explore' mode
  if(!register.e){register.e = 1;}

  //lazy init to whatever corner we're in
  if(!register.f){
    register.f = topHalf ? leftSide ? 4 : 3 : leftSide ? 5 : 6;
  }

  //turn 'explore' on (1) or off (2);
  //if 'off' but hit 'home base', seek a corner
  if(register.e == 2 && ((myY > 54 && myY < 74) || (myX > 54 && myX < 74))){
    register.e = 1
    register.f = Math.floor(Math.random()*4)+3;
  }
  //if on the outskirts, go back to base
  if(myY < 10 || myY > 115 || myX < 10 || myX > 115){register.e = 2;}

  put(JSON.stringify(register));

  if(topHalf){
    if(leftSide){
      if(!safe || register.e == 2){return 6;}
    }
    else{
      if(!safe || register.e == 2){return 5;}
    }
  }
  else {
    if(leftSide){
      if(!safe || register.e == 2){return 3;}
    }
    else{
      if(!safe || register.e == 2){return 4;}
    }
  }
  return register.f;
}

evalDanger();
register.x = myX;
register.y = myY;

var whee = kill();
if(whee > -1){
    return whee;
}

whee = live();
if(whee > -1){
    return whee;
}

whee = distract();
return whee;

[ediciones: ¡resulta que funciona MUCHO mejor cuando uso mi ID real y no -1!]

Un pequeño bot tonto que corre alrededor del tablero, haciendo todo lo posible para atraer la atención y atraer cazadores, y luego correr hacia el medio donde (con suerte) encontrará a alguien que lo ayude, o simplemente detendrá al cazador y lo detendrá. de la caza

No parece tener un gran impacto en el puntaje general debido a lo poderoso que es el equipo de etiqueta azul, ¡pero al menos no empeoré las cosas!

Grita en las próximas 8 horas si quieres que agregue algo útil a mi mensaje.


El medio no es el mejor lugar para llamar la atención; muchos otros robots parecen rodear los bordes cuando buscan enemigos para luchar. ¿Quizás tu bot debería rodear el medio?
theonlygusti

Es más fácil evadir en el medio que en las esquinas, pero si dices que podría no encontrar compañeros en el medio ... bueno, tienes razón; mi causa de muerte número uno en este momento es que el rojo se vuelve un aliado antes que yo. ¡Para el próximo KotH, estoy listo para mejorar en gran medida la capacidad de llamar a otros bots para que me ayuden cuando encuentre un objetivo!
Hylianpuffball

Estoy trabajando en un bot llamado baliza; su mensaje contendrá las posiciones de cada enemigo y miembro del equipo en el campo, y luego puede ser utilizado por otros bots para rastrear y matar a dichos enemigos, o engancharse si son compañeros de equipo.
theonlygusti

4

Equipo Azul - PatrolBot

var directionMap = {'0,0':0, '0,1':1, '1,1':6, '1,0':null, '1,-1':3, '0,-1':2, '-1,-1':4, '-1,0':null, '-1,1':5},
    direction = parseInt((getMsg(38951) || getMsg(-1) || '').slice(0, 1));

if (typeof direction !== 'number' || isNaN(direction)) direction = 0;

if (!tNear.length && !eNear.length) {
    if (!isDirection(direction) || isNearWall(12, x, y)) {
        direction = moveTowardsCoords(64, 64, x, y, directionMap, eNear);
    } else {
        direction = direction;
    }
} else if (eNear.length) {
    if (canKill(x, y, eNear, directionMap)) {
        direction = kill(x, y, eNear, directionMap);
    } else if (isNearEnemy(x, y, eNear)) {
        direction = moveToBetterPosition(x, y, eNear, directionMap);
    } else if (tNear.length + 1 >= eNear.length) {
        direction = moveTowardsEnemy(eNear, x, y, directionMap);
    } else {
        if (tNear.length) {
            direction = moveTowardsTeam(tNear, x, y, directionMap);
        } else {
            direction = moveAwayFromEnemy(eNear, x, y);
        }
    }
} else if (tNear.length && Math.random() > 0.8) {
    direction = moveTowardsTeam(tNear, x, y, directionMap);
}

setMsg((direction || 0).toString());
return direction;

function find(arr, func) {
    for (var i = 0; i < arr.length; i++) {
        if (func(arr[i])) {
            return arr[i];
        }
    }
}

function invert(obj) {
    var result = {},
        key;

    for (key in obj) {
        if (obj.hasOwnProperty(key)) {
            result[obj[key]] = key;
        }
    }

    return result;
}

function isDirection(direction) {
    return direction >= 1 && direction <= 6;
}

function isNearWall(margin, x, y) {
    return x < margin || x > (127 - margin) || y < margin || y > (127 - margin);
}

function getDistance(x1, y1, x2, y2) {
    var xd, yd;

    xd = x2 - x1;
    xd = xd * xd;

    yd = y2 - y1;
    yd = yd * yd;

    return Math.sqrt(xd + yd);
}

function getCoordDiff(x1, y1, x2, y2) {
    return [x1 - x2, y1 - y2];
}

function identifyClosest(arr, x, y) {
    var lowest = 128;

    arr = arr.map(function(i) {
        i.distance = getDistance(x, y, i.x, i.y);
        return i;
    });

    arr.forEach(function(i) {
        if (i.distance < lowest) {
            lowest = i.distance;
        }
    });

    return find(arr, function(i) {
        return i.distance === lowest;
    });
}

function identifyClosestTeam(tNear, x, y) {
    return identifyClosest(tNear, x, y);
}

function identifyClosestEnemy(eNear, x, y) {
    return identifyClosest(eNear, x, y);
}

function kill(x, y, eNear, directionMap) {
    var enemy = identifyClosestEnemy(eNear, x, y);
    return enemy ? directionMap[getCoordDiff(enemy.x, enemy.y, x, y).toString()] : 0;
}

function canKill(x, y, eNear, directionMap) {
    return !!kill(x, y, eNear, directionMap);
}

function enemyCanKill(id, x, y, eNear) {
    var arr = ['1,0', '1,1', '1,-1', '-1,0', '-1,-1', '-1,1'],
        enemy = find(eNear, function(i) {
            return i.id === id;
        });

    if (!enemy) {
        return false;
    }

    return arr.indexOf(getCoordDiff(x, y, enemy.x, enemy.y).toString()) !== -1;
}

function isNearEnemy(x, y, eNear) {
    var enemy = identifyClosestEnemy(eNear, x, y);

    if (!enemy) {
        return 0;
    }

    return Math.max.apply(null, getCoordDiff(x, y, enemy.x, enemy.y).map(function(i){
        return Math.abs(i);
    })) <= 2;
}

function isIntoWall(dx, dy) {
    return dx > 127 || dx < 0 || dy > 127 || dy < 0;
}

/**
 * Picks a random direction heading towards {dx, dy}
 */
function moveTowardsCoords(destX, destY, oldX, oldY, directionMap, eNear) {
    return changeDirection(function(newX, newY) {
        return getDistance(oldX, oldY, destX, destY) - getDistance(newX, newY, destX, destY);
    }, oldX, oldY, eNear, directionMap);
}


function changeDirection (scoringFunction, x, y, eNear, directionMap) {
    var highest = 0,
        validDirections = (function() {
            var result = {};
            for (var key in directionMap) {
                if (directionMap.hasOwnProperty(key) && directionMap[key] !== null) {
                    result[key] = directionMap[key];
                }
            }
            return result;
        })(),
        coords = Object.keys(validDirections).map(function(i) {
            var result = {
                    vector: i,
                    score: 0
                },
                xy = i.split(',').map(function(term, i) {
                    return parseInt(term) + (i === 0 ? x : y);
                });

            result.x = xy[0];
            result.y = xy[1];

            result.score = scoringFunction(result.x, result.y, eNear, directionMap);

            if (result.score > highest) {
                highest = result.score;
            }

            return result;
        }),
        arr = coords.filter(function(i) {
            return i.score === highest;
        });

    var num = Math.floor(Math.random() * arr.length);

    return validDirections[arr[num].vector];
}

function moveTowards(id, x, y, tNear, eNear, directionMap) {
    var target = find([].concat(tNear, eNear), function(i) {
        return i.id === id;
    });

    if (target) {
        return moveTowardsCoords(target.x, target.y, x, y, directionMap, eNear);
    } else {
        return 0;
    }
}

function moveTowardsEnemy(eNear, x, y, directionMap) {
    var enemy = identifyClosestEnemy(eNear, x, y);

    return enemy ? moveTowards(enemy.id, x, y, [], eNear, directionMap) : 0;
}

function moveTowardsTeam(tNear, x, y, directionMap) {
    var team = identifyClosestTeam(tNear, x, y);

    return team ? moveTowards(team.id, x, y, tNear, [], directionMap) : 0;
}

function moveAwayFromEnemy(eNear, x, y) {
    var oppositeMap = {
        0: 0,
        1: 2,
        2: 1,
        3: 5,
        4: 6,
        5: 3,
        6: 4
    };
    return oppositeMap[moveTowardsEnemy(eNear, x, y, directionMap)];
}

/**
 * Gives points to each move based on three metrics:
 * 
 * 2) will not cause us to be killed next turn
 * 1) will let us kill next turn
 * 
 * Then randomly picks from the highest scoring moves
 */
function moveToBetterPosition(x, y, eNear, directionMap) {
    return changeDirection(function(x, y, eNear, directionMap) {
        var score = 0;

        if (canKill(x, y, eNear, directionMap)) {
            score += 1;
        }

        if (!eNear.some(function(e) {
                return enemyCanKill(e.id, x, y, eNear);
            })) {
            score += 2;
        }

        if (isIntoWall(x, y)) {
            score = 0;
        }

        return score;
    }, x, y, eNear, directionMap);
}

El código es una especie de autodocumentación. Cosas que podrían hacerse para mejorar PatrolBot

  • Refactor: mueva todo a IIFE, use variables de cierre en lugar de pasarlas veinte mil millones de veces.
  • Agregue if (canBeKilled() || isInWall()) { moveToBetterPosition() }justo antes de regresar.
  • Limpie el mal comportamiento al seguir a un miembro del equipo al lado de una pared.
  • Evite aterrizar en los miembros del equipo.
  • Aléjese del enemigo si está continuamente ocupado durante 200 turnos.

Este es un muy buen bot. Buen trabajo. Aquí están los resultados de una carrera de 100 rondas: chat.stackexchange.com/transcript/message/20949696#20949696
PhiNotPi

2

EQUIPO AZUL - 1 Punto Impresionante

//  1PointAwesome by Grant Davis

var myid=38941; //My ID for getMsg()

var result=0;
var leeway=1; //How close to follow enemy
var gForce=3; //How strongly gravity effects x/y
var futureDanger=true;
//Modifier Random Generation
var newX=Math.floor(Math.random()*3-1);
var newY=Math.floor(Math.random()*3-1);
var random10=Math.floor(Math.random()*2);

var dangerArray=[[false,false,false],[false,false,false],[false,false,false]];
var gravityX,gravityY,antiGravityX,antiGravityY;

//Sets defaults: gravity center
if(move==1){setMsg("64,64");}

//Change gravity when you have reached within 5 of gravity
if(eNear.length==0){
 if(Math.floor(Math.random()*2)==0){
  if(parseInt(getMsg(myid).split(",")[0])-x<5&&parseInt(getMsg(myid).split(",")[0])-x>-5){setMsg(Math.floor(Math.random()*32)+","+getMsg(myid).split(",")[1]);}
  if(parseInt(getMsg(myid).split(",")[1])-y<5&&parseInt(getMsg(myid).split(",")[1])-y>-5){setMsg(getMsg(myid).split(",")[0]+","+Math.floor(Math.random()*32));}
 }else{
  if(parseInt(getMsg(myid).split(",")[0])-x<5&&parseInt(getMsg(myid).split(",")[0])-x>-5){setMsg(Math.floor(Math.random()*32+96)+","+getMsg(myid).split(",")[1]);}
  if(parseInt(getMsg(myid).split(",")[1])-y<5&&parseInt(getMsg(myid).split(",")[1])-y>-5){setMsg(getMsg(myid).split(",")[0]+","+Math.floor(Math.random()*32+96));}
 }
}

//Pulls gravity from getMsg() and converts it into variables readable by the program
if(x<parseInt(getMsg(myid).split(",")[0])+Math.floor(Math.random()*30-15)){gravityX=1;antiGravityX=-1;}else{gravityX=-1;antiGravityX=1;}
if(y<parseInt(getMsg(myid).split(",")[1])+Math.floor(Math.random()*30-15)){gravityY=-1;antiGravityY=1;}else{gravityY=1;antiGravityY=-1;}

//Modifier Random Generation, Gravity bias.
if(Math.floor(Math.random()*gForce)!=0||x<31&&eNear.length==0||x>95&&eNear.length==0){newX=gravityX;}
if(Math.floor(Math.random()*gForce)!=0||y<31&&eNear.length==0||y>95&&eNear.length==0){newY=gravityY;}


//Avoid edges modifier:
//Sets gravity to 64,64 when within 32 of an edge

if(y<31&&eNear.length==0||y>95&&eNear.length==0){setMsg(getMsg(myid).split(",")[0]+",64");}
if(x<31&&eNear.length==0||x>95&&eNear.length==0){setMsg("64,"+getMsg(myid).split(",")[1]);}

//Targeting Modifier:
//Does not modify if outnumbered
//Tries to attack from above or below
//If enemy escapes: look where the enemy was last at
//Reset gravity if all targets

if(eNear.length<=tNear.length+1&&eNear.length!=0){

setMsg(eNear[0]["x"]+","+eNear[0]["y"]);
if(eNear[0]["x"]>x){newX=1;}else if(eNear[0]["x"]<x){newX=-1;}else{newX=0;}
if(eNear[0]["y"]>y+leeway){newY=-1;}else if(eNear[0]["y"]<y-leeway){newY=1;}
}



//Anti loop Modifier: Removed due to minor strategy flaw


//If I can get above or below a pixel, do it 


//If I can kill an enemy pixel, kill it
for(var ep=0;eNear.length>ep;ep+=1){

 if(eNear[ep]["x"]==x&&eNear[ep]["y"]-y==1){newY=-1;newX=0;}
 else if(eNear[ep]["x"]==x&&eNear[ep]["y"]-y==-1){newY=1;newX=0;}
 else if(eNear[ep]["x"]-x==-1){
  if(eNear[ep]["y"]-y==1){newX=-1;newY=-1;}
  else if(eNear[ep]["y"]-y==-1){newX=-1;newY=1;}
 }
 else if(eNear[ep]["x"]-x==1){
  if(eNear[ep]["y"]-y==1){newX=1;newY=-1;}
  else if(eNear[ep]["y"]-y==-1){newX=1;newY=1;}
 }
}

//Not allowed to move off screen.
if(x==0){for(var i=0;i<=2;i+=1){dangerArray[0][i]==true;}}
if(x==127){for(var i=0;i<=2;i+=1){dangerArray[2][i]==true;}}
if(y==0){for(var i=0;i<=2;i+=1){dangerArray[i][0]==true;}}
if(y==127){for(var i=0;i<=2;i+=1){dangerArray[i][2]==true;}}

var originalNewX=newX;
var originalNewY=newY;






//Double checks movement made by previous code, and then turns it into a number that Pixel Team Battlebots can read
for(var antiloop=0;futureDanger&&antiloop<20;antiloop+=1){

 futureDanger=false;


 //When bot tries to move left or right, it will move diagonal.
 if(newX!=0&&newY==0){
  newY=Math.floor(Math.random()*2);
  if(newY==0){newY=-1;}
 }


 if(eNear.length>0){ //Protocol Paranoid: When pixel attempts to move into dangerous square, The pixel will move into a different square, and recheck danger.




  for(var ep=0;ep<eNear.length;ep+=1){ //Checks for the danger level of the square pixel attempts to move in.

   if(Math.abs(eNear[ep]["x"]-(x+newX))==1 && eNear[ep]["y"]-(y-newY)<=1 && eNear[ep]["y"]-(y-newY)>=-1){
    futureDanger=true;

    dangerArray[newX+1][Math.abs(newY-1)]=true;
    if(dangerArray[1][1]==false){newX=0;newY=0;}//When attempt to move into dangerous square, do nothing
    else if(dangerArray[gravityX+1][gravityY+1]==false){newX=gravityX;newY=gravityY;}
    else if(dangerArray[antiGravityX+1][gravityY+1]==false){newX=antiGravityX;newY=gravityY;random10=1;}
    else if(dangerArray[gravityX+1][antiGravityY+1]==false){newX=gravityX;newY=antiGravityY;random10=0;}

    else if(dangerArray[antiGravityX+1][antiGravityY+1]==false){newX=antiGravityX;newY=antiGravityY;}
    else if(dangerArray[1][gravityY+1]==false){newX=0;newY=gravityY;}
    else if(dangerArray[1][antiGravityY+1]==false){newX=0;newY=antiGravityY;}
    else{newX=originalX;newY=originalY;}
   }
  }
 }else//End of Protocol Paranoid

 if(antiloop==18){newX=originalNewX;NewY=originalNewY;}

}//Big for end


if(newY==1){result=2;}else if(newY==-1){result=1;}

if(newX==1){if(result==2){result=3;}else if(result==1){result=6;}}else if(newX==-1){if(result==2){result=4;}else if(result==1){result=5;}}



return result;

Las prioridades del píxel:

  • Nunca se mueva a espacios peligrosos (fuera de los espacios encuadernados se consideran peligrosos)
  • Mata si puedes
  • Avanzar hacia el enemigo (el primero en eNear) siempre que no sea superado en número
  • Alejarse de los bordes
  • Ir a la última ubicación conocida de los enemigos
  • Ve a donde se encuentra la gravedad

La gravedad se establece en 64,64 en el movimiento 1

La gravedad se establece en la ubicación de los enemigos más cercanos (para guiar los píxeles a la ubicación del último enemigo, si el enemigo escapa)

La gravedad cambia aleatoriamente cuando el píxel ha alcanzado el centro de gravedad o cuando está cerca del borde


2

Rojo - LoyalFollower [15080]

var dangerValues = {
    killEnemy:      -110,
    killMe:          160,
    nearEnemy:       -20,
    killPair:       -200,
    friendIsThere:    30,
    outside:         999,
    nearWall:         10,
    wayToMinos:       -2,
    wayToFriend:      -1,
    wayToEnemy:       -4,
    wayToManyEnemies:  3
};

var moves = [
    {newX: x, newY: y, danger: 0},
    {newX: x + 1, newY: y, danger: 0},
    {newX: x - 1, newY: y, danger: 0},
    {newX: x + 1, newY: y - 1, danger: 0},
    {newX: x - 1, newY: y - 1, danger: 0},
    {newX: x - 1, newY: y + 1, danger: 0},
    {newX: x + 1, newY: y + 1, danger: 0}
];
var closestEnemy = null;
var closestFriend = null;

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

var meKillable = function(meX, meY, himX, himY) {
    return (Math.abs(meY - himY) === 1 && Math.abs(meX - himX) <= 1);
};

var enemyKillable = function(meX, meY, himX, himY) {
    return (Math.abs(meX - himX) === 1 && Math.abs(meY - himY) <= 1);
};

for (i = 0; i < moves.length; i++) {
    if (moves[i].newX < 0 || moves[i].newY < 0 || moves[i].newX > 127 || moves[i].newY > 127) {
        moves[i].danger = dangerValues.outside;
    }
    if (moves[i].newX === 0 || moves[i].newX === 127 || moves[i].newY === 0 || moves[i].newY === 127) {
        moves[i].danger += dangerValues.nearWall;
    }
    for (var j = 0; j < eNear.length; j++) {
        if (closestEnemy === null || distance(x, y, closestEnemy.x, closestEnemy.y) > distance(x, y, eNear[j].x, eNear[j].y)) {
            closestEnemy = eNear[i];
        }

        if (moves[i].newX === eNear[j].x && moves[i].newY === eNear[j].y) {
            if (eNear[j].id === 21487 || eNear[j].id === 2867) {
                moves[i].danger += dangerValues.killPair;
            } else {            
                moves[i].danger += dangerValues.killEnemy;
            }
        }
        if (meKillable(moves[i].newX, moves[i].newY, eNear[j].x, eNear[j].y)) {
            moves[i].danger += dangerValues.killMe;
        }
        if (enemyKillable(moves[i].newX, moves[i].newY, eNear[j].x, eNear[j].y)) {
            moves[i].danger += dangerValues.nearEnemy;
        }
    }
    for (var j = 0; j < tNear.length; j++) {
        if (closestFriend === null || distance(x, y, closestFriend.x, closestFriend.y) > distance(x, y, tNear[j].x, tNear[j].y)) {
            closestFriend = tNear[i];
        }
        if (moves[i].newX === tNear[j].x && moves[i].newY === tNear[j].y) {
            moves[i].danger += dangerValues.friendIsThere;
        }
    }
}

var bestDistanceToMinos = 200;
var minos = 38926;
var minosMsg = getMsg(minos);
var manyEnemies = eNear.length > tNear.length;
if (minosMsg !== '' && minosMsg !== undefined) {
    minosMsg = minosMsg.split(";");
    var minosPos = {posX: parseInt(minosMsg[0], 10), posY: parseInt(minosMsg[1], 10)};
    for (i = 0; i < moves.length; i++) {
        var distanceToMinos = distance(moves[i].newX, moves[i].newY, minosPos.posX, minosPos.posY);
        if (distanceToMinos < bestDistanceToMinos) {
            bestDistanceToMinos = distanceToMinos;
        }       
    }
}
for (i = 0; i < moves.length; i++) {
    if (minosMsg !== '' && minosMsg !== undefined) {
        var distanceToMinos = distance(moves[i].newX, moves[i].newY, minosPos.posX, minosPos.posY);
        if (distanceToMinos === bestDistanceToMinos) {
            moves[i].danger += dangerValues.wayToMinos;
        }
    }
    if (closestFriend != null && distance(moves[i].x, moves[i].y, closestFriend.x, closestFriend.y) < distance(x, y, closestFriend.x, closestFriend.y)) {
        moves[i].danger += dangerValues.wayToFriend;
    }

    if (closestEnemy != null && distance(moves[i].x, moves[i].y, closestEnemy.x, closestEnemy.y) < distance(x, y, closestEnemy.x, closestEnemy.y)) {
        moves[i].danger += manyEnemies ? dangerValues.wayToManyEnemies : dangerValues.wayToEnemy;
    }
}

var bestMove = null;
var leastDanger = 10000;
for (i = 0; i < moves.length; i++) {
    if (moves[i].danger < leastDanger || (moves[i].danger === leastDanger && Math.random() < 0.5)) {
        leastDanger = moves[i].danger;
        bestMove = i;
    }
}
var newX = ("000" + moves[bestMove].newX).substr(-3, 3);
var newY = ("000" + moves[bestMove].newY).substr(-3, 3);
setMsg(newX + ";" + newY);
return bestMove;

Intenta encontrar a Minos y matar enemigos. Lamentablemente, el equipo rojo todavía pierde, tal vez porque somos menos jugadores ...


2

Equipo Azul - MiddleMan

// MiddleMan by Mwr247

// Self identification
var id = 30793;

// Bounds
var minPos = 0;
var midPos = 63;
var maxPos = 127;

// Movesets
var up = [0, 4, 2, 3, 5, 1, 6];
var down = [0, 5, 1, 6, 4, 2, 3];
var left = [0, 4, 5, 2, 1, 3, 6];
var right = [0, 3, 6, 2, 1, 4, 5];

// Our grid
var points = [0, 0, 0, 0, 0, 0, 0];

// Point system
var bound = -100000;
var death = -5000;
var dodge = 500;
var evade_best = 100;
var evade_better = 50;
var evade_good = 25;
var evade_bad = -25;
var evade_worse = -50;
var evade_worst = -100;
var kill = 4900;
var enemy = 5;

// Message
var msg = [[], []];

// Normalize values
var norm = function(val) {
    return Math.max(-1, Math.min(1, Math.round(val)));
};

// Get detailed ent data
var data = function(ent) {
    var info = {};
    info.x = ent.x - x;
    info.y = ent.y - y;
    info.normX = norm(info.x);
    info.normY = norm(info.y);
    info.distX = Math.abs(info.x);
    info.distY = Math.abs(info.y),
    info.dist = Math.sqrt(Math.pow(info.x, 2) + Math.pow(info.y, 2))
    return info
};

// Set position value
var pos = function(dir, index, val) {
    points[dir[index]] += val;
};

// Set position value above/below
var ver = function(dir, val) {
    pos(dir, 1, val);
    pos(dir, 2, val * 1.001);
    pos(dir, 3, val);
};

// Set position value on the sides
var hor = function(dir, val) {
    pos(dir, 1, val);
    pos(dir, 2, val);
};

// Vertical bound logic
if (y === minPos) {
    ver(up, bound);
} else if (y === maxPos) {
    ver(down, bound);
}

// Horizontal bound logic
if (x === minPos) {
    hor(left, bound);
} else if (x === maxPos) {
    hor(right, bound);
}

// Enemy logic
if (eNear.length) {
    var tmp;
    for (var i = 0; i < eNear.length; i++) {
        // Add the enemy to the message data
        msg[1].push([eNear[i].x, eNear[i].y]);
        tmp = data(eNear[i]);
        // We're touching, either attack or evade
        if (tmp.distY <= 1 && tmp.distX <= 1) {
            var d;
            if (tmp.distX !== 0) { // If we are not right above/below, current position is a death zone
                pos(up, 0, death);
            }
            if (tmp.distY === 0) { // Dodge like heck
                if (tmp.normX > 0) {
                    hor(right, dodge);
                    hor(left, evade_best);
                } else if (tmp.normX < 0) {
                    hor(left, dodge);
                    hor(right, evade_best);
                }
                pos(up, 2, death);
                pos(down, 2, death);
            } else { // We are above or below; finish them!
                d = tmp.y > 0 ? down : up;
                pos(d, 2 + tmp.normX, kill);
                if (tmp.normX === 0) {
                    pos(d, 1, death);
                    pos(d, 3, death);
                } else {
                    pos(d, 2, death);
                }
            }
        } else if (tmp.distY <= 2 && tmp.distX <= 2) { // We're a spot away, don't get too close!
            var d;
            if (tmp.distY === 2) { // They are two below
                d = tmp.y === 2 ? down : up;
                if (tmp.distX === 0) { // Straight down
                    pos(d, 1, death);
                    pos(d, 3, death);
                    pos(d, 2, dodge);
                    pos(d, 5, evade_good);
                    pos(d, 0, evade_best);
                } else if (tmp.distX === 1) { // One to the side
                    pos(d, 2, death);
                    pos(d, 2 + tmp.normX, dodge);
                    pos(d, 5 + tmp.normX, evade_better);
                    pos(d, 5 - tmp.normX, evade_bad);
                    pos(d, 2 - tmp.normX, evade_worst);
                } else { // Diagonals
                    pos(d, 2 + tmp.normX, death);
                    pos(d, 5 + tmp.normX, evade_better);
                    pos(d, 5 - tmp.normX, evade_bad);
                    pos(d, 2, evade_worse);
                    pos(d, 2 - tmp.normX, evade_worst);
                }
            } else { // They are to the sides
                d = tmp.normX === 1 ? right : left;
                if (tmp.distY === 0) { // Straight out
                    hor(d, death);
                    pos(d, 3, evade_better);
                    pos(d, 4, evade_better);
                } else { // A little angled
                    pos(d, 1 + (tmp.normY > 0), death);
                    pos(d, 1 + (tmp.normY < 0), evade_best);
                }
            }
        }

        // If there's a horizontal enemy, head that way
        if (tmp.x > 0) {
            hor(right, enemy + 16 - tmp.x);
        } else if (tmp.x < 0) {
            hor(left, enemy + 16 - tmp.x);
        }
        // If there's a vertical enemy, head that way
        if (tmp.y > 0) {
            ver(down, enemy + 16 - tmp.y);
        } else if (tmp.y < 0) {
            ver(up, enemy + 16 - tmp.y);
        }
    }

    // If we're near an enemy, lets try to bring them towards our friends
    if (tNear.length) {
        for (var i = 0; i < tNear.length; i++) {
            tmp = data(tNear[i]);
            if (tmp.x > 0) { // Horizontal moves
                hor(right, 1 + (16 - tmp.x) / 4);
            } else if (tmp.x < 0) {
                hor(left, 1 + (16 - tmp.x) / 4);
            }
            if (tmp.y > 0) { // Vertical moves
                ver(down, 1 + (16 - tmp.y) / 4);
            } else if (tmp.y < 0) {
                ver(up, 1 + (16 - tmp.y) / 4);
            }
        }
    }
}

// If not fighting, be the middleman you really want to be
if (y < midPos) {
    ver(down, 1);
} else if (y > midPos) {
    ver(up, 1);
}

// Hang around the horizontal middle, safe from those nasty corners
if (x < midPos) {
    hor(right, 1);
} else if (x > midPos) {
    hor(left, 1);
} else {
    pos(up, 0, 0.1);
}

// Evaluate our grid and find the winning move
var max = 0;
for (var i = 1; i < points.length; i++) {
    // If a clear winner, go with that. If there's a tie, randomize to keep things fresh
    if (points[max] < points[i] || (points[max] === points[i] && Math.round(Math.random()))) {
        max = i;
    }
}

// Set our new coordinates
var nX = x + (max === 3 || max === 6) - (max === 4 || max === 5);
var nY = y + (max === 5 || max === 1 || max === 6) - (max === 4 || max === 2 || max === 1);
msg[0] = [nX, nY];

// Set our message
setMsg(JSON.stringify(msg));

// Return the highest value move
return max;

MiddleMan es el hermano gemelo de WallFlower (a quien reemplazó). Al igual que su hermano, no tiende a ser un tipo social. Prefiere pasar el rato en el medio de la habitación, mirando y esperando. Pero eso no quiere decir que sea pasivo o tímido. Mientras está en su lugar o camino a él, si encuentra un enemigo, sin importar el tamaño, cargará para enfrentarse a él. Sabiendo que hay fuerza en los números, con gusto los atraerá hacia cualquier compañero de equipo que encuentre o, alternativamente, hacia el centro con la esperanza de encontrar a otros. Una vez que termina su negocio, regresa a su lugar, listo para la próxima oportunidad de ayudar a su equipo.

Cuidado, equipo rojo. Si bien puede no parecer mucho, es tan feroz y persistente como parece; un maestro de la lucha cuerpo a cuerpo en solitario. Es posible que no se comunique directamente con su equipo, pero los reconoce y trabajarán juntos para derrotar al enemigo común. Recientemente aprendió a enviar mensajes, aunque él mismo no escuchará ninguno, solo que no es su estilo. El formato es una cadena JSON que contiene una matriz como esta: [[selfX,selfY],[[enemy1X,enemy1Y],[enemy2X,enemy2Y]]]y así sucesivamente para más enemigos.


1

Equipo azul : VersaBot, un motor polimórfico

Mi código seguirá automáticamente el bot más cercano cerca de él, proporcionando potencia de fuego y protección adicionales.

// VersaBot - The PolyMorphic Companion
// Copyright 2017.5 Sam Weaver
// For this SO challenge: http://codegolf.stackexchange.com/questions/48353/red-vs-blue-pixel-team-battlebots

//FUNctions
var randInt = function(min,max) {return Math.floor((Math.random() * ((max + 1) - min)) + min);};
var degrees = function(radians) {return radians * 180 / Math.PI;};

//variables
var me = 31743;
var friendId;

if(getMsg(me) == '') {
    friendId = 0;
    setMsg(friendId);
} else {
    friendId = getMsg(me);
}

//first, check if any teammates nearby
if(tNear.length > 0) {
    //loop through and see if friend is found
    var found = false;
    var fx,fy;
    for(var index in tNear) {
        var nearAlly = tNear[index];
        //check if friend
        if(nearAlly.id == friendId) {
            //yay, let's follow 'em
            fx = nearAlly.x;
            fy = nearAlly.y;
            found = true;
            break;
        }
    }
    if(!found) {
        //pick the first friend to be a new friend
        friendId = tNear[0].id;
        fx = tNear[0].x;
        fy = tNear[0].y;
    }

    //NOW, let's follow'em
    //get the radian angle in relation to me
    var radAngle = Math.atan2(fy-y,fx-x);
    //to degrees we go!
    //console.log('friend');
    var deg = Math.floor(degrees(radAngle));
    //now reverse it so it works
    deg = -1*deg;


    //we can return the right direction now
    if(deg > 120) {
        return 4; //up left
    } else if(deg > 60) {
        return 2; //up
    } else if(deg > 0) {
        return 3; //up right
    } else if(deg < -120) {
        return 5; //down left
    } else if(deg < -60) {
        return 1; //down
    } else if(deg < 0) {
        return 6; //down right
    }
    //for some reason?
    return 0;

} else {
    //pick a random direction
    return randInt(1,6);
}

¡Disfrutar!

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.