visão global
Esta é uma batalha de robôs para ver quem consegue sobreviver por mais tempo. Esses robôs aumentam seu poder ao serem atacados, portanto, você precisa pensar com cuidado antes de atirar.
A cada turno, você pode escolher um bot para atacar ou defender. Atacar diminuirá sua vida e aumentará seu poder. O último bot em pé vence.
Bots
Cada bot começa com 1000 pontos de vida e 10 de poder.
Quando atacado:
- o poder do seu atacante é subtraído da sua vida
- seu poder aumenta em 1.
Portanto, se no primeiro turno, você for atacado por dois bots, terá 980 de vida e 12 de poder.
Se você optar por defender:
- seu poder será reduzido em 1
- todos os ataques contra você neste turno serão reduzidos pela metade
- se você for atacado, você ganhará 2 de poder por cada atacante em vez de 1
Portanto, se você defender no primeiro turno e for atacado por dois bots, terá 990 pontos de vida e 13 de poder. Se você defender e não for atacado, terá 1000 pontos de vida, mas 9 de poder.
Se no final de um turno sua potência estiver abaixo de um, ele será definido para um. Se sua vida é inferior a 1, você morre.
Entrada / Saída
Bots são chamados uma vez por turno. Há um limite de tempo de um segundo para cada turno.
Inicial
A primeira vez que seu bot é chamado, ele não recebe argumentos. Responder com ok
. Isso é feito apenas para garantir que seu bot responda. Caso contrário, não será adicionado à lista de jogadores.
Cada turno
A cada turno, seu bot recebe informações sobre todos os bots no jogo como argumentos de linha de comando. Um exemplo desses argumentos é:
1 0,1000,10,1 1,995,11,D
O primeiro argumento é o ID único do seu bot. Em seguida, uma lista de bots separada por espaço é exibida. Cada bot é formatado como:
id,life,power,lastAction
lastAction
pode ser um número inteiro representando qual bot eles atacaram, D
se defenderam e X
se esta é a primeira vez. Os outros são todos números inteiros.
Então, no exemplo acima, você é bot 1
e defendido no seu último turno. Bot 0
atacou você e ainda está iniciando saúde / poder.
A saída para cada turno é muito simples. Basta imprimir o bot que você deseja atacar como um número inteiro (por exemplo, 0
ou 3
) ou D
defender. Não ataque bots mortos ou inexistentes, pois isso conta como um comando inválido. Qualquer comando inválido resultará na perda de 1 poder.
Estrutura do torneio
Cada jogo consiste em todos os bots a partir de 1000 pontos de vida e 10 de poder. Ações de todos os bots são executadas simultaneamente. O número máximo de turnos para um jogo é 1000.
Se no final do turno houver um bot que permanece vivo (vida> 0), ele marca um ponto e outro jogo é iniciado. Se o limite do turno for atingido e houver vários bots ativos, ninguém ganha um ponto. Se todos os bots restantes morrerem no mesmo turno, ninguém ganha um ponto.
Um torneio consiste em 15 jogos. Quem tiver mais pontos no final vence! Os laços são quebrados pela soma da vida útil restante em cada jogo ganho.
Estado
Os bots podem apenas ler ou gravar em um único arquivo com o nome próprio, em uma subpasta direta chamada state
("Hero" pode gravar state/hero.whatever
). Este arquivo não deve exceder 1024 2 bytes de tamanho. Tome cuidado para observar o prazo. Seu programa deve terminar em um segundo para contar, e não apenas dar uma resposta.
Esses arquivos serão apagados antes de cada torneio, mas persistirão de jogo para jogo. Todos os identificadores de bot ( id
) também permanecerão os mesmos entre os jogos.
Controlador
Abaixo está o controlador do torneio ( Stronger.java
). Por padrão , ele produz apenas os resultados finais (lista classificada de jogadores, vencedor no topo), o que pode demorar um pouco. Não está congelado, apenas silencioso. Se você desejar uma saída mais detalhada, adicione o -log
argumento ao executar.
Para adicionar bots, você tem duas opções:
adicione o comando como argumento (
java Stronger -log "python bot.py"
)adicione o comando
defaultPlayers[]
no source ("python bot.py"
)
Os robôs Hero , Bully e Coward podem ser encontrados nesta resposta e serão usados para fins de pontuação.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
public class Stronger {
static final String[] defaultPlayers = {
"java Hero",
"java Bully",
"java Coward"
};
final int timeout = 1000;
final int startLife = 1000;
final int startPower = 10;
final int numRounds = 15;
boolean log = false;
List<Player> players;
public static void main(String[] args){
new Stronger().run(args);
}
void run(String[] args){
init(args);
for(int i=0;i<numRounds;i++){
Collections.shuffle(players);
runGame();
}
Collections.sort(players);
for(Player player : players)
System.out.println(player.toString());
}
void runGame(){
log("Player Count: " + players.size());
for(Player player : players)
player.reset();
int turn = 0;
while(turn++ < startLife){
if(aliveCount() < 2)
break;
log("Turn " + turn);
List<Player> clones = new ArrayList<Player>();
for(Player player : players)
clones.add(player.copy());
for(Player player : players){
if(player.life < 1 || player.timedOut)
continue;
String[] args = new String[players.size()+1];
args[0] = "" + player.id;
for(int i=1;i<args.length;i++)
args[i] = players.get(i-1).toArgument();
String reply = getReply(player, args);
Player clone = player.findCopyOrMe(clones);
if(reply.equals("T")){
clone.timedOut = true;
clone.life = 0;
}
clone.lastAction = reply.trim();
}
for(Player player : players){
if(player.life < 1 || player.timedOut)
continue;
Player clone = player.findCopyOrMe(clones);
if(clone.lastAction.equals("D")){
clone.power--;
}else{
try{
int target = Integer.parseInt(clone.lastAction);
for(Player t : players)
if(t.id == target && t.life < 1)
throw new Exception();
for(Player tclone : clones){
if(tclone.id == target){
int atk = player.power;
if(tclone.lastAction.equals("D")){
atk -= player.power / 2;
tclone.power++;
}
tclone.life -= atk;
tclone.power++;
}
}
} catch (Exception e){
log(player.cmd + " returned an invalid command: (" + clone.lastAction + ")");
clone.power--;
}
}
}
players = clones;
for(Player player : players){
if(player.power < 1)
player.power = 1;
log(player.life + "\t\t" + player.power + "\t\t(" + player.id + ")\t" + player.cmd);
}
log("\n");
}
if(aliveCount() == 1)
for(Player player : players)
if(player.life > 0){
player.scoreRounds++;
player.scoreLife += player.life;
}
}
void log(String msg){if(log)System.out.println(msg);}
String getReply(Player player, String[] args){
try{
List<String> cmd = new ArrayList<String>();
String[] tokens = player.cmd.split(" ");
for(String token : tokens)
cmd.add(token);
for(String arg : args)
cmd.add(arg);
ProcessBuilder builder = new ProcessBuilder(cmd);
builder.redirectErrorStream();
long start = System.currentTimeMillis();
Process process = builder.start();
Scanner scanner = new Scanner(process.getInputStream());
process.waitFor();
String reply = scanner.nextLine();
scanner.close();
process.destroy();
if(System.currentTimeMillis() - start > timeout)
return "T";
return reply;
}catch(Exception e){
e.printStackTrace();
return "Exception: " + e.getMessage();
}
}
void init(String[] args){
players = new ArrayList<Player>();
for(String arg : args){
if(arg.toLowerCase().startsWith("-log")){
log = true;
}else{
Player player = createPlayer(arg);
if(player != null)
players.add(player);
}
}
for(String cmd : defaultPlayers){
Player player = createPlayer(cmd);
if(player != null)
players.add(player);
}
}
Player createPlayer(String cmd){
Player player = new Player(cmd);
String reply = getReply(player, new String[]{});
log(player.cmd + " " + reply);
if(reply != null && reply.equals("ok"))
return player;
return null;
}
int aliveCount(){
int alive = 0;;
for(Player player : players)
if(player.life > 0)
alive++;
return alive;
}
static int nextId = 0;
class Player implements Comparable<Player>{
int id, life, power, scoreRounds, scoreLife;
boolean timedOut;
String cmd, lastAction;
Player(String cmd){
this.cmd = cmd;
id = nextId++;
scoreRounds = 0;
scoreLife = 0;
reset();
}
public Player copy(){
Player copy = new Player(cmd);
copy.id = id;
copy.life = life;
copy.power = power;
copy.scoreRounds = scoreRounds;
copy.scoreLife = scoreLife;
copy.lastAction = lastAction;
return copy;
}
void reset(){
life = startLife;
power = startPower;
lastAction = "X";
timedOut = false;
}
Player findCopyOrMe(List<Player> copies){
for(Player copy : copies)
if(copy.id == id)
return copy;
return this;
}
public int compareTo(Player other){
if(scoreRounds == other.scoreRounds)
return other.scoreLife - scoreLife;
return other.scoreRounds - scoreRounds;
}
public String toArgument(){
return id + "," + life + "," + power + "," + lastAction;
}
public String toString(){
String out = "" + scoreRounds + "\t" + scoreLife;
while(out.length() < 20)
out += " ";
return out + "(" + id + ")\t" + cmd;
}
}
}
Regras
Você pode inserir até dois bots. Se você deseja remover um do jogo para inserir um terceiro, exclua sua postagem.
Você não pode segmentar ou destacar um bot por meta-análise. Use apenas as informações fornecidas pelo seu bot. Isso inclui seus próprios bots; portanto, você não pode inserir dois bots que conspiram.
Não tente interferir com o funcionamento do controlador ou de outros robôs.
Seu bot não pode instanciar ou executar o controlador ou outros bots.
Resultados
(de bots enviados em 22/05/2015 00: 00: 00Z)
Esta rodada de jogo foi um pouco melhor, com apenas dois jogos parando em 1000 turnos. Parabéns a Santayana , de Ralph Marshall , que ficou em primeiro lugar, sendo o único bot que conseguiu três vitórias. Isso não foi suficiente, então ele também ficou em terceiro lugar com o Tactician . Stormcrow ficou em segundo lugar com Phantom Menace , um ótimo primeiro post aqui. No geral, tivemos uma exibição muito agradável de novos membros, com os seis primeiros lugares indo para pessoas com menos de cinco postagens. Parabéns e bem-vindo ao site!
Os robôs que obtiveram zero vitórias não são listados para economizar espaço. Todos os bots postados antes do carimbo de data / hora acima foram executados. Portanto, se você não vê o seu, ele não ganha nada.
Wins Life(tiebreaker) Name
3 561 perl Santayana.pl
2 850 java PhantomMenace
2 692 perl Tactician.pl
2 524 java Wiisniper
1 227 java Tank
1 184 java Velociraptor
1 7 java Coward
1 3 java IKnowYou
Controlador paralelo esboçado de Sorta ( por outros ):
import java.lang.ProcessBuilder.Redirect;
import java.nio.file.FileSystems;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.atomic.AtomicInteger;
public class Stronger {
static final String[] defaultPlayers = {
"java Hero",
"java Bully",
"java Coward",
"java Psycho",
"./monte.out",
"java Analyst",
"java Guardian",
"java Revenger",
"python precog.py",
//"python snappingTurtle.py",
"python beserker.py",
"./suprise.out",
//"python boxer.py",
"python defense.py",
"java Tank",
"java IKnowYou",
//"java BroBot",
"java Equaliser",
"java Velociraptor",
//"java AboveAverage",
"java PhantomMenace",
"java Wiisniper",
//"python semiRandom.py",
"/usr/bin/perl tactition.pl",
"/usr/bin/perl santayana.pl",
//"java GlitchUser"
"/usr/local/bin/Rscript opportunity.R",
"/usr/local/bin/scala Bandwagoner",
};
final int timeout = 5000;
final int startLife = 1000;
final int startPower = 10;
final int numRounds = 20;
boolean log = true;
List<Player> players;
public static void main(String[] args){
new Stronger().run(args);
}
void run(String[] args){
init(args);
for(int i=1;i<=numRounds;i++){
if(log) System.out.println("Begining round "+ i);
Collections.shuffle(players);
runGame();
}
Collections.sort(players);
for(Player player : players)
System.out.println(player.toString());
}
void runGame(){
log("Player Count: " + players.size());
for(Player player : players)
player.reset();
int turn = 0;
while(turn++ < startLife){
if(aliveCount() < 2)
break;
log("Turn " + turn);
List<Player> clones = new ArrayList<Player>();
for(Player player : players)
clones.add(player.copy());
AtomicInteger count=new AtomicInteger(players.size());
for(Player player : players){
new Thread(() -> {
if(player.life >= 1 && !player.timedOut){
String[] args = new String[players.size()+1];
args[0] = "" + player.id;
for(int i=1;i<args.length;i++)
args[i] = players.get(i-1).toArgument();
String reply = getReply(player, args);
Player clone = player.findCopyOrMe(clones);
if(reply.equals("T")){
clone.timedOut = true;
clone.life = 0;
}
clone.lastAction = reply.trim();
}
synchronized(count){
count.decrementAndGet();
count.notify();
}
}).start();
}
synchronized(count){
while(count.get() > 0){
//System.out.println(count);
try{
count.wait();
}catch(InterruptedException e){
}
}
}
for(Player player : players){
if(player.life < 1 || player.timedOut)
continue;
Player clone = player.findCopyOrMe(clones);
if(clone.lastAction.equals("D")){
clone.power--;
}else{
try{
int target = Integer.parseInt(clone.lastAction);
for(Player t : players)
if(t.id == target && t.life < 1)
throw new Exception();
for(Player tclone : clones){
if(tclone.id == target){
int atk = player.power;
if(tclone.lastAction.equals("D")){
atk -= player.power / 2;
tclone.power++;
}
tclone.life -= atk;
tclone.power++;
}
}
} catch (Exception e){
log(player.cmd + " returned an invalid command: (" + clone.lastAction + ")");
clone.power--;
}
}
}
players = clones;
for(Player player : players){
if(player.power < 1)
player.power = 1;
log(player.life + "\t\t" + player.power + "\t\t" + player.lastAction + "\t\t(" + player.id + ")\t" + player.cmd);
}
log("\n");
}
if(aliveCount() == 1)
for(Player player : players)
if(player.life > 0){
player.scoreRounds++;
player.scoreLife += player.life;
}
}
void log(String msg){if(log)System.out.println(msg);}
String getReply(Player player, String[] args){
try{
List<String> cmd = new ArrayList<String>();
String[] tokens = player.cmd.split(" ");
for(String token : tokens)
cmd.add(token);
for(String arg : args)
cmd.add(arg);
ProcessBuilder builder = new ProcessBuilder(cmd);
builder.directory(FileSystems.getDefault().getPath(".", "bin").toFile());
//builder.redirectError(Redirect.PIPE);
long start = System.currentTimeMillis();
Process process = builder.start();
Scanner scanner = new Scanner(process.getInputStream());
process.waitFor();
String reply = scanner.nextLine();
scanner.close();
process.destroy();
if(System.currentTimeMillis() - start > timeout)
return "T";
return reply;
}catch(Exception e){
//e.printStackTrace();
return "Exception: " + e.getMessage();
}
}
void init(String[] args){
players = new ArrayList<Player>();
for(String arg : args){
if(arg.toLowerCase().startsWith("-log")){
log = true;
}else{
Player player = createPlayer(arg);
if(player != null)
players.add(player);
}
}
for(String cmd : defaultPlayers){
Player player = createPlayer(cmd);
if(player != null)
players.add(player);
}
}
Player createPlayer(String cmd){
Player player = new Player(cmd);
String reply = getReply(player, new String[]{});
log(player.cmd + " " + reply);
if(reply != null && reply.equals("ok"))
return player;
return null;
}
int aliveCount(){
int alive = 0;;
for(Player player : players)
if(player.life > 0)
alive++;
return alive;
}
static int nextId = 0;
class Player implements Comparable<Player>{
int id, life, power, scoreRounds, scoreLife;
boolean timedOut;
String cmd, lastAction;
Player(String cmd){
this.cmd = cmd;
id = nextId++;
scoreRounds = 0;
scoreLife = 0;
reset();
}
public Player copy(){
Player copy = new Player(cmd);
copy.id = id;
copy.life = life;
copy.power = power;
copy.scoreRounds = scoreRounds;
copy.scoreLife = scoreLife;
copy.lastAction = lastAction;
return copy;
}
void reset(){
life = startLife;
power = startPower;
lastAction = "X";
timedOut = false;
}
Player findCopyOrMe(List<Player> copies){
for(Player copy : copies)
if(copy.id == id)
return copy;
return this;
}
public int compareTo(Player other){
if(scoreRounds == other.scoreRounds)
return other.scoreLife - scoreLife;
return other.scoreRounds - scoreRounds;
}
public String toArgument(){
return id + "," + life + "," + power + "," + lastAction;
}
public String toString(){
String out = "" + scoreRounds + "\t" + scoreLife;
while(out.length() < 20)
out += " ";
return out + "(" + id + ")\t" + cmd;
}
}
}