Su programa controlará un robot minero que busca minerales subterráneos valiosos. Su robot le dirá al controlador dónde desea moverse y excavar, y el controlador le proporcionará información sobre el estado de su robot.
Inicialmente, su robot recibirá un mapa de imagen de la mina con algunos pozos de minería ya presentes, y un archivo de datos que especifica el valor y la dureza de los minerales en la mina. Su robot se moverá a través de los ejes en busca de minerales valiosos para extraer. Su robot puede cavar a través de la tierra, pero es ralentizado por el rock duro.
El robot que regrese con la carga más valiosa después de un turno de 24 horas será el ganador. Puede parecer un desafío complicado, pero es simple hacer un robot de minería básico (vea la respuesta del Robot de minería de muestra a continuación).
Operación
El programa iniciará su programa con la imagen de la mina, los datos minerales y los nombres de los archivos del equipo. Los robots pueden usar la imagen de la mina y los datos de minerales para encontrar minerales valiosos y evitar rocas duras. El robot también puede querer comprar equipos de la lista de equipos.
p.ej: python driller.py mineimage.png minerals.txt equipmentlist.txt
Después de un período de inicialización de 2 segundos, el controlador se comunica con el programa del robot a través de stdin y stdout. Los robots deben responder con una acción dentro de 0.1 segundos después de recibir un mensaje de estado.
Cada turno, el controlador envía al robot una línea de estado:
timeleft cargo battery cutter x y direction
p.ej: 1087 4505 34.65 88.04 261 355 right
El número entero timeleft
es el juego que quedan segundos antes del final del turno. El
cargo
es el valor entero de los minerales que ha extraído hasta ahora menos de lo que ha pagado por el equipo. El battery
nivel es un porcentaje entero de la carga restante de la batería. El cutter
nivel entero es la nitidez actual del cortador como un porcentaje del valor estándar. Los valores x
y y
son enteros positivos con la posición del robot referenciada desde la esquina superior izquierda en (0, 0). La dirección es la dirección actual que enfrenta el robot (izquierda, derecha, arriba, abajo).
Cuando su robot recibe la entrada 'desplazamiento final' o 'fallido', su programa pronto terminará. Es posible que desee que su robot escriba primero los datos de depuración / rendimiento en un archivo.
Hay 4 comandos posibles que el controlador aceptará. direction
left|right|up|down
apuntará a su robot en esa dirección y requerirá 15 segundos de juego. move <integer>
le indicará a su robot que mueva o excave tantas unidades hacia adelante, lo que lleva tiempo dependiendo de la dureza del corte de minerales y la nitidez de su cortador (ver más abajo). buy <equipment>
instalará el equipo especificado y deducirá el costo del valor de su carga, pero solo si el robot está en la superficie (valor y <= valor y inicial). La instalación del equipo lleva 300 segundos de juego. El comando especial snapshot
escribe la imagen de mina actual en el disco y no requiere tiempo de juego. Puede usar instantáneas para depurar su robot o crear animaciones.
Su robot comenzará con 100 baterías y 100 nitidez de corte. Mover y girar utiliza una pequeña cantidad de batería. La excavación usa mucho más y es una función de la dureza de los minerales y la nitidez actual del cortador. A medida que su robot cava en minerales, el cortador perderá su agudeza, dependiendo del tiempo necesario y la dureza de los minerales. Si su robot tiene suficiente valor de carga, puede volver a la superficie para comprar una nueva batería o cortador. Tenga en cuenta que los equipos de alta calidad tienen una efectividad inicial de más del 100%. Las baterías tienen la cadena "batería" en el nombre y los cortadores (sorpresa) tienen "cortador" en el nombre.
Las siguientes relaciones definen movimiento y corte:
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
Tenga en cuenta que mover 1 unidad sin cortar minerales requiere 1 segundo de juego y usa 0.0178 de la batería. Por lo tanto, el robot puede conducir 5600 unidades en 93 minutos de juego con una carga estándar de 100, si no está cortando minerales o girando.
NUEVO: El robot tiene 11 píxeles de ancho, por lo que cortará hasta 11 píxeles con cada píxel de movimiento. Si hay menos de 11 píxeles para cortar, el robot tardará menos en moverse y causará menos desgaste en el cortador. Si no se especifica un color de píxel en el archivo de datos minerales, es un espacio libre de dureza cero y valor cero.
La ejecución finaliza cuando se agota el tiempo, la batería del robot se agota, una parte del robot excede el límite de la imagen, se envía un comando ilegal o se agota el tiempo de comunicación del robot.
Su puntaje es el valor final de la carga del robot. El controlador generará su puntaje y la imagen del mapa final. La salida stderr de su programa se registra en el archivo robot.log. Si su robot muere, el error fatal puede estar en el registro.
Los datos de la mina
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
imagen mía:
La imagen de la mina puede tener un canal alfa, pero esto no se usa.
El controlador
El controlador debería funcionar con Python 2.7 y requiere la biblioteca PIL. Me han informado que Python Pillow es una descarga amigable de Windows para obtener el módulo de imagen PIL.
Inicie el controlador con el programa del robot, cfg.py, archivos de imagen y datos en el directorio actual. La línea de comando sugerida es:
python controller.py [<interpreter>] {<switches>} <robotprogram>
P.ej: python controller.py java underminer.class
El controlador escribirá un archivo robot.log y un archivo finalmine.png al final de la ejecución.
#!/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()
El archivo de configuración vinculado (no se debe cambiar):
# 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'
Formato de respuesta
Las respuestas deben tener un título que incluya lenguaje de programación, nombre del robot y puntaje final (como Python 3 , Tunnel Terror , 1352 ). El cuerpo de la respuesta debe tener su código y la imagen final del mapa de la mina. Otras imágenes o animaciones son bienvenidas también. El ganador será el robot con la mejor puntuación.
Otras reglas
- Las lagunas comunes están prohibidas.
- Si usa un generador de números aleatorios, debe codificar una semilla en su programa, para que la ejecución de su programa sea reproducible. Alguien más debe poder ejecutar su programa y obtener la misma imagen y puntaje final de la mina.
- Su programa debe estar programado para cualquier imagen de mina. No debe codificar su programa para estos archivos de datos o este tamaño de imagen, diseño mineral, diseño de túnel, etc. Si sospecho que un robot está infringiendo esta regla, me reservo el derecho de cambiar los archivos de imagen y / o datos de la mina.
Ediciones
- Explicó la regla de respuesta de 0.1 segundos.
- Ampliado en las opciones y archivos de la línea de comandos de inicio del robot.
- Se agregó una nueva versión del controlador con una mejor captura de errores.
- Se agregó la nota robot.log.
- Explicación de la dureza y valor mineral predeterminados.
- Batería explicada vs equipo de corte.
- Hecho robot tamaño 11 explícito.
- Se agregaron cálculos de tiempo, desgaste del cortador y batería.
fuente
Respuestas:
Python 2, Sample Miner, 350
Este es un ejemplo del código mínimo para un robot minero. Simplemente cava hacia abajo hasta que se agota la batería (todos los robots comienzan a apuntar hacia abajo). Solo gana un puntaje de 350. Recuerde eliminar stdout o el controlador se bloqueará.
fuente
Python 2, plantilla de Python Robot Miner, 410
Esta es una plantilla de robot de minería para mostrar cómo funciona un robot y proporcionar un marco para construir sus propios robots. Hay una sección para analizar los datos minerales y una sección para responder con acciones. Los algoritmos de marcador de posición no funcionan bien. El robot encuentra algunos minerales valiosos, pero no lo suficiente como para comprar suficientes baterías y cortadores de repuesto. Se detiene con una batería descargada en su camino a la superficie por segunda vez.
Un mejor plan es utilizar los túneles existentes para acercarse a minerales valiosos y minimizar la excavación.
Tenga en cuenta que este robot escribe un archivo de registro de cada mensaje de estado que recibe para que pueda verificar sus decisiones después de una ejecución.
fuente