斯沃沃
语言= Java
分数= 162.3289512601408075 169.4020975612382575
寻找敌人并包围。 您可能需要给它更长的时间限制。可以改进很多。有时会打印无效的像素。
更新:环绕声更快。使用另一个线程来更新优先级。始终在0.1秒内返回。如果不提高分数的话应该是不可能击败的MAX_TURNS
。
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
public class Swallower {
static final byte MY_TYPE = 1;
static final byte BLANK_TYPE = 0;
static final byte NEUTRAL_TYPE = 2;
static final byte ENEMY_TYPE = 3;
private static final int WHITE = Color.WHITE.getRGB();
private static final int MAX_TIME = 50;
private final int color;
private final int N;
private final int width;
private final int height;
private final BufferedReader in;
Lock borderLock;
private final PriorityBlockingQueue<Pixel> border;
private final Set<Pixel> borderSet;
private final Thread updater;
Lock imageLock;
volatile byte[][] image;
Lock priorityLock;
volatile int[][] priority;
volatile boolean updating;
volatile private boolean exit;
class Pixel implements Comparable<Pixel> {
int x;
int y;
public Pixel(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public int compareTo(Pixel o) {
return priority() - o.priority();
}
private int priority() {
priorityLock.lock();
int p = priority[x][y];
priorityLock.unlock();
return p;
}
public byte type() {
imageLock.lock();
byte i = image[x][y];
imageLock.unlock();
return i;
}
public boolean isBorder() {
if (type() != BLANK_TYPE){
return false;
}
for (Pixel p : pixelsAround()){
if (p.type() == MY_TYPE){
return true;
}
}
return false;
}
public void setType(byte newType) {
imageLock.lock();
image[x][y] = newType;
imageLock.unlock();
}
public void setPriority(int newPriority) {
borderLock.lock();
boolean contains = borderSet.remove(this);
if (contains){
border.remove(this);
}
priorityLock.lock();
priority[x][y] = newPriority;
priorityLock.unlock();
if (contains){
border.add(this);
borderSet.add(this);
}
borderLock.unlock();
}
public List<Pixel> pixelsAround() {
List<Pixel> pixels = new ArrayList<>(4);
if (x > 0){
pixels.add(new Pixel(x - 1, y));
}
if (x < width - 1){
pixels.add(new Pixel(x + 1, y));
}
if (y > 0){
pixels.add(new Pixel(x, y - 1));
}
if (y < height - 1){
pixels.add(new Pixel(x, y + 1));
}
return pixels;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pixel pixel = (Pixel) o;
return x == pixel.x && y == pixel.y;
}
@Override
public int hashCode() {
int result = x;
result = 31 * result + y;
return result;
}
}
public static void main(String[] args) throws IOException {
BufferedImage image = ImageIO.read(new File(args[0]));
int color = parseColorString(args[1]);
int N = Integer.parseInt(args[2]);
new Swallower(image, color, N).start();
}
private void start() throws IOException {
updater.start();
try {
while (true) {
String input = in.readLine();
if (input.equals("exit")) {
exit = true;
if (!updating) {
updater.interrupt();
}
return;
} else if (input.startsWith("colour")) {
updateImage(input);
} else if (input.equals("pick pixels")) {
if (updating) {
try {
synchronized (Thread.currentThread()){
Thread.currentThread().wait(MAX_TIME);
}
} catch (InterruptedException ignored) {
}
}
for (int i = 0; i < N && !border.isEmpty(); i++) {
borderLock.lock();
Pixel p = border.poll();
borderSet.remove(p);
borderLock.unlock();
if (!p.isBorder()){
i--;
continue;
}
updateImage(MY_TYPE, p);
System.out.print(p.x + "," + p.y + " ");
}
System.out.println();
}
}
} catch (Throwable e){
exit = true;
if (!updating){
updater.interrupt();
}
throw e;
}
}
private void updateImage(byte type, Pixel... pixels) {
for (Pixel pixel : pixels){
pixel.setType(type);
if (type == MY_TYPE){
pixel.setPriority(Integer.MAX_VALUE);
} else {
pixel.setPriority(0);
}
}
for (Pixel pixel : pixels){
for (Pixel p : pixel.pixelsAround()){
if (p.type() == BLANK_TYPE){
addPixelToUpdate(p);
}
if (type == MY_TYPE && p.isBorder()){
borderLock.lock();
if (borderSet.add(p)){
border.add(p);
}
borderLock.unlock();
}
}
}
}
private synchronized void addPixelToUpdate(Pixel p) {
if (pixelsToUpdateSet.add(p)) {
pixelsToUpdate.add(p);
if (!updating){
updater.interrupt();
}
}
}
Queue<Pixel> pixelsToUpdate;
Set<Pixel> pixelsToUpdateSet;
private void update(){
while (true){
if (exit){
return;
}
if (pixelsToUpdate.isEmpty()){
try {
updating = false;
while (!exit) {
synchronized (Thread.currentThread()) {
Thread.currentThread().wait();
}
}
} catch (InterruptedException ignored){}
continue;
}
updating = true;
Pixel pixel = pixelsToUpdate.poll();
if (pixel.type() != BLANK_TYPE){
continue;
}
pixelsToUpdateSet.remove(pixel);
updatePixel(pixel);
}
}
private void updatePixel(Pixel pixel) {
int originalPriority = pixel.priority();
int minPriority = Integer.MAX_VALUE;
List<Pixel> pixelsAround = pixel.pixelsAround();
for (Pixel p : pixelsAround){
int priority = p.priority();
if (priority < minPriority){
minPriority = priority;
}
}
if (minPriority >= originalPriority){
pixel.setPriority(Integer.MAX_VALUE);
pixelsToUpdate.addAll(pixelsAround.stream().filter(p -> p.type() == 0 && p.priority() != Integer.MAX_VALUE).filter(pixelsToUpdateSet::add).collect(Collectors.toList()));
} else {
pixel.setPriority(minPriority + 1);
for (Pixel p : pixelsAround){
if (p.type() == 0 && p.priority() > minPriority + 2){
if (pixelsToUpdateSet.add(p)){
pixelsToUpdate.add(p);
}
}
}
}
}
private void updateImage(String input) {
String[] inputs = input.split("\\s");
int color = parseColorString(inputs[1]);
byte type;
if (color == this.color){
return;
} else {
type = ENEMY_TYPE;
}
Pixel[] pixels = new Pixel[inputs.length - 3];
for (int i = 0; i < inputs.length - 3; i++){
String[] coords = inputs[i + 3].split(",");
pixels[i] = new Pixel(Integer.parseInt(coords[0]), Integer.parseInt(coords[1]));
}
updateImage(type, pixels);
}
private static int parseColorString(String input) {
String[] colorString = input.split("[\\(\\),]");
return new Color(Integer.parseInt(colorString[1]), Integer.parseInt(colorString[2]), Integer.parseInt(colorString[3])).getRGB();
}
private Swallower(BufferedImage image, int color, int N){
this.color = color;
this.N = N;
this.width = image.getWidth();
this.height = image.getHeight();
this.image = new byte[width][height];
this.priority = new int[width][height];
for (int x = 0; x < width; x++){
for (int y = 0; y < height; y++){
int pixelColor = image.getRGB(x,y);
priority[x][y] = Integer.MAX_VALUE;
if (pixelColor == WHITE){
this.image[x][y] = BLANK_TYPE;
} else if (pixelColor == this.color){
this.image[x][y] = MY_TYPE;
} else {
this.image[x][y] = NEUTRAL_TYPE;
}
}
}
border = new PriorityBlockingQueue<>();
borderSet = Collections.synchronizedSet(new HashSet<>());
borderLock = new ReentrantLock();
priorityLock = new ReentrantLock();
imageLock = new ReentrantLock();
for (int x = 0; x < width; x++){
for (int y = 0; y < height; y++){
Pixel pixel = new Pixel(x,y);
if (pixel.type() == BLANK_TYPE){
if (pixel.isBorder()){
if (borderSet.add(pixel)){
border.add(pixel);
}
}
}
}
}
in = new BufferedReader(new InputStreamReader(System.in));
updating = false;
updater = new Thread(this::update);
pixelsToUpdate = new ConcurrentLinkedQueue<>();
pixelsToUpdateSet = Collections.synchronizedSet(new HashSet<>());
exit = false;
}
}
怎么运行的:
该漫游器会维护一个可以添加的像素优先级队列。敌方像素的优先级为0。空白像素的优先级比其周围的最低优先级大1。所有其他像素的优先级为Integer.MAX_VALUE。更新器线程正在不断更新像素的优先级。每转一圈,最低N个像素就会从优先级队列中弹出。
绿色Blob vs红色Swallower
Blob分数= 1.680553372583887225
斯沃沃分数= 169.4020975612382575
竞技场1:
Bot Blob.py with colour (0, 255, 0) scored 1.2183333333333333
Bot Swallower.class with colour (255, 0, 0) scored 177.435
竞技场2:
Bot Swallower.class with colour (255, 0, 0) scored 149.57829253338517
Bot Blob.py with colour (0, 255, 0) scored 0.5159187091564356
竞技场3:
Bot Blob.py with colour (0, 255, 0) scored 0.727104853136361
Bot Swallower.class with colour (255, 0, 0) scored 163.343720545521
4号竞技场:
Bot Swallower.class with colour (255, 0, 0) scored 187.25137716604686
Bot Blob.py with colour (0, 255, 0) scored 4.260856594709419
绿色Swallower与红色Blob
Blob分数= 1.6852943642218457375
斯沃沃分数= 169.3923095387498625
竞技场1:
Bot Blob.py with colour (255, 0, 0) scored 1.3166666666666667
Bot Swallower.class with colour (0, 255, 0) scored 177.33666666666667
竞技场2:
Bot Swallower.class with colour (0, 255, 0) scored 149.57829253338517
Bot Blob.py with colour (255, 0, 0) scored 0.49573058575466195
竞技场3:
Bot Swallower.class with colour (0, 255, 0) scored 163.14367053301788
Bot Blob.py with colour (255, 0, 0) scored 0.9271548656394868
4号竞技场:
Bot Swallower.class with colour (0, 255, 0) scored 187.51060842192973
Bot Blob.py with colour (255, 0, 0) scored 4.0016253388265675
Red Swallower与Green Depth First Blob
Swallower的分数= 157.0749775233111925
深度第一Blob分数= 18.192783547939744
竞技场1:
Bot Swallower.class with colour (255, 0, 0) scored 173.52166666666668
Bot dfblob.py with colour (0, 255, 0) scored 5.131666666666667
竞技场2:
Bot dfblob.py with colour (0, 255, 0) scored 17.25635925887156
Bot Swallower.class with colour (255, 0, 0) scored 149.57829253338517
竞技场3:
Bot Swallower.class with colour (255, 0, 0) scored 153.59801488833747
Bot dfblob.py with colour (0, 255, 0) scored 10.472810510319889
4号竞技场:
Bot dfblob.py with colour (0, 255, 0) scored 39.91029775590086
Bot Swallower.class with colour (255, 0, 0) scored 151.60193600485545
绿色Swallower vs红色深度优先Blob
斯沃沃得分= 154.3368355651281075
深度第一Blob分数= 18.84463249420435425
竞技场1:
Bot Swallower.class with colour (0, 255, 0) scored 165.295
Bot dfblob.py with colour (255, 0, 0) scored 13.358333333333333
竞技场2:
Bot dfblob.py with colour (255, 0, 0) scored 8.91118721119768
Bot Swallower.class with colour (0, 255, 0) scored 149.57829253338517
竞技场3:
Bot Swallower.class with colour (0, 255, 0) scored 157.01136822667206
Bot dfblob.py with colour (255, 0, 0) scored 7.059457171985304
4号竞技场:
Bot dfblob.py with colour (255, 0, 0) scored 46.0495522603011
Bot Swallower.class with colour (0, 255, 0) scored 145.4626815004552
绿色Blob vs红色深度第一Blob vs蓝色Swallower:
Blob分数= 6.347962032393275525
深度第一Blob分数= 27.34842554331698275
斯沃沃分数= 227.720728953415375
竞技场1:
Bot Swallower.class with colour (0, 0, 255) scored 242.54
Bot Blob.py with colour (0, 255, 0) scored 1.21
Bot dfblob.py with colour (255, 0, 0) scored 24.3525
竞技场2:
Bot dfblob.py with colour (255, 0, 0) scored 17.828356088588478
Bot Blob.py with colour (0, 255, 0) scored 0.9252889892479551
Bot Swallower.class with colour (0, 0, 255) scored 224.36743880007776
竞技场3:
Bot dfblob.py with colour (255, 0, 0) scored 7.105141670032893
Bot Swallower.class with colour (0, 0, 255) scored 226.52057245080502
Bot Blob.py with colour (0, 255, 0) scored 12.621905476369092
4号竞技场:
Bot dfblob.py with colour (255, 0, 0) scored 60.10770441464656
Bot Blob.py with colour (0, 255, 0) scored 10.634653663956055
Bot Swallower.class with colour (0, 0, 255) scored 217.45490456277872
这是Sam Yonnou的法官,进行了一些更改,以便您分别指定文件和命令:
import sys, re, random, os, shutil, subprocess, datetime, time, signal, io
from PIL import Image
ORTH = ((-1,0), (1,0), (0,-1), (0,1))
def place(loc, colour):
# if valid, place colour at loc and return True, else False
if pix[loc] == (255,255,255):
plist = [(loc[0]+dx, loc[1]+dy) for dx,dy in ORTH]
if any(pix[p]==colour for p in plist if 0<=p[0]<W and 0<=p[1]<H):
pix[loc] = colour
return True
return False
def updateimage(image, msg, bot):
if not re.match(r'(\s*\d+,\d+)*\s*', msg):
return []
plist = [tuple(int(v) for v in pr.split(',')) for pr in msg.split()]
plist = plist[:PIXELBATCH]
return [p for p in plist if place(p, bot.colour)]
class Bot:
botlist = []
def __init__(self, progs, command=None, colour=None):
self.prog = progs[0]
self.botlist.append(self)
self.colour = colour
self.colstr = str(colour).replace(' ', '')
self.faults = 0
self.env = 'env%u' % self.botlist.index(self)
try: os.mkdir(self.env)
except: pass
for prog in progs:
shutil.copy(prog, self.env)
shutil.copy(imagename, self.env)
os.chdir(self.env)
args = command + [imagename, self.colstr, str(PIXELBATCH)]
errorfile = 'err.log'
with io.open(errorfile, 'wb') as errorlog:
self.proc = subprocess.Popen(args, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=errorlog)
os.chdir('..')
def send(self, msg):
if self.faults < FAULTLIMIT:
self.proc.stdin.write((msg+'\n').encode('utf-8'))
self.proc.stdin.flush()
def read(self, timelimit):
if self.faults < FAULTLIMIT:
start = time.time()
inline = self.proc.stdout.readline().decode('utf-8')
if time.time() - start > timelimit:
self.faults += 1
inline = ''
return inline.strip()
def exit(self):
self.send('exit')
from cfg import *
for i, (progs, command) in enumerate(botspec):
Bot(progs, command, colourspec[i])
image = Image.open(imagename)
pix = image.load()
W,H = image.size
resultdirectory = 'results of ' + BATTLE
os.mkdir(resultdirectory)
time.sleep(INITTIME)
total = 0
image.save(resultdirectory+'/'+'result000.png')
for turn in range(1, MAXTURNS+1):
random.shuffle(Bot.botlist)
nullbots = 0
for bot in Bot.botlist:
bot.send('pick pixels')
inmsg = bot.read(TIMELIMIT)
newpixels = updateimage(image, inmsg, bot)
total += len(newpixels)
if newpixels:
pixtext = ' '.join('%u,%u'%p for p in newpixels)
msg = 'colour %s chose %s' % (bot.colstr, pixtext)
for msgbot in Bot.botlist:
msgbot.send(msg)
else:
nullbots += 1
if nullbots == len(Bot.botlist):
break
if turn % 100 == 0:
print('Turn %s done %s pixels' % (turn, total))
image.save(resultdirectory+'/result'+str(turn//100).zfill(3)+'.png')
image.save(resultdirectory+'/result999.png')
for msgbot in Bot.botlist:
msgbot.exit()
resultfile = io.open(resultdirectory+'/result.txt','w')
counts = dict((c,f) for f,c in image.getcolors(W*H))
avg = 1.0 * sum(counts.values()) / len(Bot.botlist)
for bot in Bot.botlist:
score = 100 * counts[bot.colour] / avg
print('Bot %s with colour %s scored %s' % (bot.prog, bot.colour, score))
print('Bot %s with colour %s scored %s' % (bot.prog, bot.colour, score), file=resultfile)
image.save(BATTLE+'.png')
cfg示例:
BATTLE = 'Green DepthFirstBlob vs Red Swallower @ arena1'
MAXTURNS = 20000
PIXELBATCH = 10
INITTIME = 2.0
TIMELIMIT = .1
FAULTLIMIT = 5
imagename = 'arena1.png'
colourspec = (0,255,0), (255,0,0)
botspec = [
(['DepthFirstBlob.py'], ['python', 'DepthFirstBlob.py']),
(['Swallower.class','Swallower$Pixel.class'], ['java', 'Swallower']),
]
注意:吞噬Swallower的任何人都会获得100点声望。如果成功的话,请在下面的评论中发表。