Огляд
Це бот-битва, щоб побачити, хто може вижити найдовше. Однак ці боти збільшують свою силу шляхом нападу, тому перед тим, як стріляти, потрібно добре подумати.
Кожен виток, ви можете вибрати бота для нападу або захисту. Атака знизить її життя і збільшить її силу. Виграє останній бот, що стоїть.
Боти
Кожен бот починається з 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.
Якщо наприкінці повороту залишився живий один бот (життя> 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;
}
}
}
Правила
Ви можете ввести до двох ботів. Якщо ви хочете вилучити один із відтворення, щоб увійти до третього, видаліть його публікацію.
Ви не можете орієнтуватися на бот або іншим чином виділити його за допомогою мета-аналізу. Використовуйте лише ту інформацію, яку надано вашому боту. Сюди входять ваші власні боти, тож ви не можете вводити двох ботів, які мають змову.
Не намагайтеся жодним чином перешкоджати роботі контролера чи інших ботів.
Ваш бот може не створювати інстанцію або іншим чином запускати контролер або інші боти.
Результати
(ботів, поданих станом на 22.05.2015 00: 00: 00З)
Цей раунд гри пройшов трохи краще, лише дві гри затрималися на 1000 обертів. Престижність Ральфа Маршалла Сантаяна , який посів перше місце, будучи єдиними ботами , який здобув три перемоги. Цього було недостатньо, тому він також зайняв третє місце з « Тактиком» . Stormcrow зайняв друге місце з Phantom Menace , чудовим першим повідомленням тут. Загалом, у нас було дуже приємно показувати нових членів, де шість найкращих місць займали люди, які мають менше п'яти постів. Вітаємо, і ласкаво просимо на сайт!
Боти, які набрали нульовий виграш, не вказуються для економії місця. Усі боти, розміщені до часової позначки, були запущені, тому якщо ви не бачите своїх, нічого не виграло.
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;
}
}
}