Ваша програма контролюватиме гірничого робота, який шукає під землею корисні копалини. Ваш робот повідомить контролеру, куди ви хочете рухатися та копати, а контролер надасть відгуки про ваш статус робота.
Спочатку вашому роботу буде надана карта зображень шахти з уже наявними шахтними шахтами, а також файл даних із зазначенням значення та твердості корисних копалин у шахті. Потім ваш робочий рух переміститься по валах, шукаючи корисні копалини. Ваш робот може копати землю, але сповільнений твердою скелею.
Робот, який повернеться з найціннішим вантажем після 24-годинної зміни, стане переможцем. Це може здатися складним викликом, але зробити основний робочий майнінг просто (див. Відповідь Роботи з видобутку зразків нижче).
Операція
Вашу програму розпочне контролер із зображеннями шахти, мінеральними даними та назви файлів обладнання. Роботи можуть використовувати шахтні зображення та дані корисних копалин, щоб знайти цінну руду та уникнути важких порід. Робот може також захотіти придбати обладнання зі списку обладнання.
наприклад: python driller.py mineimage.png minerals.txt equipmentlist.txt
Після 2-секундного періоду ініціалізації, контролер спілкується з робот-програмою через stdin та stdout. Роботи повинні відповісти дією протягом 0,1 секунди після отримання повідомлення про стан.
Кожен поворот контролер надсилає роботові рядки стану:
timeleft cargo battery cutter x y direction
наприклад: 1087 4505 34.65 88.04 261 355 right
Ціле число timeleft
- це ігрові секунди, що залишилися до кінця зсуву. Це
cargo
ціле значення корисних копалин, які ви видобули поки що менше, ніж ви заплатили за обладнання. battery
Рівень являє собою ціле число в процентах від заряду акумулятора. cutter
Рівень цілого числа є поточної гостротою різця в процентах від стандартного значення. Значення x
і y
значення є натуральними цілими числами, з позицією робота, на яку посилається верхній лівий кут (0, 0). Напрямок - поточний напрямок, з яким стикається робот (вліво, вправо, вгору, вниз).
Коли ваш робот отримає вхід 'endhift' або 'fail', ваша програма незабаром буде припинена. Можливо, ви бажаєте, щоб робот спочатку записав дані про налагодження / продуктивність у файл.
Існує 4 можливі команди, які контролер прийме. direction
left|right|up|down
вкаже ваш робот у цьому напрямку та потребує 15 ігор-секунд. move <integer>
доручить вашому роботові переміщати чи копати стільки одиниць вперед, що потребує часу залежно від твердості різання мінералів та різкості вашого різака (див. нижче). buy <equipment>
встановить вказане обладнання та відрахує вартість від вашої вантажної вартості, але лише якщо робот знаходиться на поверхні (y-значення <= початкове значення y). Установка обладнання займає 300 ігор-секунд. Спеціальна команда snapshot
записує поточний образ шахти на диск і не вимагає часу для гри. Ви можете використовувати знімки для налагодження роботи або створення анімації.
Ваш робот почне працювати з акумулятором на 100 акумуляторів і 100 різкостями. Для переміщення та повороту використовуйте невелику кількість енергії акумулятора. Копання використовує набагато більше і є функцією твердості мінералів та різкості струму різця. У міру того, як ваш робочий копається в мінералах, різець втратить свою гостроту, залежно від часу і твердості корисних копалин. Якщо ваш робот має достатню вантажну цінність, він може повернутися на поверхню, щоб придбати нову батарею або фрезу. Зауважте, що високоякісне обладнання має початкову ефективність понад 100%. Акумулятори мають назву "акумулятор" у назві, а різці (несподівано) мають у назві "різак".
Наступні відносини визначають переміщення та різання:
timecutting = sum(hardness of pixels cut) * 100 / cutter
cutterwear = 0.01 for each second cutting
cutters will not wear below 0.1 sharpness
timemoving = 1 + timecutting
batterydrain = 0.0178 for each second moving
changing direction takes 15 seconds and drains 0.2 from the battery
installing new equipment takes 300 seconds
Зауважте, що переміщення 1 одиниці без різання корисних копалин займає 1 гру секунду і використовує 0,0178 акумулятора. Таким чином, робот може загнати 5600 одиниць за 93 ігрові хвилини зі стандартним зарядом 100, якщо це не різання корисних копалин або поворот.
НОВО: Робот шириною 11 пікселів, тому він виріже до 11 пікселів з кожним піксельним рухом. Якщо для вирізання буде менше 11 пікселів, роботу знадобиться менше часу на переміщення та зменшить знос різака. Якщо колір пікселів не вказаний у файлі мінеральних даних, це вільний простір нульової твердості та нульове значення.
Запуск припиняється, коли закінчується час, акумулятор роботи вичерпується, частина робота перевищує межу зображення, надсилається незаконна команда або вимикається час спілкування робота.
Ваш бал - остаточне значення вантажу робота. Контролер видасть ваш результат та кінцеве зображення карти. Швидший вихід вашої програми реєструється у файлі robot.log. Якщо ваш робот помирає, у журналі може бути фатальна помилка.
Дані шахти
обладнання.txt:
Equipment_Name Cost Initial_Value
std_cutter 200 100
carbide_cutter 600 160
diamond_cutter 2000 250
forcehammer_cutter 7200 460
std_battery 200 100
advanced_battery 500 180
megapower_battery 1600 320
nuclear_battery 5200 570
mineraldata.txt:
Mineral_Name Color Value Hardness
sandstone (157,91,46) 0 3
conglomerate (180,104,102) 0 12
igneous (108,1,17) 0 42
hard_rock (219,219,219) 0 15
tough_rock (146,146,146) 0 50
super_rock (73,73,73) 0 140
gem_ore1 (0,255,0) 10 8
gem_ore2 (0,0,255) 30 14
gem_ore3 (255,0,255) 100 6
gem_ore4 (255,0,0) 500 21
моє зображення:
У зображенні шахти може бути альфа-канал, але це не використовується.
Контролер
Контролер повинен працювати з Python 2.7 і вимагає бібліотеки PIL. Мені було повідомлено, що Python Pillow - це зручне завантаження для Windows, щоб отримати модуль зображення PIL.
Запустіть контролер з програмою робота, cfg.py, файлами зображень та даних у поточному каталозі. Запропонований командний рядок:
python controller.py [<interpreter>] {<switches>} <robotprogram>
Наприклад: python controller.py java underminer.class
Контролер запише файл robot.log та файл finalmine.png наприкінці запуску.
#!/usr/bin/env python
# controller.py
# Control Program for the Robot Miner on PPCG.
# Tested on Python 2.7 on Ubuntu Linux. May need edits for other platforms.
# V1.0 First release.
# V1.1 Better error catching
import sys, subprocess, time
# Suggest installing Pillow here if you don't have PIL already
from PIL import Image, ImageDraw
from cfg import *
program = sys.argv[1:]
calltext = program + [MINEIMAGE, MINERALFILE, EQUIPMENTFILE]
errorlog = open(ERRORFILE, 'wb')
process = subprocess.Popen(calltext,
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=errorlog)
image = Image.open(MINEIMAGE)
draw = ImageDraw.Draw(image)
BLACK, ORANGE, WHITE = (0,0,0), (255,160,160), (255,255,255)
W,H = image.size
dirmap = dict(right=(1,0), left=(-1,0), up=(0,-1), down=(0,1))
# read in mineral file (Name, Color, Value, Hardness):
data = [v.split() for v in open(MINERALFILE)][1:]
mineralvalue = dict((eval(color), int(value)) for
name, color, value, hard in data)
hardness = dict((eval(color), int(hard)) for
name, color, value, hard in data)
# read in the equipment list:
data = [v.split() for v in open(EQUIPMENTFILE)][1:]
equipment = dict((name, (int(cost), float(init))) for
name, cost, init in data)
# Set up simulation variables:
status = 'OK'
rx, ry, direction = START_X, START_Y, START_DIR # center of robot
cargo, battery, cutter = 0, 100.0, 100.0
clock = ENDSHIFT
size = ROBOTSIZE / 2
msgfmt = '%u %u %u %u %u %u %s'
snapnum = 1
def mkcutlist(x, y, direc, size):
dx, dy = dirmap[direc]
cx, cy = x+dx*(size+1), y+dy*(size+1)
output = [(cx, cy)]
for s in range(1, size+1):
output += [ (cx+dy*s, cy+dx*s), (cx-dy*s, cy-dx*s)]
return output
def send(msg):
process.stdin.write((msg+'\n').encode('utf-8'))
process.stdin.flush()
def read():
return process.stdout.readline().decode('utf-8')
time.sleep(INITTIME)
while clock > 0:
try:
start = time.time()
send(msgfmt % (clock, cargo, battery, cutter, rx, ry, direction))
inline = read()
if time.time() - start > TIMELIMIT:
status = 'Move timeout'
break
except:
status = 'Robot comslink failed'
break
# Process command:
movecount = 0
try:
arg = inline.split()
cmd = arg.pop(0)
if cmd == 'buy':
if ry <= START_Y and arg and arg[0] in equipment:
cost, initperc = equipment[arg[0]]
if cost <= cargo:
cargo -= cost
if 'battery' in arg[0]:
battery = initperc
elif 'cutter' in arg[0]:
cutter = initperc
clock -= 300
elif cmd == 'direction':
if arg and arg[0] in dirmap:
direction = arg[0]
clock -= 15
battery -= 0.2
elif cmd == 'move':
if arg and arg[0].isdigit():
movecount = abs(int(arg[0]))
elif cmd == 'snapshot':
image.save('snap%04u.png' % snapnum)
snapnum += 1
except:
status = 'Robot command malfunction'
break
for move in range(movecount):
# check image boundaries
dx, dy = dirmap[direction]
rx2, ry2 = rx + dx, ry + dy
print rx2, ry2
if rx2-size < 0 or rx2+size >= W or ry2-size < 0 or ry2+size >= H:
status = 'Bounds exceeded'
break
# compute time to move/cut through 1 pixel
try:
cutlist = mkcutlist(rx2, ry2, direction, size)
colors = [image.getpixel(pos)[:3] for pos in cutlist]
except IndexError:
status = 'Mining outside of bounds'
break
work = sum(hardness.get(c, 0) for c in colors)
timetaken = work * 100 / cutter
cutter = max(0.1, cutter - timetaken / 100)
clock -= 1 + int(timetaken + 0.5)
battery -= (1 + timetaken) / 56
if battery <= 0:
status = 'Battery exhausted'
break
cargo += sum(mineralvalue.get(c, 0) for c in colors)
draw.rectangle([rx-size, ry-size, rx+size+1, ry+size+1], BLACK, BLACK)
rx, ry = rx2, ry2
draw.rectangle([rx-size, ry-size, rx+size+1, ry+size+1], ORANGE, WHITE)
if clock <= 0:
break
if status != 'OK':
break
del draw
image.save('finalmine.png')
if status in ('Battery exhausted', 'OK'):
print 'Score = %s' % cargo
send('endshift')
else:
print 'Error: %s at clock %s' % (status, clock)
send('failed')
time.sleep(0.3)
process.terminate()
Зв'язаний файл конфігурації (не змінюється):
# This is cfg.py
# Scenario files:
MINEIMAGE = 'testmine.png'
MINERALFILE = 'mineraldata.txt'
EQUIPMENTFILE = 'equipment.txt'
# Mining Robot parameters:
START_X = 270
START_Y = 28
START_DIR = 'down'
ROBOTSIZE = 11 # should be an odd number
ENDSHIFT = 24 * 60 * 60 # seconds in an 24 hour shift
INITTIME = 2.0
TIMELIMIT = 0.1
ERRORFILE = 'robot.log'
Формат відповідей
У відповідях має бути назва, включаючи мову програмування, ім'я робота та остаточну оцінку (наприклад, Python 3 , Tunnel Terror , 1352 ). Орган відповіді повинен мати ваш код та остаточне зображення карти міни. Інші зображення чи анімації також вітаються. Переможцем стане робот з найкращим балом.
Інші правила
- Загальні лазівки заборонені.
- Якщо ви використовуєте генератор випадкових чисел, ви повинні твердо кодувати насіння у вашій програмі, щоб відтворити запуск програми. Хтось інший повинен мати змогу запустити вашу програму та отримати такий самий остаточний мінний образ та бал.
- Ваша програма повинна бути запрограмована для будь-якого мого зображення. Ви не повинні кодувати свою програму для цих файлів даних або цього розміру зображення, макету мінералу, макета тунелю тощо. Якщо я підозрюю, що робот порушує це правило, я залишаю за собою право змінити шахтне зображення та / або файли даних.
Правки
- Пояснили правило відповіді 0,1 секунди.
- Розширено на роботах, запускаючи параметри і файли командного рядка.
- Додана нова версія контролера з кращим виявленням помилок.
- Додано примітку robot.log.
- Пояснили твердість та значення мінералу за замовчуванням.
- Пояснили обладнання акумулятора проти різака.
- Зроблено роботом розміром 11 явним.
- Додано розрахунки часу, зносу різця та акумулятора.