Este é um jogo de captura da bandeira, fortemente inspirado e baseado em Red vs. Blue - Pixel Team Battlebots . Essa foi uma pergunta impressionante (muito obrigado pelos Calvin's Hobbies; espero que você não se importe de eu ter roubado vergonhosamente muito código de você) - aqui está outro rei do monte. Felizmente, capturar a bandeira exigirá mais cooperação da equipe e mais estratégia.
Para confundir, você é considerado na equipe vermelha se o último dígito do seu ID estiver entre 0
e 4
inclusive. Isso deve impedir que exatamente as mesmas equipes lutem novamente, se as mesmas pessoas decidirem responder. O conselho é 350px
por 350px
. O time azul começa na metade superior do tabuleiro e o time vermelho começa na metade inferior.
A maneira como você joga captura a bandeira é a seguinte: o objetivo do jogo é pegar a bandeira do time adversário e trazê-la de volta para o seu lado. Se você estiver do lado deles, poderá ser marcado e enviado para a prisão. Se você estiver preso, não poderá se mover. Se você está do seu lado, seu trabalho é marcar os membros da equipe adversários para enviá-los para a cadeia. A única maneira de sair da cadeia é alguém da sua equipe que é livre para marcar todos na cadeia. (Observe que a prisão está localizada no lado da equipe adversária).
Especificamente:
- Há uma constante -
FIELD_PADDING
- definida como 20. Esse é o preenchimento do campo. Se fosse zero, as bandeiras e a prisão estariam exatamente nos cantos da tela. Como não está, a bandeira e a prisão estão a 20 pixels dos cantos. - A bandeira azul (lembre-se: a equipe azul está na metade superior) está localizada no
(WIDTH - FIELD_PADDING, FIELD_PADDING) = (330, 20)
canto superior direito. - A bandeira vermelha está em
(FIELD_PADDING, HEIGHT - FIELD_PADDING) = (20, 330)
- A prisão azul (onde os membros vermelhos são mantidos) fica no
(20, 20)
lado azul, no canto superior esquerdo. - A prisão vermelha, onde os membros azuis são mantidos, está em
(330, 330)
Todo membro da equipe começa aleatoriamente em uma posição 45 < x < 305
e 45 < y < 175
para azul e 175 < y < 305
vermelho. Nenhum membro da equipe pode ficar dentro de DEFENSE_RADIUS = 25
pixels de sua própria bandeira ou prisão (a não ser, é claro, que sua própria bandeira tenha sido tomada por um bot oponente; nesse caso, você precisará marcá-lo). Isso é para evitar a guarda de filhotes como bots. Se você for dentro desse intervalo, será "empurrado" para trás. Da mesma forma, nenhum membro da equipe pode sair dos limites (menos que zero ou mais que 350) - se você o fizer, será empurrado de volta para o local legal mais próximo que puder.
Toda vez que você se move, você gasta strength
. Você strength
começa 20
e é reabastecido a 2
cada turno. A quantidade de força que você usa é igual à distância que você viaja. Se sua força se tornasse negativa ao se mudar para um determinado lugar, você será impedido de fazer esse movimento. Provavelmente, é uma boa ideia simplesmente acelerar 2
a perseguição normal. Você só deve usar velocidades mais altas se estiver perto de ganhar e precisar de velocidade extra (na minha opinião).
Especificação :
A especificação é bastante semelhante à pergunta Pixel Team Battlebots. Você deve escrever um bloco de código (lembre-se, sem variáveis globais) em javascript. Ele deve retornar um objeto com os valores x
-value e y
-value representando sua alteração nos valores de xe y. A seguinte resposta:
return {
x: 0,
y: -2
};
sempre sobe, até atingir uma parede. Você não pode editar 8 horas após a postagem (exceto LegionMammal98, que pensou que o controlador não estava carregando seu código e não testou) . Você tem acesso às seguintes variáveis no seu código:
this
- você mesmo, como jogador (veja abaixo o que os jogadores são)move
- o número da rodada, começando em 0tJailed
- uma matriz de todos os jogadores do seu time que estão presoseJailed
- uma matriz de todos os jogadores da equipe adversária que estão presosteam
- uma variedade de todos os jogadores do seu time, não apenas os que estão perto de vocêenemies
- uma variedade de todos os jogadores do outro time, NÃO apenas aqueles perto de vocêtFlag
- sua bandeira (você está tentando protegê-la)eFlag
- a outra bandeira (você está tentando roubá-la)messages
- explicado abaixo- A lista de constantes:
WIDTH = 350
,HEIGHT = 350
,FIELD_PADDING = 20
,DEFENSE_RADIUS = 25
.
Todo "jogador" é um objeto com as seguintes propriedades:
x
ey
strength
id
isJailed
- verdadeiro se o jogador estiver preso
Cada sinalizador possui as seguintes propriedades:
x
ey
pickedUpBy
- o jogador que atualmente tem a bandeira ou nulo se nenhum jogador tiver a bandeira.
Agora, messages
é um objeto que é compartilhado entre seus colegas de equipe. Eu não ligo para o que você faz com isso. O mesmo objeto é compartilhado e passado para todos os membros da sua equipe. Essa é a única maneira de se comunicar. Você pode anexar propriedades a ele, compartilhar objetos etc. Pode ser do tamanho que você deseja - sem limite de tamanho.
A cada turno acontece o seguinte:
- A lista de jogadores (vermelho e azul) é aleatoriamente aleatória para ordem dos turnos.
- Todo jogador faz um movimento.
- Se algum membro vermelho da equipe tocar (a menos de 10 pixels de) de algum membro azul do lado vermelho, envie-o para a cadeia e vice-versa. Um jogador preso deixa sua bandeira cair e sua força cai para zero. Observe que a função step (código que você fornece) ainda é chamada - para que você possa receber / definir mensagens, mas não pode se mover enquanto estiver na prisão.
- Se algum jogador estiver tocando (dentro de 10 pixels) da outra bandeira, a outra bandeira será marcada como "apanhada por" esse jogador. Quando o jogador se move, a bandeira se move - até que o jogador seja identificado e vá para a cadeia, ou seja.
- Se algum jogador estiver tocando na prisão do outro lado, liberte todos na prisão. Quando um jogador é libertado da prisão, ele / ela é teleportado para um local aleatório do seu lado.
Dicas:
- Pelo menos na captura regular da bandeira, os ataques funcionam muito melhor quando muitos jogadores vão ao mesmo tempo, porque isso tende a confundir os defensores quanto a qual jogador eles devem perseguir.
- Da mesma forma, os defensores podem querer coordenar quem estão perseguindo para que os ataques não passem
Fragmento de pilha:
window.onload=function(){(function(){function p(a,b,c,e){return Math.sqrt((a-c)*(a-c)+(b-e)*(b-e))}function l(a,b){this.x=this.y=0;this.id=a.id;this.title=a.title+" ["+this.id+"]";this.link=a.link||"javascript:;";this.team=b;this.isJailed=!1;this.flag=null;this.moveFn=new Function("move","tJailed","eJailed","team","enemies","tFlag","eFlag","messages","WIDTH","HEIGHT","FIELD_PADDING","DEFENSE_RADIUS",a.code);this.init()}function x(a,b){return Math.floor(Math.random()*(b-a))+a}function q(a,b){this.startX=this.x=a;this.startY=
this.y=b;this.following=null}function t(a,b){return a===e&&b||a===h&&!b?{x:20,y:20}:{x:g.width-20,y:g.height-20}}function y(){var a,b=$("#redTeam"),c=$("#blueTeam");for(a=0;a<e.length;++a)e[a].addToDiv(b);for(a=0;a<h.length;++a)h[a].addToDiv(c)}function z(){d.clearRect(0,0,g.width,g.height);d.beginPath();d.moveTo(0,g.height/2);d.lineTo(g.width,g.height/2);d.stroke();var a=e.concat(h),b,c;for(b=a.length-1;0<b;b--){c=Math.floor(Math.random()*(b+1));var f=a[b];a[b]=a[c];a[c]=f}for(b=0;b<a.length;++b)a[b].step(u);
for(b=0;b<e.length;++b)for(c=0;c<h.length;++c)10>p(e[b].x,e[b].y,h[c].x,h[c].y)&&(e[b].y<g.height/2&&e[b].goToJail(),h[c].y>g.height/2&&h[c].goToJail());for(b=0;b<a.length;++b)c=a[b].team===e!==!0?m:n,!c.following&&10>p(a[b].x,a[b].y,c.x,c.y)&&(c.following=a[b]);for(b=0;b<a.length;++b)if(c=t(a[b].team,!0),!a[b].isJailed&&10>p(a[b].x,a[b].y,c.x,c.y))for(c=a[b].team,f=0;f<c.length;++f)c[f].isJailed&&(c[f].isJailed=!1,c[f].init());m.follow();n.follow();b=m.y<g.height/2;c=n.y>g.height/2;b&&c&&alert("EXACT TIE!!!! This is very unlikely to happen.");
b&&!c&&(alert("Blue wins!"),$("#playpause").click().hide());c&&!b&&(alert("Red wins!"),$("#playpause").click().hide());for(b=0;b<a.length;++b)a[b].draw(d);m.draw("red");n.draw("blue");u++}$.ajaxSetup({cache:!1});var e=[],h=[],g=$("canvas")[0],d=g.getContext("2d"),v,u=0,m={},n={},r=!0,A={},B={},w;l.prototype.init=function(){this.x=x(45,g.width-45);this.y=x(45,g.height/2);this.team===e&&(this.y+=g.height/2);this.strength=20};l.prototype.makeShallowCopy=function(){return{x:this.x,y:this.y,strength:this.strength,
id:this.id,isJailed:this.isJailed}};l.prototype.goToJail=function(){this.isJailed=!0;var a=this.team===e!==!0?m:n;(this.team===e!==!0?m:n).following===this&&(a.following=null);a=t(this.team,!0);this.x=a.x;this.y=a.y;this.strength=0};l.prototype.step=function(a){function b(a,b,c){var e,d,f;for(e=0;e<a.length;++e)d=a[e],d!==C&&(f=d.makeShallowCopy(),d.isJailed?b.push(f):c.push(f))}var c=[],f=[],d=[],k=[],l=this.team===e?h:e,C=this,q=this.team===e?m:n,r=this.team===e?n:m;b(this.team,c,d);b(l,f,k);f=
this.moveFn.call(this.makeShallowCopy(),a,c,f,d,k,q.copy(),r.copy(),this.team===e?A:B,g.width,g.height,20,25);"object"===typeof f&&"number"===typeof f.x&&"number"===typeof f.y&&(d=p(0,0,f.x,f.y),a=t(this.team,!1),c=this.team===e!==!1?m:n,d<=this.strength&&(this.strength-=d,this.x+=f.x,this.y+=f.y,0>this.x&&(this.x=0),0>this.y&&(this.y=0),this.x>g.width&&(this.x=g.width),this.y>g.height&&(this.y=g.height),f=p(this.x,this.y,c.x,c.y),d=p(this.x,this.y,a.x,a.y),25>f&&null===c.following&&(this.x=25*(this.x-
c.x)/f*1.3+c.x,this.y=25*(this.y-c.y)/f*1.3+c.y),25>d&&(this.x=25*(this.x-a.x)/d*1.3+a.x,this.y=25*(this.y-a.y)/d*1.3+a.y)),this.isJailed||(this.strength+=2),20<this.strength&&(this.strength=20))};l.prototype.addToDiv=function(a){var b=$("<option>").text(this.title).val(this.id);a.find(".playersContainer").append(b)};l.prototype.draw=function(a){a.fillStyle=this.team===e?"red":"blue";a.beginPath();a.arc(this.x,this.y,5,0,2*Math.PI,!0);a.fill();!this.isJailed&&$("#labels").is(":checked")&&a.fillText(this.title,
this.x+5,this.y+10)};q.prototype.draw=function(a){d.strokeStyle=a;d.beginPath();d.arc(this.x,this.y,5,0,2*Math.PI,!0);d.stroke();d.fillStyle=a;d.strokeRect(this.x-2,this.y-2,4,2);d.beginPath();d.moveTo(this.x-2,this.y);d.lineTo(this.x-2,this.y+3);d.stroke()};q.prototype.copy=function(){return{x:this.x,y:this.y,pickedUpBy:this.following&&this.following.makeShallowCopy()}};q.prototype.follow=function(){null!==this.following&&(this.x=this.following.x,this.y=this.following.y)};$("#newgame").click(function(){function a(a,
b){w?b(w):$.get("https://api.stackexchange.com/2.2/questions/"+(49028).toString()+"/answers",{page:a.toString(),pagesize:100,order:"asc",sort:"creation",site:"codegolf",filter:"!JDuPcYJfXobC6I9Y-*EgYWAe3jP_HxmEee"},b,"json")}function b(g){w=g;g.items.forEach(function(a){function b(a){return $("<textarea>").html(a).text()}var d=4>=a.owner.user_id%10?e:h;a.owner.display_name=b(a.owner.display_name);if(!(a.hasOwnProperty("last_edit_date")&&28800<a.last_edit_date-a.creation_date&&33208!==a.owner.user_id||
-1<p.indexOf(a.owner.user_id))){p.push(a.owner.user_id);var g=c.exec(a.body);if(!(null===g||1>=g.length)){var f={};f.id=a.owner.user_id;f.title=a.owner.display_name;f.code=b(g[1]);f.link=a.link;d.push(new l(f,d))}}});g.has_more?a(++d,b):(console.log("Red team",e),console.log("Blue team",h),y(),clearInterval(v),r=!0,$("#playpause").show().click())}var c=/<pre><code>((?:\n|.)*?)\n<\/code><\/pre>/,d=1,p=[];e=[];h=[];u=0;m=new q(20,g.height-20);n=new q(g.width-20,20);$(".teamColumn select").empty();var k=
$("#testbotCode").val();0<k.length&&(console.log("Using test entry"),k={title:"TEST ENTRY",link:"javascript:;",code:k},$("#testbotIsRed").is(":checked")&&(k.id=-1,e.push(new l(k,e)),k.id=-3,e.push(new l(k,e))),$("#testbotIsBlue").is(":checked")&&(k.id=-2,h.push(new l(k,h)),k.id=-4,h.push(new l(k,h))));a(1,b)});$("#playpause").hide().click(function(){r?(v=setInterval(z,25),$(this).text("Pause")):(clearInterval(v),$(this).text("Play"));r=!r})})();}
#main{padding:10px;text-align:center}#testbot{padding:10px;clear:both}.teamColumn{width:25%;padding:0 10px;border:3px solid;border-color:#000;text-align:center;height:500px;overflow:scroll;white-space:nowrap}.playersContainer p{padding:0;margin:0}#redTeam{float:left;border-color:red;color:red;background-color:#fee}#blueTeam{float:right;border-color:#00f;color:#00f;background-color:#fee}#arena{display:inline-block;width:40%;text-align:center}canvas{border:1px solid #000}select{width:100%}
<script src=https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js></script><div id=main><div class=teamColumn id=redTeam><h1>Red Team</h1><select size=20 class=playersContainer></select></div><div id=arena><h1>Battlefield</h1><canvas width=350 height=350></canvas></div><div class=teamColumn id=blueTeam><h1>Blue Team</h1><select size=20 class=playersContainer></select></div><div id=loadingInfo><button id=newgame>New Game</button> <button id=playpause>Play</button><br><input type=checkbox id="labels"> Show labels</div></div><div id=testbot><textarea id=testbotCode placeholder="testbot code"></textarea><br><input type=checkbox id="testbotIsRed">Red Team<br><input type=checkbox id="testbotIsBlue">Blue Team<br></div>
Controlador: http://jsfiddle.net/prankol57/4L7fdmkk/
Controlador de tela cheia: http://jsfiddle.net/prankol57/4L7fdmkk/embedded/result/
Deixe-me saber se há algum erro no controlador.
Nota: Se você for ao controlador e achar que ele não está carregando nada, pressione "Novo Jogo". Ele carrega tudo depois que você pressiona "Novo jogo" para carregar todos os bots e possíveis bots de teste de uma só vez.
Boa sorte.
Se alguém quiser ver um exemplo de jogo, criei um exemplo de bot que você pode copiar e colar na área de texto "testbot" (o testbot cria duas duplicatas em cada equipe; verifique a equipe vermelha e a equipe azul):
var r2 = Math.sqrt(2);
if (this.id === -1) {
// red team 1
// go after flag regardless of what is going on
if (eFlag.pickedUpBy !== null && eFlag.pickedUpBy.id === this.id) {
return {
x: 0,
y: 2
};
}
return {
x: this.x < eFlag.x ? r2 : -r2,
y: this.y < eFlag.y ? r2 : -r2
};
}
if (this.id === -2) {
// blue team 1
// a) go after opposing team members on your side b) get the other flag if no enemies on your side
var closestEnemy = null;
for (var i = 0; i < enemies.length; ++i) {
if (enemies[i].y < HEIGHT/2 && (closestEnemy === null || enemies[i].y < closestEnemy.y)) {
closestEnemy = enemies[i];
}
}
if (closestEnemy !== null) {
return {
x: this.x < closestEnemy.x ? r2 : -r2,
y: this.y < closestEnemy.y ? r2 : -r2
};
}
if (eFlag.pickedUpBy !== null && eFlag.pickedUpBy.id === this.id) {
return {
x: 0,
y: -2
};
}
return {
x: this.x < eFlag.x ? r2 : -r2,
y: this.y < eFlag.y ? r2 : -r2
};
}
if (this.id === -3) {
// red team 2
// a) defend the flag b) if at least half of enemies in jail and no enemies on this side, free jailed reds and quickly return
var closestEnemy = null;
for (var i = 0; i < enemies.length; ++i) {
if (enemies[i].y > HEIGHT/2 && (closestEnemy === null || enemies[i].y > closestEnemy.y)) {
closestEnemy = enemies[i];
}
}
if (closestEnemy !== null) {
return {
x: this.x < closestEnemy.x ? r2 : -r2,
y: this.y < closestEnemy.y ? r2 : -r2
};
}
if (enemies.length / eJailed.length <= 1 && tJailed.length > 0) {
return {
x: this.x < FIELD_PADDING ? r2 : -r2,
y: this.y < FIELD_PADDING ? r2 : -r2
};
}
if (this.y < 350/2) return {x: 0, y: 2};
return {
x: this.x < tFlag.x ? r2 : -r2,
y: this.y < tFlag.y ? r2 : -r2
};
}
if (this.id === -4) {
// blue team 2
// a) try freeing jail if there are jailed team members b) capture the flag
if (tJailed.length > 0) {
return {
x: this.x < WIDTH - FIELD_PADDING ? r2 : -r2,
y: this.y < HEIGHT - FIELD_PADDING ? r2 : -r2
};
}
if (eFlag.pickedUpBy !== null && eFlag.pickedUpBy.id === this.id) {
return {
x: 0,
y: -2
};
}
return {
x: this.x < eFlag.x ? r2 : -r2,
y: this.y < eFlag.y ? r2 : -r2
};
}