최고의 응모를 위해 @kuroineko에 축하를 전하고 @TheBestOne (우수한 스포츠맨 쉽)에서 200 현상금을 획득했습니다.
야당 프로그램보다 가능한 한 많은 이미지를 색칠하는 프로그램을 작성하십시오.
간단한 규칙
- 프로그램에 이미지, 색상 및 정수 N이 제공됩니다.
- 매 턴마다 다른 프로그램에 의해 픽셀 업데이트가 전송되고 N 업데이트를 요청합니다.
- 색상의 픽셀 옆에있는 흰색 픽셀을 업데이트 할 수 있습니다.
- 가장 많은 픽셀을 추가 한 프로그램이 승리합니다.
세부 규칙
프로그램에 PNG 이미지 파일 이름, 홈 컬러 및 숫자 N이 부여됩니다. 숫자 N은 프로그램이 매번 색상을 지정할 수있는 최대 픽셀 수입니다.
예: MyProg arena.png (255,0,0) 30
입력 이미지는 20에서 1000 픽셀 사이의면을 가진 사각형입니다. 검은 색, 흰색 및 컬러 픽셀로 구성됩니다. 프로그램은 각각의 새로운 픽셀이 자신의 색상으로 된 네 개의 인접 픽셀 중 하나 이상을 가져야하는 조건으로 자신 만의 색상으로 흰색 픽셀 시퀀스를 선택할 수 있습니다 . 이미지에는 처음에 컬러의 픽셀이 하나 이상 있습니다. 또한 프로그램이 지정되지 않은 색상의 픽셀이있을 수 있습니다. 알파 채널은 사용되지 않습니다.
당신의 목표는 상대방을 차단하고 가능한 한 많은 픽셀에 색상을 쓰는 것입니다.
매번 프로그램은 STDIN에서 하나 이상의 메시지 라인을 받아들이고 STDOUT에 픽셀 좌표로 구성된 라인을 작성합니다. STDOUT을 버퍼되지 않은 것으로 지정하거나 매 턴마다 STDOUT 버퍼를 플러시하십시오.
각 차례의 선수 순서는 무작위로 할당됩니다. 이것은 상대 (또는 당신의 프로그램)가 연속으로 2 턴을 할 수 있음을 의미합니다.
프로그램은 colour (N,N,N) chose X,Y X,Y ... X,Y
플레이어 프로그램에 의해 채워진 픽셀을 설명하는 정보 메시지를 받게됩니다 . 플레이어가 움직이지 않거나 유효한 움직임이 없으면 해당 플레이어의 움직임에 대한 메시지가 표시되지 않습니다. 프로그램은 또한 하나 이상의 유효한 이동을 지정한 경우 자신의 승인 된 이동에 대한 메시지를받습니다. 픽셀 0,0은 이미지의 왼쪽 상단에 있습니다.
수신 pick pixels
하면 프로그램은 X,Y X,Y ... X,Y
최대 N 픽셀을 출력 합니다 ( '\ n'으로 구성된 빈 문자열이 허용됩니다). 픽셀은 플로팅 순서 여야합니다. 픽셀이 유효하지 않으면 픽셀이 무시되고 플레이어에게보고되지 않습니다. 프로그램은 시작 후 초기화하는 데 2 초가 걸리지 만, 매 턴마다 응답으로 0.1 초만 응답하면 해당 턴을 놓치게됩니다. 0.1 초 후에 전송 된 픽셀 업데이트는 오류를 기록합니다. 오류가 5 회 발생한 후 프로그램이 일시 중단되며 업데이트 나 pick pixels
요청 이 전송되지 않습니다 .
심사 프로그램이 일시 중단되지 않은 모든 플레이어 프로그램에서 비어 있거나 유효하지 않은 픽셀 선택을 수신하면 이미지가 완료된 것으로 간주 되고 프로그램에 "종료"메시지가 전송됩니다. "종료"를받은 후 프로그램을 종료해야합니다.
채점
판사는 이미지가 완성 된 후 점수를 매 깁니다. 점수는 업데이트 된 픽셀 수를 해당 라운드의 평균 픽셀 캡처로 나눈 값이며 백분율로 표시됩니다.
플레이어가 이미지에 추가 한 픽셀 수는 A입니다. 모든 P 플레이어가 추가 한 총 픽셀 수 는 T입니다.
avg = T/P
score = 100*A/avg
게시 점수
참조 상대 "Blob"이 제공됩니다. 각 답변에 대해 기준 상대에 대한 이름, 언어 및 점수 (평균 1-4)로 봇의 제목을 지정하십시오. 전투 중 하나의 그림이나 애니메이션도 좋습니다. 우승자는 참조 로봇에 대해 가장 높은 점수를받은 프로그램입니다.
Blob이 너무 쉽게 이길 수없는 경우, 더 강력한 참조 상대와 함께 두 번째 라운드를 추가 할 수 있습니다.
4 개 이상의 플레이어 프로그램을 시험해 볼 수도 있습니다. 답변으로 게시 된 다른 봇에 대해 봇을 테스트 할 수도 있습니다.
판사
판사 프로그램에는 일반적인 PIL (Python Imaging Library)이 필요하며 Linux의 OS 패키지 관리자에서 쉽게 설치할 수 있습니다. Windows 7에서 64 비트 Python에서 PIL이 작동하지 않는다는 보고서가 있으므로이 도전을 시작하기 전에 PIL이 작동하는지 확인하십시오 (2015-01-29 업데이트).
#!/usr/bin/env python
# Judge Program for Image Battle challenge on PPCG.
# Runs on Python 2.7 on Ubuntu Linux. May need edits for other platforms.
# V1.0 First release.
# V1.1 Added Java support
# V1.2 Added Java inner class support
# usage: judge cfg.py
import sys, re, random, os, shutil, subprocess, datetime, time, signal
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, name, interpreter=None, colour=None):
self.prog = name
self.botlist.append(self)
callarg = re.sub(r'\.class$', '', name) # Java fix
self.call = [interpreter, callarg] if interpreter else [callarg]
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
if name.endswith('.class'): # Java inner class fix
rootname = re.sub(r'\.class$', '', name)
for fn in os.listdir('.'):
if fn.startswith(rootname) and fn.endswith('.class'):
shutil.copy(fn, self.env)
else:
shutil.copy(self.prog, self.env)
shutil.copy(imagename, self.env)
os.chdir(self.env)
args = self.call + [imagename, self.colstr, `PIXELBATCH`]
self.proc = subprocess.Popen(args, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
os.chdir('..')
def send(self, msg):
if self.faults < FAULTLIMIT:
self.proc.stdin.write(msg + '\n')
self.proc.stdin.flush()
def read(self, timelimit):
if self.faults < FAULTLIMIT:
start = time.time()
inline = self.proc.stdout.readline()
if time.time() - start > timelimit:
self.faults += 1
inline = ''
return inline.strip()
def exit(self):
self.send('exit')
from cfg import *
for i, (prog, interp) in enumerate(botspec):
Bot(prog, interp, colourspec[i])
image = Image.open(imagename)
pix = image.load()
W,H = image.size
time.sleep(INITTIME)
total = 0
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)
for msgbot in Bot.botlist:
msgbot.exit()
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)
image.save(BATTLE+'.png')
구성 예-cfg.py
BATTLE = 'Green Blob vs Red Blob'
MAXTURNS = 20000
PIXELBATCH = 10
INITTIME = 2.0
TIMELIMIT = 0.1
FAULTLIMIT = 5
imagename = 'arena1.png'
colourspec = (0,255,0), (255,0,0)
botspec = [
('blob.py', 'python'),
('blob.py', 'python'),
]
Blob-참조 상대
# Blob v1.0 - A reference opponent for the Image Battle challenge on PPCG.
import sys, os
from PIL import Image
image = Image.open(sys.argv[1])
pix = image.load()
W,H = image.size
mycolour = eval(sys.argv[2])
pixbatch = int(sys.argv[3])
ORTH = ((-1,0), (1,0), (0,-1), (0,1))
def canchoose(loc, colour):
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):
return True
return False
def near(loc):
plist = [(loc[0]+dx, loc[1]+dy) for dx,dy in ORTH]
pboard = [p for p in plist if 0<=p[0]<W and 0<=p[1]<H]
return [p for p in pboard if pix[p] == (255,255,255)]
def updateimage(image, msg):
ctext, colourtext, chose, points = msg.split(None, 3)
colour = eval(colourtext)
plist = [tuple(int(v) for v in pr.split(',')) for pr in points.split()]
for p in plist:
pix[p] = colour
skin.discard(p)
if colour == mycolour:
for np in near(p):
skin.add(np)
board = [(x,y) for x in range(W) for y in range(H)]
skin = set(p for p in board if canchoose(p, mycolour))
while 1:
msg = sys.stdin.readline()
if msg.startswith('colour'):
updateimage(image, msg.strip())
if msg.startswith('pick'):
plen = min(pixbatch, len(skin))
moves = [skin.pop() for i in range(plen)]
movetext = ' '.join('%u,%u'%p for p in moves)
sys.stdout.write(movetext + '\n')
sys.stdout.flush()
if msg.startswith('exit'):
break
image.save('blob.png')
아레나 1
아레나 2
아레나 3
아레나 4
전투 예-Blob vs Blob
이 전투는 예측 가능한 결과를 가져 왔습니다.
Bot blob.py with colour (255, 0, 0) scored 89.2883333333
Bot blob.py with colour (0, 255, 0) scored 89.365