Visión de conjunto
Esta es una batalla bot para ver quién puede sobrevivir más tiempo. Sin embargo, estos robots aumentan su poder al ser atacados, por lo que debes pensar cuidadosamente antes de disparar.
Cada turno, puedes elegir un bot para atacar o defender. Atacar disminuirá su vida y aumentará su poder. El último robot en pie gana.
Bots
Cada bot comienza con 1000 de vida y 10 de potencia.
Cuando atacado:
- el poder de tu atacante se resta de tu vida
- tu poder aumenta en 1.
Entonces, si en el primer turno, eres atacado por dos bots, tendrás 980 de vida y 12 de poder.
Si eliges defender:
- tu poder se reducirá en 1
- todos los ataques contra ti este turno se reducirán a la mitad
- si eres atacado, ganarás 2 de poder por cada atacante en lugar de 1
Entonces, si te defiendes en el primer turno y eres atacado por dos bots, tendrás 990 de vida y 13 de poder. Si defiendes y no eres atacado, tendrás 1000 vidas, pero 9 de poder.
Si al final de un turno tu poder está por debajo de uno, se establecerá en uno. Si tu vida es inferior a 1, mueres.
De entrada y salida
Los bots se llaman una vez por turno. Hay un límite de tiempo de un segundo para cada turno.
Inicial
La primera vez que se llama a su bot, no se le darán argumentos. Responde con ok
. Esto se hace solo para asegurarse de que su bot responda. Si no lo hace, no se agregará a la lista de jugadores.
Cada turno
Cada turno, su bot recibe información sobre todos los bots en el juego como argumentos de línea de comando. Un ejemplo de estos argumentos es:
1 0,1000,10,1 1,995,11,D
El primer argumento es la identificación única de su bot. Luego, aparece una lista de bots separados por espacios. Cada bot está formateado como:
id,life,power,lastAction
lastAction
puede ser un número entero que representa a qué bot atacaron, D
si defendieron y X
si este es el primer turno. Los demás son todos enteros.
Entonces, en el ejemplo anterior, eres bot 1
y estás defendido en tu último turno. Bot 0
te atacó y todavía está comenzando salud / poder.
La salida para cada turno es muy simple. Simplemente muestre el bot que desea atacar como un entero (por ejemplo, 0
o 3
), o D
para defender. No ataque los bots muertos o inexistentes, ya que eso cuenta como un comando no válido. Cualquier comando no válido hará que pierdas 1 poder.
Estructura de torneo
Cada juego consta de todos los bots que comienzan en 1000 de salud y 10 de poder. Las acciones de todos los bots se toman simultáneamente. El número máximo de turnos para un juego es 1000.
Si al final del turno queda un bot vivo (vida> 0), obtiene un punto y se inicia otro juego. Si se alcanza el límite de giro y hay varios bots vivos, nadie obtiene un punto. Si todos los robots restantes mueren en el mismo turno, nadie obtiene un punto.
Un torneo consta de 15 juegos. ¡Quien tenga más puntos al final gana! Los empates se rompen por la suma de la vida restante en cada juego ganado.
Estado
Los bots solo pueden leer o escribir en un solo archivo que lleva su nombre, en una subcarpeta directa llamada state
("Hero" puede escribir state/hero.whatever
). Este archivo no debe exceder 1024 2 bytes de tamaño. Tenga cuidado de observar el límite de tiempo. Su programa debe finalizar dentro de un segundo para contar, no solo dar una respuesta.
Estos archivos se borrarán antes de cada torneo, pero persistirán juego a juego. Todos los identificadores de bot ( id
) también permanecerán iguales entre los juegos.
Controlador
A continuación se muestra el controlador del torneo ( Stronger.java
). De forma predeterminada , solo genera los resultados finales (lista ordenada de jugadores, ganador en la parte superior), lo que puede llevar bastante tiempo. No está congelado, solo silencioso. Si desea una salida paso a paso más detallada, agregue el -log
argumento al ejecutar.
Para agregar bots, tienes dos opciones:
agregue el comando como argumento (
java Stronger -log "python bot.py"
)agregue el comando a
defaultPlayers[]
en la fuente ("python bot.py"
)
Los bots Hero , Bully y Coward se pueden encontrar en esta respuesta , y se utilizarán con fines de puntuación.
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;
}
}
}
Reglas
Puede ingresar hasta dos bots. Si desea eliminar uno del juego para ingresar un tercero, elimine su publicación.
No puede apuntar o seleccionar un bot de otra manera mediante un metanálisis. Use solo la información que le da su bot. Esto incluye sus propios bots, por lo que no puede ingresar dos bots que coluden.
No intente interferir con el funcionamiento del controlador u otros bots de ninguna manera.
Su bot no puede crear instancias ni ejecutar el controlador u otros bots.
Resultados
(de bots enviados a partir del 22/05/2015 00: 00: 00Z)
Esta ronda de juego fue un poco mejor, con solo dos juegos deteniéndose en 1000 turnos. Felicitaciones a Santayana de Ralph Marshall , que obtuvo el primer lugar, siendo el único bot que obtuvo tres victorias. Eso no fue suficiente, por lo que también ocupó el tercer lugar con Tactician . Stormcrow ocupó el segundo lugar con Phantom Menace , una excelente primera publicación aquí. En general, tuvimos una muy buena presentación de nuevos miembros, con los seis primeros lugares para personas con menos de cinco publicaciones. ¡Felicitaciones y bienvenido al sitio!
Los bots que obtuvieron cero victorias no están listados para ahorrar espacio. Todos los bots publicados antes de la marca de tiempo anterior se ejecutaron, por lo que si no ve el suyo, no ganó 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
Sorta controlador paralelo incompleto ( por otros ):
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;
}
}
}