Ваша программа будет управлять горным роботом, ищущим под землей ценные полезные ископаемые. Ваш робот сообщит контроллеру, куда вы хотите переместить и копать, а контроллер предоставит обратную связь о состоянии вашего робота.
Первоначально вашему роботу будет предоставлена карта с изображением шахты с уже имеющимися шахтными стволами и файл данных, указывающий значение и твердость минералов в шахте. Затем ваш робот будет перемещаться по шахтам в поисках ценных полезных ископаемых. Ваш робот может копаться в земле, но замедляется тяжелым камнем.
Робот, который вернется с самым ценным грузом после 24-часовой смены, станет победителем. Это может показаться сложной задачей, но сделать простого майнингового робота просто (см. Ответ на пример Sample Mining Robot ниже).
операция
Ваша программа будет запущена контроллером с изображением шахты, данными о минералах и именами оборудования. Роботы могут использовать данные о рудниках и минералах, чтобы найти ценную руду и избежать твердых пород. Робот также может захотеть купить оборудование из списка оборудования.
например: 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). Направление - это текущее направление, в котором стоит робот (влево, вправо, вверх, вниз).
Когда ваш робот получит данные «завершенное смещение» или «сбой», ваша программа будет вскоре остановлена. Возможно, вы захотите, чтобы ваш робот сначала записывал данные отладки / производительности в файл.
Есть 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 пикселей, роботу потребуется меньше времени для перемещения, что приведет к меньшему износу резака. Если цвет пикселя не указан в файле данных о минералах, это свободное пространство с нулевой твердостью и нулевым значением.
Прогон прекращается, когда время истекает, батарея робота разряжена, часть робота выходит за границы изображения, отправляется недопустимая команда или время ожидания связи робота.
Ваша оценка является окончательной стоимостью груза робота. Контроллер выведет ваш счет и окончательное изображение карты. Вывод stderr вашей программы регистрируется в файле robot.log. Если ваш робот умирает, фатальная ошибка может быть в журнале.
Данные шахты
equipment.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 явно.
- Добавлены расчеты времени, износа резца и аккумулятора.