Красный против Синего - Пиксельные Командные Боевые Боты

133

Этот конкурс официально завершен. Синяя команда победила!

Я произвел два сета по 50 битв, и удивительно, что Blue выиграл все 100 из них. Глядя на статистику, становится ясно, что совместные записи PhiNotPi и Sp3000 были настоящими героями. Отличная работа, вы двое! Фактически, если вы дисквалифицируете любого другого члена Синей Команды , Сфиботы все равно будут вести очень хороший бой . Некоторые члены Красной команды планировали уничтожить Сфиботов, но это усилие, казалось, прекратилось. Извините, Красная Команда.

Конкурс официально завершен, но это не значит, что вы больше не можете отвечать, это лишь означает, что я никогда не буду повторно объявлять официального победителя. Обе команды могут отправлять ботов, просто для удовольствия. Контроллер останется включенным и будет функционировать до тех пор, пока его не нарушат никакие будущие записи.


Это состязание царя горы , но вместо всех, кто сражается друг против друга, будут соревноваться две команды: Красная и Синяя. Только один будет победителем.

Команда, в которую вы входите, зависит от вашего идентификационного номера PPCG . Чтобы найти это, нажмите на свой аватар в верхней части экрана (вы должны войти в систему) и посмотрите на URL открывшейся страницы. Число после users/вашего идентификационного номера:

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

Например, мой идентификатор пользователя PPCG - 26997:

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

Обратите внимание, что это число отличается для разных сайтов Stack Exchange.

Если у вас четное число , значит вы в команде Red .
Если у вас нечетное число , значит, вы в команде Blue .
Нет возможности сменить команду.

Вы должны работать со своей командой, чтобы попытаться победить другую команду в своего рода королевской битве, где каждый пользователь контролирует «пиксель» цвета своей команды на сетке 128 × 128, которая является полем битвы. Пиксели могут перемещаться, общаться со своими товарищами по команде и снимать пиксели другой команды. Было бы плохо, если бы кто-нибудь мог создать любое количество пикселей, поэтому каждый пользователь может отправить только один ответ на этот вопрос.

Этот фрагмент стека (уменьшенная версия этой скрипки [ fullscreen ]) является контроллером для всего соревнования. Он автоматически читает представленные материалы, проверяет их правильность и устраивает сражения между командами. Он делает это прямо в вашем браузере в любое время, используя JavaScript . Поскольку JavaScript является единственным языком сценариев на стороне клиента, который поддерживается большинством браузеров, все представления должны быть также написаны на 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>

Для наглядности поле битвы Сниппета масштабируется в 3 раза, поэтому оно составляет 384 × 384 реальных пикселей, а «пиксели» - 3 × 3.

Pixel Team Battlebots - Обзор

игроки

Каждый действительный ответ на этот вопрос представляет игрока . (Подробнее о действительности см. «Правила и дисквалификации» .) Каждый игрок имеет контроль над одной ячейкой 1 × 1 (она же пиксель) на поле битвы 128 × 128 . У игроков красной команды красные пиксели, а у синих - синие.

Сражения

Битва борьба между всеми игроками обеих команд, даже если команды не имеют одинаковое количество игроков. Битва начинается с того, что каждый игрок находится на случайной позиции на поле битвы, то есть с любой целочисленной координатой от (0,0) в верхнем левом углу до (127,127) в нижнем правом углу. Гарантируется, что никакие два игрока не начнут игру в одной и той же позиции.

Ходы

Каждое сражение разбито на 2048 ходов . Только одна команда может перемещать своих игроков во время каждого хода. Эта команда чередуется взад-вперед от красного до синего, поэтому каждая команда делает 1024 хода (если игра не заканчивается раньше).

Команда, которая должна двигаться первым - это опция, которую вы должны установить в контроллере.
Когда сражения запускаются автоматически, команда, которая движется первой, чередуется в каждом сражении.

Ход игрока

Когда команда движется, все игроки этой команды должны двигаться сами. Эти вызовы выполняются в абсолютно случайном порядке для каждого хода. При вызове каждому игроку предоставляется информация о состоянии битвы, чтобы он мог решить, каким путем двигаться.

Все ходы находятся на расстоянии до одного пикселя. Темные круги на этих диаграммах отмечают, в какие позиции каждый цветной игрок (квадраты) может перейти:

Красная команда движется диаграмма Синяя команда движется диаграмма

Оба цвета могут двигаться по диагонали в любом направлении или оставаться на месте, но только красные игроки могут двигаться вправо и влево, и только синие игроки могут двигаться вниз и вверх. Спасибо Фи и другим.

Если игрок пытается выйти за пределы поля битвы, или слишком долго решает, в каком направлении двигаться, или имеет какую-то ошибку, он автоматически останется на месте.

Помимо перемещения, во время хода игрок может читать сообщения, написанные его товарищами по команде, и писать сообщения, которые, в свою очередь, могут быть прочитаны. Это позволяет грубую форму командного общения.

Код, который вы отправляете в качестве ответа, представляет собой логику, которая определяет, каким образом перемещать проигрыватель и какие сообщения читать и писать (см. «Как ответить» ).

Удаление Вражеских Игроков

Когда игрок входит в ту же ячейку, что и игрок в противостоящей команде, этот противоборствующий игрок немедленно удаляется из битвы. Игрок, который только что переехал, продолжает игру как обычно. Это единственный механизм, который удаляет игроков из битвы, и овладение им является ключом к победе!

Если в ячейке есть несколько вражеских игроков, в которых только что перешел игрок, то все вражеские игроки удаляются. Ничего не происходит, если два игрока в одной команде занимают одну и ту же клетку.

Выиграть битву

Битва заканчивается, когда все 2048 ходов сделаны или когда в одной команде не осталось игроков. Команда с наибольшим количеством выживших игроков побеждает. Это ничья, если в обеих командах одинаковое количество выживших игроков.

Как ответить

В своем ответе вам необходимо предоставить код JavaScript, который решает, в каком направлении будет перемещаться ваш пиксель, когда для этого потребуется.

В первом примере кода с отступом в вашем ответе (префикс с 4 пробелами) напишите тело для этой функции:

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

Там нет необходимости играть в гольф ваш код.

Что вернуть

Возвращаемое значение функции определяет, в каком направлении движется ваш пиксель:

0оставаться неподвижным,
1чтобы двигаться вправо для красной команды, вниз для голубой команды,
2чтобы двигаться влево для красной команды, вверх для голубой команды,
3чтобы двигаться по диагонали вверх и вправо,
4чтобы двигаться по диагонали вверх и влево,
5чтобы двигаться по диагонали вниз и влево,
6чтобы двигаться по диагонали вниз и вправо

В виде диаграммы:

переместить диаграмму возвращаемых значений

Ваш пиксель останется неподвижным по умолчанию, если ваш код выполняет одно из следующих действий:

  • Возвращает все, кроме целого числа от 0 до 6.
  • Попытки вывести пиксель за пределы поля боя.
  • Занимает более 15 миллисекунд.
  • Выбрасывает любые исключения.

Ваша запись не должна быть детерминированной; использование Math.randomв порядке.

Параметры

Первые 7 функциональных параметров moveMeдают информацию о состоянии битвы:

  • move целое число, которое начинается с 1 и увеличивается после каждого хода, пока не станет 1024 на последнем ходу вашей команды.
  • x ваша текущая позиция х, целое число от 0 (крайний левый) до 127 (крайний правый).
  • y ваша текущая позиция у, целое число от 0 (самый верхний) до 127 (самый нижний).
  • tCount текущее общее количество выживших игроков в вашей команде.
  • eCount текущее общее количество выживших игроков вражеской команды.
  • tNearэто список текущих выживших игроков в вашей команде, которые находятся на расстоянии менее 16 пикселей (евклидово расстояние). Каждый элемент tNearпредставляет собой объект с x, yи idсвойствами:
    • x х позиция другого игрока
    • y позиция у другого игрока
    • id является идентификатором пользователя PPCG другого игрока (в виде целого числа)
  • eNearточно так же, как tNearтолько список вражеских игроков, а не товарищей по команде.

Круги в фрагменте каждого игрока tNearи eNearдиапазон.

Сообщения

Последние 2 параметра, setMsgи getMsg, имеют несколько иное назначение.

В течение битвы у каждого игрока есть до 64 символов, которыми они могут манипулировать во время каждого хода, чтобы хранить данные и потенциально общаться со своими товарищами по команде. Строка каждого игрока начинается с пустой строки. Когда игрок удаляется из битвы, его строка устанавливается на «X».

  • setMsg является функцией с одним аргументом, которая устанавливает вашу строку в строку, переданную в.
    • Если переданное значение не является строкой, то ваша строка не изменяется.
    • Если значение является строкой с более чем 64 символами, сохраняются только первые 64 символа.
  • getMsg это функция с одним аргументом, которая берет идентификационный номер пользователя PPCG (в виде целого числа) кого-то из вашей команды и возвращает его строку.
    • Этот игрок может быть где угодно в сетке. Они не должны быть в вашем радиусе 16 пикселей.
    • undefined возвращается, если данный идентификатор не найден.

Пример представления

Этот игрок движется вверх и вправо, если есть враг слева, или вниз и влево, если товарищ по команде с ID 123 говорит, но в остальном остается неподвижным:

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

Обратите внимание, что этот блок кода - это все, что требуется. Определение функции и скобки не должны присутствовать.

Правила и дисквалификации

Если пользователь не соблюдает правила, перечисленные ниже, я могу пометить их как дисквалифицированных, и контроллер автоматически проигнорирует их ответы. Я верю, что большинство пользователей здесь не будут намеренно нарушать правила, и будет только несколько временных дисквалификаций по случайным причинам.

Важные правила

  1. Вы можете редактировать свой ответ только в течение 8 часов после публикации.
    Ответы, отредактированные через 8 часов после их публикации, будут автоматически дисквалифицированы контроллером. Это правило запрещает первоначальным ответам постоянно оптимизировать свой подход, возможно, крадя идеи из более поздних ответов. Ваша команда должна делать то, с чего она начинала.

    Вы не можете удалять и публиковать свой ответ без специального разрешения. Я дам это, если кто-то случайно отредактирует ваш пост после 8-часовой отметки или что-то в этом роде, но не только потому, что вы нашли ошибку.

    Если вы удалите свое сообщение и решите его удалить, правило редактирования будет по-прежнему применяться. (Контроллер не может видеть удаленные ответы.)

  2. При объявлении новой переменной JavaScript вы должны использовать varключевое слово.
    Это связано с тем, что переменная, объявленная без, varстановится глобальной, а не локальной, поэтому было бы легко случайно (или намеренно) связываться с контроллером или свободно общаться с другими игроками. Должно быть ясно, что вы не пытаетесь обмануть.

    При объявлении функций лучше всего использовать varключевое слово. т.е. использовать var f = function(...) {...}вместо function f(...) {...}. Я не совсем уверен, почему, но иногда кажется, что это что-то меняет.

  3. Ваш код не должен выполняться слишком много времени.
    Если ваш код выполняется более 15 миллисекунд, ваш пиксель не будет двигаться вообще. Однако, поскольку в JavaScript трудно остановить выполнение функций в середине, все сценарии игрока выполняются до конца при каждом движении, а время проверяется позже. Это означает, что если ваш код требует много времени, все , кто работает с контроллером, заметят это и будут раздражены.

Автоматическая дисквалификация

Контроллер автоматически дисквалифицировал записи по следующим причинам:

  • Пользователь уже ответил.
  • Изменения были сделаны более чем через 8 часов после создания.
  • Пользователь специально помечен как дисквалифицированный.

Другие правила

В вашем коде вы не можете ...

  • попытаться получить доступ или изменить контроллер или код другого игрока.
  • попытаться изменить что-либо встроенное в JavaScript.
  • пытаться общаться с другими игроками, кроме как с помощью getMsgи setMsg.
  • делать веб-запросы.
  • делать иначе злые вещи.

Я буду следить за другим неспортивным поведением, таким как кража дословного кода из других ответов или использование марионеток с носками, чтобы связываться с другой командой.

Вы можете сотрудничать и составить схему со своей командой, но примите участие в конкурсе дружелюбно и этично.

Если вы считаете, что кто-то должен быть дисквалифицирован, или считаете, что вы исправили причину, по которой вы были дисквалифицированы, оставьте комментарий здесь для меня или в чате по конкретному вопросу . Я не участвую в конкурсе.

Предлагаемый формат ответа

#[team color] Team - [entry title]

    //function body
    //probably on multiple lines

Explanations, notes, etc.

Заголовок записи - это необязательное имя, которое вы можете дать, если хотите. Контроллер ничего с этим не делает.

счет

Этот конкурс будет официально завершен 19 апреля 2015 года. В этот день (около 23:00 по Гринвичу) я буду автоматически запускать не менее 100 боев (возможно, еще больше в зависимости от того, сколько времени займет сражение). Команда, которая победит больше всего, будет абсолютным победителем. Если это ничья или очень близко, я буду проводить больше сражений, пока не станет ясно, что одна команда имеет преимущество.

(Вы можете ответить после определения победителя, но я не буду менять официальный результат.)

Я буду использовать их в последней версии Google Chrome на ноутбуке с 64-битной Windows 8.1, 4 ГБ оперативной памяти и четырехъядерным процессором 1,6 ГГц. Убедитесь, что ваш JavaScript работает в Chrome.

Победа, прежде всего, в командной славе, но я приму самый высокий голос за команду-победителя.

На протяжении всего конкурса имейте в виду, что командный аспект и тот факт, что он полностью выполняется в фрагменте стека, являются очень экспериментальными. У меня большие надежды, но я не могу точно сказать, насколько хорошо все будет работать.

Подсказки:

  • Вы можете проверить записи, прежде чем ответить. Отредактируйте текстовое поле «Тестовая запись» в нижней части фрагмента стека и нажмите «Перезагрузить с тестовой записью». Если он не пуст, он становится игроком указанной команды.
  • Ответы запускаются в замаскированном объеме, поэтому такие вещи, как alertи console.logне будут работать. consoleОбъект может быть использован только в записи теста.
  • Отметьте «Отладочные сообщения» в нижней части фрагмента стека и посмотрите на консоль вашего браузера (F12). Много полезной информации печатается во время сражений.
  • Вы можете использовать Meta Sandbox как своеобразную площадку для постановки. Ответы там, конечно, разные, чем здесь, и контроллер там может устареть.
  • Поскольку это не официальное приложение Stack , контроллер может прекратить загрузку ответов для вас, если вы перезапустите его более 300 раз в день.

«Продолжение» этого задания : Блочная сборка ботов!

Быстрые ссылки

Fiddle Controller    Полноэкранный режим    Общий чат    Красный чат    (Blue Chat?)    SandboxPost

Кальвин Хобби
источник
51
Вы проделали потрясающую работу, соединив все это.
Алекс А.
6
Все, пожалуйста, используйте чат для не критичных комментариев.
Увлечения Кэлвина
4
Красная команда координирует свою работу в этом чате: chat.stackexchange.com/rooms/22548/…
Адам Дэвис,
5
Помоги мне, я абсолютно влюблен в это. Пожалуйста, расскажите об этом всем разработчикам, которых вы знаете.
Hylianpuffball
3
@HelkaHomba Привет! Просто хотел сообщить, что редакция сообщества по некоторым ответам дисквалифицировала их.
Стивен

Ответы:

52

Синяя команда - 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;
    }
}

Этот бот образует пару с ботом Sp3000 .

Основная идея заключается в том, что два бота, расположенные рядом друг с другом, помогают скрыть слабости друг друга, так что ни один бот не имеет открытой стороны. Это помогает защитить от угроз и ограничить возможности побега цели.

В начале игры они движутся навстречу друг другу и образуют пару. Эта пара затем движется как единое целое, причем один бот ведет другого. Два бота имеют практически идентичный код, что позволяет им обменивать позиции и роли в случае необходимости.

В режиме ожидания боты перемещаются по доске в поисках врагов. Как только они обнаруживают врага, они осторожно маневрируют в правильные позиции для атаки. Очень аккуратная особенность - способность формации двигаться прямо по горизонтали, достигаемая наличием ботов в разных местах.

PhiNotPi
источник
9
О, Боже! Как только они образуют пару, для красных это автоматическая потеря.
Минос
@Minos В значительной степени, да :)
theonlygusti
Я думал о том, чтобы написать похожего бота для красных, но раньше не удосужился, теперь мне нужно придумать стратегию, которая сможет победить дуэт.
Нить
Для справки , я видел, что есть место, где varне используется в этом посте и Sp3000. Они сразу присваивают j0, и это не мешает контроллеру, так что, к счастью, в этом случае это не проблема.
Увлечения Кэлвина
47

Синяя команда - 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;
    }
}

Этот бот образует пару с ботом PhiNotPi . Смотрите сообщение Фи для краткого объяснения нашей стратегии.

Sp3000
источник
Ой! Хороший ..
DoubleDouble
21

Красная Команда - 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;

Наивысшим приоритетом SeekerBot является выживание. Следовательно, он будет рассматривать только ходы, которые не поставят его под угрозу быть убитым в следующем ходу (пока существуют такие ходы).

Когда противники не видны, они будут перемещаться по полю битвы, что обеспечит регулярную дистанцию ​​обзора большей части земли.

Если SeekerBot обнаружит врага, он будет двигаться к нему. Если он может убить врага, он будет делать это до тех пор, пока ход спасен.

Если он не может убить врага, но враг может убить его в следующий ход, SeekerBot попытается заманить врага к другу (если он виден). Если ни один из членов команды не виден, он попытается перейти в положение, где он может убить врага в следующем ходу. Если это не сработает 5 раз подряд, он переключит тактику и начнет двигаться в случайном порядке, возможно, снова приблизившись к врагу в следующем раунде.

Для чего он стоит, он будет использовать первые 7 символов сообщения, чтобы выкрикнуть свою собственную позицию в формате «x; y» (где x и y дополняются нулями).

Это, конечно, не самый чистый код, но он, кажется, делает то, что я ожидал от него.

Минос
источник
2
Вы убиваете!
Увлечения Кэлвина
2
Вы приводили красную команду к победе каждый раз, когда я ее запускаю. Будет интересно посмотреть, что будут делать два новых синих бота, когда они объединятся.
Адам Дэвис
Очень интересно наблюдать за этим убийством блюза :)
TheNumberOne
@AdamDavis Эти два голубых бота координируются безумно; каждую игру, которую я смотрел до сих пор, они побили!
theonlygusti
12

Красная Команда - Грумба

// 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;

Заметки в комментариях.

Адам Дэвис
источник
3
Не используйте self. Эта переменная зарезервирована для указания window.self. Используйте I(заглавная I) вместо. Или me. Или даже myself.
Исмаэль Мигель
11

Красная Команда - Ленивый Убийца

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;

Это самое основное, что я мог получить. Это больше не является базовым на 100%.

Это только двигается, ЕСЛИ ТРЕБУЕТСЯ .

Если пользователь отправляет сообщение с двумя числами между -1и 1(например:) '1,0', разделенными запятой, оно переместится туда. Это полностью доверяет своим товарищам по команде.

Это теперь общается через JSON. Он имеет очень базовую структуру:

  • getMsg:
    • a: определяет действие:
      • 0: стоп
      • 1: переместить
    • м: движение отправить
      • {x: n, y: n}: объект с x и y, между -1 и 1
      • необработанное значение, которое будет возвращено с числом, представленным в сетке.
  • setMsg:
    • a: указывает, переместился ли он или остановился;
    • o: массив с моей старой позицией;
    • m: необработанное движение, возвращаемое кодом;
    • id: если заказ был соблюден, у него будет удостоверение личности виновного;
    • e: список всех позиций противника. Каждая позиция смещена на 32, чтобы избежать непечатаемых символов. Используйте string.charCodeAt (i) -32, чтобы получить позицию противника. Это будет строка с четной длиной. У каждого врага будет 2 символа.

Пример сообщения для управления им:

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

Который отправит:

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

Он также немного эгоистичен и не поможет тебе и теперь он полезен как стационарный маяк.

Если это сообщение неправильное (формат неправильный), попробуйте добавить "}вместо }.


Это было отредактировано после 6-часового лимита, и после того, как было расширено до 8.

Это больше не сломано и останется как окончательная версия.

Исмаэль Мигель
источник
2
Как кто-то из красной команды, я думаю, что одна важная вещь, которую мы должны включить, это всегда устанавливать сообщение с вашим текущим состоянием и окружением в какой-то согласованной форме объекта (это должно включать то, на какое движение это было установлено, в противном случае выиграли боты '). не знаю, какое состояние устарело). Это позволит другим, более поздним ботам знать больше, чем их собственное окружение, возможно, всю доску, и принимать лучшие решения.
Нить
@ Нет, я согласен с вами, и именно поэтому я выбрал JSON для общения. У меня есть 5 часов и 22 м, чтобы внести изменения. есть еще идеи?
Исмаэль Мигель
1
Я думаю, что первые несколько должны быть сканерами. Нам нужно только четыре, чтобы развернуть из стороны в сторону, чтобы покрыть всю доску (32 эффективных ширины сканирования покрывают 1/4 платы). Перемещайтесь из стороны в сторону, устанавливайте ближайших N плохих парней, используя двоичную или сжатую строку, и либо избегайте плохих парней, либо ищите и убивайте плохих парней, используя разумную стратегию, чтобы не быть убитым (никогда не позволяйте им входить в свой угол, ни выше, ни ниже вы?).
Адам Дэвис
1
@IsmaelMiguel Нету. Я также надеюсь представить его в ближайшее время, но не зная, что Javascript замедляет меня.
Адам Дэвис
3
Если это не сломано, удалите старые устаревшие комментарии, чтобы уменьшить беспорядок.
Нить
10

Красная Команда - Трус

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);
        }
    }
}

Этот бот остается неподвижным, чтобы избежать его обнаружения в максимально возможной степени. Когда один или несколько врагов видны, может произойти несколько вещей:

  • Если в поле зрения больше врагов, чем бот и его союзники, он пытается убежать от ближайшего врага.
  • Если в поле зрения больше друзей, чем врагов, численное превосходство придает боту смелости и пытается идти вперед и атаковать врага.
  • Если он может убить врага рядом с ним, он будет пытаться, независимо от того, сколько там дружественных и вражеских ботов, всегда пытаться оказаться в клетке, которая не может быть атакована другим ботом.
  • Если все враги защищены другими врагами, пытается бежать.
  • Если он не может никуда идти, потому что все позиции могут быть атакованы, входит в режим камикадзе и пытается хотя бы взять кого-нибудь с ним в могилу.

Ни с кем не общается, если кто-то может его услышать и пойти за ним.

Возможно, это не самый полезный бот для команды, но было забавно наблюдать, как он пытается уйти от всех.

rorlork
источник
Хорошо, я люблю твоего бота. Мой - своего рода противоположность (он ищет врагов и затем бежит к центру), поэтому у них есть фантастическое взаимодействие, где мой может попытаться дразнить вас из угла и перетащить его в середину, но затем, если ваш видит кого-то, он испугается и бежит обратно в угол, пока мой преследует его.
Hylianpuffball
Спасибо! Мне смешно видеть, как он взаимодействует с другими. Но я нашел пару ошибок, касающихся границ и того, как они отскакивают, но слишком поздно, чтобы их исправить ... Так что это не так хорошо, как хотелось бы.
rorlork
9

Синяя команда - Орел

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;
}

Я вполне доволен своим ботом в данный момент. Он имеет следующую тактику:

  • Если поблизости нет врагов, двигайтесь в случайном направлении. Если я ударился о стену или примерно через 33 хода, я сменил направление.
  • Если я вижу врага, я двигаюсь к нему. (Осторожно, чтобы не перейти на поле, где враг может меня убить). Как только я подойду достаточно, подойдите к нему сверху или снизу и убейте.
Jakube
источник
7

Синяя команда - 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);

Этот маленький пиксель ищет окружающие его окружения и пытается съесть его, если вокруг него нет пикселя, который движется в случайном направлении. Я с нетерпением жду, чтобы увидеть, что придумают другие народы.

Loovjo
источник
Извините, последний раз, когда я кодировал JavaScript, было как 2 года назад.
Loovjo
2
Math.floorнет Math.float!
января
1
@Jakube Или (Math.random() * 6) & 6или (Math.random() * 6) << 0или (Math.random() * 6) >> 0 (полезно для Codegolf).
Исмаэль Мигель
Вам не нужно делать Math.random() * 7? Я пробовал несколько тестовых прогонов, и кажется, что ваш бот не идет внизу справа. IIRC Math.random()включает 0 и 1, что означает, что * 6никогда не бывает 6.
Destrictor
1
Извините всех, я сосу на JavaScript.
Loovjo
7

Красная команда - Jittery Red Charger

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;

Red Charger движется только влево и вправо, надеясь использовать неспособность Blue Team двигаться в этих направлениях. Достигнув стены, он поворачивается и атакует в противоположном направлении, надеясь вслепую уничтожить любых ботов на своем пути.

РЕДАКТИРОВАТЬ: Red Charger только что выпил галлон энергетического напитка и теперь не может перестать дрожать, он надеется использовать это также в своих интересах. В нем слишком кофеин, чтобы слушать своих товарищей по команде, но он кричит каждый из своих шагов.

Вопросительные знаки
источник
6

Синяя команда - 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;
}
Dieter
источник
Вы знаете, сколько байтов обычно занимает JSON-сообщение? Только первые 64 символа сообщения могут быть сохранены.
PhiNotPi
.. Я забыл об этом ограничении :(
Дитер
Я предполагаю, что это будет зависеть от количества противников, так как строка json включает в себя позиции ближайшего eminems
dieter
Я меняю формат прямо сейчас
Дитер
1
Вы должны поместить это JSON.parseв блок try / catch или что-то ... это вызывает слишком много ошибок.
12Me21
6

Синяя команда - массовый убийца

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);

Я предполагаю довольно простую тактику. Я считаю врагов, которых я непосредственно могу достать (полагаю, их будет множество :)) и убиваю наибольшее количество. Если их нет, по крайней мере, я попытаюсь защитить себя, ступая выше или ниже наибольшего количества врагов, надеющихся убить их следующим шагом.

Я отказался от учета стен, поэтому просто игнорирую их. Все равно довольно долго.

Я не смог протестировать / запустить этот код, поэтому будет много ошибок.

Эрлик
источник
5

Синяя команда - 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())]);

Он двигается случайным образом, пока не схватит союзника, если он следует за ним. Он пытается избежать быть убитым, и убить, если он может. Извините за ужасный код, я пошел прямо и забыл о рефакторинге. Я постараюсь улучшить читаемость, если у меня будет время :)

Ударил
источник
5

Красная Команда - Искатель Командир

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;

Это копия SeekerBot от Minos с несколькими модификациями.

  • Сжатая внутренняя память для лучшего распределения сообщений "$":[seekmode]

  • Читает вражеские позиции от союзников, используя формат JSON Lazy Slayer's "e":"[positions]"; принимает [positions]смещение как 32и174

  • Сообщает о позициях противника в формате JSON Lazy Slayer, "e":"[positions]"смещенное на174

  • Сообщает последний ход, "m":[move]чтобы указать, что этим ботом можно командовать

  • Выдает команды другим ботам, используя "[ally_id]":{"m":[move],"a":1,"id":29354}. Команда использует тот же алгоритм поиска, за исключением местоположения союзника. Если другие боты слушают эти приказы, они должны сгруппироваться и охотиться в стае. Заказы выдаются только если сообщение союзника включает"m":

  • Следует командам других ботов, таких как: "29354":[move]или "29354":{"m":[move]. Команды выполняются только тогда, когда нет врагов в радиусе действия, и другие союзники не сообщают о врагах.

Wasmoo
источник
Я бы рекомендовал увеличивающиеся координаты на 174 вместо 32. Некоторые сообщения , которые Ленивый убийца отправлял были как: ""a":0,"o":[122,70],"m":0,"e":"f"". Вы можете присоединиться к нам в чате, если хотите.
TheNumberOne
Увы, у меня нет времени. Я проверю еще раз позже сегодня вечером, но это будет так. Я обновил пост, чтобы использовать кодировку 174, как для публикации, так и для анализа.
Wasmoo
5

Красная Команда - 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;

Мой бот подпрыгивает от стены к стене (не совсем так, так что он покрывает другую землю) в поисках врагов. Если он получает один в своем диапазоне, он атакует, тащит их к стене и пытается их убить (подумайте, вышибала в дубинке).

NinjaBearMonkey
источник
5

Красная Команда - 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;

Любит следить за товарищами по команде, хорошо, что их много!

DoubleDouble
источник
Забавно отметить, что когда это объединяется с ботом Васму, иногда он может победить синий дуэт.
Нит
1
@ Нет, я не был свидетелем этого; но я предполагаю, что мое становится отвлечением для Васму, чтобы убить их? Хотел бы я добавить к этому сейчас; Я попытался бы предсказать несколько ходов вперед и посмотреть, какая тактика самоубийств может сработать против дуэта.
DoubleDouble
5

Синяя команда - нерешительный магнит

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;
        }
    }
}

У него есть несколько стратегий: если он может немедленно победить врага, он сделает это, и он убежит от групп врагов, если они будут достаточно далеко, иначе он будет сражаться. Кроме этого он просто ищет членов команды и пытается следовать за ними.

flawr
источник
4

Синяя команда - выборка [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;

[редактирует: оказывается, это работает намного лучше, когда я использую свой фактический идентификатор, а не -1!]

Тупой маленький бот, который бегает по доске, делает все возможное, чтобы привлечь внимание и привлечь преследователей, а затем побежит к середине, где (надеюсь) он найдет кого-нибудь, чтобы помочь ему, или он просто остановит преследователя и остановит его с охоты.

Похоже, что это не оказывает большого влияния на общий счет из-за того, насколько сильна команда Blue Tagteam, но, по крайней мере, я не ухудшил ситуацию!

Кричите в течение следующих 8 часов, если вы хотите, чтобы я добавил что-нибудь полезное в мое сообщение.

Hylianpuffball
источник
Середина - не лучшее место для привлечения внимания; многие другие боты, кажется, окружают края, когда ищут врагов для боя. Может быть, ваш бот должен кружить посередине?
theonlygusti
В середине легче уклониться, чем в поворотах, но если вы говорите, что я не могу найти партнеров по команде в середине ... ну, вы правы; Моя причина смерти №1 сейчас заключается в том, что красный получает союзника раньше, чем я. Для следующего KotH я готов значительно улучшить способность вызывать других ботов за помощью, когда я нашел цель!
Hylianpuffball
Я работаю над ботом под названием Beacon; это сообщение будет содержать информацию о позициях каждого врага и члена команды на поле, а затем может быть использовано другими ботами для отслеживания и убийства указанных врагов или захвата, если товарищи по команде.
theonlygusti
4

Синяя команда - 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);
}

Код является своего рода самодокументированием. Что можно сделать, чтобы улучшить PatrolBot

  • Рефакторинг - Переместите все в IIFE, используйте переменные из замыкания вместо передачи их двадцать миллионов раз.
  • Добавить if (canBeKilled() || isInWall()) { moveToBetterPosition() }только до возвращения.
  • Убирайте плохое поведение, когда следите за членом команды рядом со стеной.
  • Избегайте посадки на членов команды.
  • Отойдите от врага, если непрерывно участвуете в течение 200 ходов.
Эштонская война
источник
Это очень хороший бот. Отличная работа. Вот результаты из 100 раундов: chat.stackexchange.com/transcript/message/20949696#20949696
PhiNotPi
2

ГОЛУБАЯ КОМАНДА - 1 очко

//  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;

Приоритеты пикселя:

  • Никогда не перемещайтесь в опасные места (вне связанных мест считается опасным)
  • Убей если сможешь
  • Двигайтесь к врагу (первому в eNear), пока не будете в меньшинстве
  • Отойти от краев
  • Перейти к врагам последней известной локации
  • Идите туда, где находится гравитация

Гравитация установлена ​​на 64,64 на 1-м ходу

Гравитация устанавливается для местоположения ближайших врагов (чтобы направлять пиксель к местоположению последнего врага, если враг убегает)

Гравитация изменяется случайным образом, когда пиксель достигает центра тяжести или когда он приближается к краю

Грант Дэвис
источник
2

Красный - 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;

Пытается найти Миноса и убить врагов. К сожалению, красная команда все еще проигрывает, возможно, потому что мы меньше игроков ...

CommonGuy
источник
2

Синяя команда - 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 - брат-близнец WallFlower (которого он заменил). Как и его брат, он не склонен быть социальным парнем. Он предпочел бы просто посидеть посреди комнаты, наблюдая и ожидая. Но это не значит, что он пассивен или робок. Находясь на своем месте или на пути к нему, если он найдет врага, независимо от его размера, он примет на себя ответственность, чтобы победить его. Зная, что в численности есть сила, он с удовольствием потянет их к любым товарищам по команде, которых он найдет, или, наоборот, к центру в надежде найти других. Как только его бизнес закончен, он возвращается на свое место, готовый к следующей возможности помочь своей команде.

Осторожно, красная команда. Хотя он может показаться не таким уж большим, он такой же яростный и настойчивый, как и они; мастер ближнего боя в одиночном бою. Он может не общаться напрямую со своей командой, но он признает их и будет работать вместе, чтобы победить общего врага. Недавно он научился отправлять сообщения, хотя сам не будет слушать, только не в своем стиле. Формат представляет собой строку JSON, содержащую массив, подобный следующему: [[selfX,selfY],[[enemy1X,enemy1Y],[enemy2X,enemy2Y]]]и т. Д. Для большего количества врагов.

Mwr247
источник
1

Blue Team - VersaBot, полиморфный движок

Мой код будет автоматически следовать ближайшему боту рядом с ним, обеспечивая дополнительную огневую мощь и защиту.

// 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);
}

Наслаждайтесь!

Сэм Уивер
источник