Tổng quan
Đây là một trận chiến bot để xem ai có thể sống sót lâu nhất. Tuy nhiên, những bot này tăng sức mạnh bằng cách bị tấn công, vì vậy bạn cần suy nghĩ cẩn thận trước khi bắn.
Mỗi lượt, bạn có thể chọn một bot để tấn công hoặc phòng thủ. Tấn công sẽ hạ thấp tuổi thọ và tăng sức mạnh của nó. Bot cuối cùng đứng thắng.
Bots
Mỗi bot bắt đầu với 1000 cuộc sống và 10 sức mạnh.
Khi bị tấn công:
- sức mạnh của kẻ tấn công bị trừ khỏi cuộc sống của bạn
- sức mạnh của bạn tăng lên 1.
Vì vậy, nếu ở lượt đầu tiên, bạn bị tấn công bởi hai bot, bạn sẽ có 980 sinh mạng và 12 sức mạnh.
Nếu bạn chọn bảo vệ:
- sức mạnh của bạn sẽ bị giảm 1
- tất cả các cuộc tấn công chống lại bạn lần lượt này sẽ giảm đi một nửa
- nếu bạn bị tấn công, bạn sẽ nhận được 2 sức mạnh cho mỗi kẻ tấn công thay vì 1
Vì vậy, nếu bạn phòng thủ ở lượt đầu tiên và bị tấn công bởi hai bot, bạn sẽ có 990 sinh mạng và 13 sức mạnh. Nếu bạn phòng thủ và không bị tấn công, bạn sẽ có 1000 sinh mạng, nhưng 9 sức mạnh.
Nếu ở cuối lượt, sức mạnh của bạn ở dưới một, nó sẽ được đặt thành một. Nếu cuộc sống của bạn dưới 1, bạn chết.
Đầu ra đầu vào
Bots được gọi một lần mỗi lượt. Có giới hạn thời gian là một giây cho mỗi lượt.
Ban đầu
Lần đầu tiên bot của bạn được gọi, nó sẽ không có đối số. Trả lời với ok
. Điều này được thực hiện chỉ để đảm bảo bot của bạn phản hồi. Nếu không, nó sẽ không được thêm vào danh sách người chơi.
Mỗi lượt
Mỗi lượt, bot của bạn được cung cấp thông tin về tất cả các bot trong trò chơi dưới dạng đối số dòng lệnh. Một ví dụ về các đối số này là:
1 0,1000,10,1 1,995,11,D
Đối số đầu tiên là id duy nhất của bot của bạn. Sau đó, một danh sách các bot được phân tách không gian xuất hiện. Mỗi bot được định dạng là:
id,life,power,lastAction
lastAction
có thể là một số nguyên đại diện cho bot mà họ tấn công, D
nếu họ bảo vệ và X
nếu đây là lượt đầu tiên. Những cái khác đều là số nguyên.
Vì vậy, trong ví dụ trên, bạn là bot 1
và bảo vệ trong lượt cuối cùng của bạn. Bot 0
tấn công bạn và vẫn đang bắt đầu sức khỏe / sức mạnh.
Đầu ra cho mỗi lượt rất đơn giản. Đơn giản chỉ cần xuất bot bạn muốn tấn công dưới dạng số nguyên (ví dụ 0
hoặc 3
) hoặc D
để bảo vệ. Đừng tấn công các bot đã chết hoặc không tồn tại, vì đó được coi là một lệnh không hợp lệ. Bất kỳ lệnh không hợp lệ sẽ dẫn đến bạn mất 1 sức mạnh.
Cơ cấu giải đấu
Mỗi trò chơi bao gồm tất cả các bot bắt đầu từ 1000 sức khỏe và 10 sức mạnh. Hành động của tất cả các bot được thực hiện đồng thời. Số lượt chơi tối đa cho một trò chơi là 1000.
Nếu ở cuối lượt chơi có một bot còn sống (tuổi thọ> 0), nó ghi được một điểm và một trò chơi khác được bắt đầu. Nếu đạt đến giới hạn rẽ và có nhiều bot còn sống, không ai có được điểm. Nếu tất cả các bot còn lại chết trong cùng một lượt, không ai có được điểm.
Một giải đấu bao gồm 15 trò chơi. Ai có nhiều điểm nhất vào cuối sẽ thắng! Ties bị phá vỡ bởi tổng số cuộc sống còn lại trong mỗi trò chơi giành chiến thắng.
Tiểu bang
Bots chỉ có thể đọc từ hoặc ghi vào một tệp duy nhất được đặt tên theo chính nó, trong thư mục con trực tiếp có tên state
("Hero" có thể ghi vào state/hero.whatever
). Tệp này không được vượt quá 1024 2 byte kích thước. Hãy cẩn thận để quan sát giới hạn thời gian. Chương trình của bạn phải chấm dứt trong vòng một giây để đếm, không chỉ đưa ra phản hồi.
Các tệp này sẽ bị xóa trước mỗi giải đấu, nhưng sẽ tiếp tục trò chơi này đến trò chơi khác. Tất cả các định danh bot ( id
) cũng sẽ giữ nguyên giữa các trò chơi.
Bộ điều khiển
Dưới đây là bộ điều khiển giải đấu ( Stronger.java
). Theo mặc định , nó chỉ đưa ra kết quả cuối cùng (danh sách người chơi được sắp xếp, người chiến thắng trên đầu trang), có thể mất nhiều thời gian. Nó không bị đóng băng, chỉ im lặng. Nếu bạn muốn đầu ra lần lượt chi tiết hơn, hãy thêm -log
đối số khi chạy.
Để thêm bot, bạn có hai tùy chọn:
thêm lệnh làm đối số (
java Stronger -log "python bot.py"
)thêm lệnh vào
defaultPlayers[]
trong nguồn ("python bot.py"
)
Các bot Hero , Bully và Coward có thể được tìm thấy trong câu trả lời này và sẽ được sử dụng cho mục đích ghi điểm.
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;
}
}
}
Quy tắc
Bạn có thể nhập tối đa hai bot. Nếu bạn muốn xóa một từ chơi để nhập một phần ba, xin vui lòng xóa bài viết của nó.
Bạn không thể nhắm mục tiêu hoặc loại bỏ một bot bằng cách phân tích tổng hợp. Chỉ sử dụng thông tin bot của bạn được cung cấp. Điều này bao gồm các bot của riêng bạn, vì vậy bạn không thể nhập hai bot thông đồng.
Không cố gắng can thiệp vào việc chạy bộ điều khiển hoặc các bot khác bằng mọi cách.
Bot của bạn có thể không khởi tạo hoặc chạy bộ điều khiển hoặc các bot khác.
Các kết quả
(trong số các bot được gửi kể từ 2015-05-22 00: 00: 00Z)
Vòng chơi này đã tốt hơn một chút, chỉ có hai trò chơi bị đình trệ ở 1000 lượt. Kudos để Ralph Marshall của Santayana , diễn ra đầu tiên, là bot duy nhất ghi được ba chiến thắng. Thế là chưa đủ, nên anh cũng giành vị trí thứ ba với Tactician . Stormcrow đứng thứ hai với Phantom Menace , một bài đăng đầu tiên tốt ở đây. Tất cả trong tất cả chúng tôi đã có một màn trình diễn rất hay của các thành viên mới, với sáu vị trí hàng đầu sẽ thuộc về những người có ít hơn năm bài đăng. Xin chúc mừng, và chào mừng đến với trang web!
Bots ghi được chiến thắng bằng không được liệt kê để tiết kiệm không gian. Tất cả các bot được đăng trước khi dấu thời gian ở trên được chạy, vì vậy nếu bạn không thấy của bạn, nó sẽ không giành được bất cứ điều gì.
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
Bộ điều khiển song song sắp xếp sơ sài ( của người khác ):
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;
}
}
}