обзор
Это битва с ботами, чтобы увидеть, кто выживет дольше всех. Эти боты увеличивают свою силу, будучи атакованы, поэтому вам нужно тщательно подумать, прежде чем стрелять.
Каждый ход вы можете выбрать бота для атаки или защиты. Атакующий уменьшит его жизнь и увеличит его силу. Последний стоящий бот выигрывает.
Боты
Каждый бот начинается с 1000 жизни и 10 сил.
При нападении:
- сила вашего атакующего вычитается из вашей жизни
- ваша сила увеличивается на 1.
Таким образом, если в первый ход вас атакуют два бота, у вас будет 980 жизней и 12 сил.
Если вы решили защищать:
- ваша сила будет уменьшена на 1
- все атаки против вас в этом ходу будут уменьшены вдвое
- если на вас напали, вы получите 2 силы для каждого атакующего вместо 1
Таким образом, если вы защищаетесь в первый ход и атакованы двумя ботами, у вас будет 990 жизней и 13 сил. Если вы защищаетесь и не подвергаетесь нападению, у вас будет 1000 жизней, но 9 сил.
Если в конце хода ваша сила ниже единицы, она будет установлена на единицу. Если ваша жизнь ниже 1, вы умрете.
Ввод, вывод
Боты вызываются один раз за ход. Существует ограничение в одну секунду для каждого хода.
начальный
При первом вызове вашего бота ему не будет предоставлено никаких аргументов. Ответить с ok
. Это делается только для того, чтобы ваш бот отвечал. Если этого не произойдет, он не будет добавлен в список игроков.
Каждый ход
Каждый ход вашему боту предоставляется информация обо всех ботах в игре в качестве аргументов командной строки. Пример этих аргументов:
1 0,1000,10,1 1,995,11,D
Первый аргумент - уникальный идентификатор вашего бота. Затем появляется разделенный пробелами список ботов. Каждый бот отформатирован как:
id,life,power,lastAction
lastAction
может быть целым числом, представляющим, какого бота они атаковали, D
защищались ли они, и X
если это первый ход. Все остальные целые числа.
Таким образом, в приведенном выше примере, вы бот 1
и защитили в свой последний ход. Бот 0
напал на вас и все еще находится на начальном этапе здоровья / силы.
Выход за каждый ход очень прост. Просто выведите бота, которого вы хотите атаковать, целым числом (например, 0
или 3
) или D
для защиты. Не атакуйте мертвых или несуществующих ботов, так как это считается неверной командой. Любая неверная команда приведет к потере 1 силы.
Структура турнира
Каждая игра состоит из всех ботов, начиная с 1000 здоровья и 10 силы. Действия всех ботов выполняются одновременно. Максимальное количество ходов для игры - 1000.
Если в конце хода остался один бот (life> 0), он получает одно очко и запускается другая игра. Если достигнут предел хода и в игре несколько ботов, никто не получает очко. Если все остальные боты умирают на одном ходу, никто не получает очко.
Турнир состоит из 15 игр. Тот, у кого больше очков в конце, побеждает! Связи нарушаются суммой оставшейся жизни в каждой выигранной игре.
государственный
Боты могут только читать или писать в один файл, названный в его честь, в прямой подпапке с именем state
(«Герой» может писать в state/hero.whatever
). Этот файл не должен превышать 1024 2 байта в размере. Позаботьтесь о соблюдении сроков. Ваша программа должна завершиться в течение одной секунды, чтобы считать, а не просто дать ответ.
Эти файлы будут стираться перед каждым турниром, но будут сохраняться в игре. Все идентификаторы ботов ( id
) также останутся неизменными между играми.
контроллер
Ниже находится контроллер турнира ( Stronger.java
). По умолчанию выводятся только окончательные результаты (отсортированный список игроков, победитель сверху), что может занять довольно много времени. Это не заморожено, просто тихо. Если вы хотите более подробный пошаговый вывод, добавьте -log
аргумент при запуске.
Чтобы добавить ботов, у вас есть два варианта:
добавить команду в качестве аргумента (
java Stronger -log "python bot.py"
)добавить команду
defaultPlayers[]
в источник ("python bot.py"
)
В этом ответе можно найти ботов- героев , хулиганов и трусов , которые будут использоваться для подсчета очков.
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;
}
}
}
правила
Вы можете ввести до двух ботов. Если вы хотите удалить один из игр, чтобы ввести третий, пожалуйста, удалите его пост.
Вы не можете нацеливаться или иным образом выделять бота с помощью мета-анализа. Используйте только ту информацию, которая предоставлена вашему боту. Это включает в себя ваших собственных ботов, поэтому вы не можете ввести двух ботов, которые вступают в сговор.
Не пытайтесь каким-либо образом вмешиваться в работу контроллера или других ботов.
Ваш бот не может создавать или иным образом запускать контроллер или других ботов.
Результаты
(ботов, представленных по состоянию на 2015-05-22 00: 00: 00Z)
Этот раунд игры прошел немного лучше, только две игры затормозились на 1000 ходов. Престижность Ральфа Маршалла Сантаяна , который занял первое место, будучи единственными ботами , который одержал три победы. Этого было недостаточно, поэтому он также занял третье место с тактиком . Stormcrow занял второе место с « Призрачной угрозой» , прекрасным первым постом здесь. В целом, у нас был очень хороший показ новых участников: шесть лучших мест достались людям с менее чем пятью постами. Поздравляем и добро пожаловать на сайт!
Боты с нулевым выигрышем не указаны в списке для экономии места. Все боты, опубликованные до указанной выше отметки времени, были запущены, поэтому, если вы не видите свою, она ничего не выиграет.
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
Сорта схематично распараллеленный контроллер ( другие ):
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;
}
}
}