Bir Maden Robotu İnşa Et


12

Programınız, yeraltında değerli mineralleri araştıran bir maden robotunu kontrol edecektir. Robotunuz denetleyiciye nereye taşımak ve kazmak istediğinizi söyler ve denetleyici robot durumunuz hakkında geri bildirim sağlar.

Başlangıçta robotunuza bazı madencilik şaftları bulunan madenin bir görüntü haritası ve madendeki minerallerin değerini ve sertliğini belirten bir veri dosyası verilecektir. Robotunuz daha sonra madenler için değerli mineraller arayan şaftlarda hareket edecektir. Robotunuz dünyayı kazabilir, ancak sert kaya tarafından yavaşlatılır.

küçük mayın görüntü

24 saatlik vardiyadan sonra en değerli kargo ile geri dönen robot kazanan olacak. Karmaşık bir meydan okuma gibi görünebilir, ancak temel bir madencilik robotu yapmak basittir (aşağıdaki Örnek Madencilik Robotu cevabına bakın).

Operasyon

Programınız mayın görüntüsü, mineral verileri ve ekipman dosya adları ile kontrolör tarafından başlatılacaktır. Robotlar maden cevheri ve mineral verilerini değerli cevher bulmak ve sert kayalardan kaçınmak için kullanabilirler. Robot ayrıca ekipman listesinden ekipman satın almak isteyebilir.

Örneğin: python driller.py mineimage.png minerals.txt equipmentlist.txt

2 saniyelik başlatma süresinden sonra, kontrolör robot programı ile stdin ve stdout aracılığıyla iletişim kurar. Robotlar, bir durum mesajı aldıktan sonra 0,1 saniye içinde bir eylemle yanıt vermelidir.

Her dönüşte, kontrolör robota bir durum satırı gönderir:

timeleft cargo battery cutter x y direction

Örneğin: 1087 4505 34.65 88.04 261 355 right

Tam sayı timeleft, vardiya sonundan önce kalan oyun saniye sayısıdır. cargoŞu ana kadar daha az ekipman için ne ödemiş mayınlı olan minerallerin tamsayı değeridir. batterySeviye Kalan pil şarj bir tamsayı yüzdesidir. Tam cuttersayı seviyesi, standart değerin yüzdesi olarak kesicinin mevcut keskinliğidir. xvey değerler (0, 0) de sol üst köşesinden başvurulan robot pozisyonuyla pozitif tam sayılardır. Yön, robotun baktığı geçerli yöndür (sol, sağ, yukarı, aşağı).

Robotunuz 'son kaydırma' veya 'başarısız' girişi aldığında, programınız yakında sonlandırılacak. Robotunuzun önce bir dosyaya hata ayıklama / performans verileri yazmasını isteyebilirsiniz.

Denetleyicinin kabul edeceği 4 olası komut vardır. direction left|right|up|downrobotunuzu bu yöne yönlendirecek ve 15 oyun-saniye gerektirecektir. move <integer>robotunuza, kesilen minerallerin sertliğine ve kesicinizin keskinliğine bağlı olarak zaman alan birçok birimi ileriye doğru hareket ettirmesi veya kazması talimatını verecektir (aşağıya bakınız). buy <equipment>belirtilen ekipmanı kuracak ve maliyeti kargo değerinizden düşecektir, ancak yalnızca robot yüzeydeyse (y değeri <= başlangıç ​​y değeri). Ekipman kurulumu 300 oyun saniyesini alır. Özel komut snapshot, geçerli mayın görüntüsünü diske yazar ve oyun süresi almaz. Robotunuzda hata ayıklamak veya animasyonlar oluşturmak için anlık görüntüleri kullanabilirsiniz.

Robotunuz 100 pil ve 100 kesici keskinliğiyle başlayacaktır. Taşıma ve tornalama az miktarda pil gücü kullanır. Kazma çok daha fazlasını kullanır ve minerallerin sertliğinin ve kesicinin mevcut keskinliğinin bir fonksiyonudur. Robotunuz mineralleri kazdıkça, kesici zamanın ve minerallerin sertliğine bağlı olarak keskinliğini kaybedecektir. Robotunuzun yeterli kargo değeri varsa, yeni bir pil veya kesici satın almak için yüzeye dönebilir. Yüksek kaliteli ekipmanın ilk etkinliği% 100'den fazladır. Piller adında "pil" dizesine ve (sürpriz) kesicilerin adında "kesici" dizeye sahiptir.

Aşağıdaki ilişkiler hareket etmeyi ve kesmeyi tanımlar:

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

Herhangi bir mineral kesmeden 1 birim hareket etmenin 1 oyun saniye sürdüğünü ve pili 0,0178 kullandığını unutmayın. Böylece robot, mineralleri kesmiyor veya dönmüyorsa, standart bir 100 şarjla 93 oyun dakikada 5600 üniteyi kullanabilir.

YENİ: Robot 11 piksel genişliğindedir, bu nedenle her hareket pikseli ile 11 piksele kadar keser. Kesilecek 11 pikselden daha az varsa, robotun hareket etmesi daha az zaman alacak ve kesicide daha az aşınmaya neden olacaktır. Mineral veri dosyasında bir piksel rengi belirtilmezse, sıfır sertlik ve sıfır değerinde boş alan olur.

Süre bittiğinde, robot pili bittiğinde, robotun bir kısmı görüntü sınırını aştığında, geçersiz bir komut gönderildiğinde veya robot iletişimi zaman aşımına uğradığında çalışma sonlandırılır.

Puanınız robot kargonun son değeridir. Kontrolör puanınızı ve son harita görüntüsünü verir. Programınızın stderr çıktısı robot.log dosyasına kaydedilir. Robotunuz ölürse, ölümcül hata günlükte olabilir.

Maden Verileri

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

mayın görüntü:

test mayını

Mayın görüntüsü alfa kanalına sahip olabilir, ancak bu kullanılmaz.

Kontrol eden, denetleyici

Denetleyici Python 2.7 ile çalışmalı ve PIL kitaplığı gerektirir. Python Yastık'ın PIL görüntü modülünü almak için Windows dostu bir indirme olduğu konusunda bilgilendirildim.

Denetleyiciyi geçerli dizindeki robot programı, cfg.py, resim ve veri dosyalarıyla başlatın. Önerilen komut satırı:

python controller.py [<interpreter>] {<switches>} <robotprogram>

Örneğin: python controller.py java underminer.class

Denetleyici, çalışmanın sonunda bir robot.log dosyası ve bir finalmine.png dosyası yazar.

#!/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()

Bağlı yapılandırma dosyası (değiştirilmeyecek):

# 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'

Yanıt Biçimi

Cevaplar programlama dili, robot adı ve final skorunu içeren bir başlığa sahip olmalıdır ( Python 3 , Tünel Terörü , 1352 gibi) ). Cevap gövdesinin kodu ve son maden haritası resmi olmalıdır. Diğer resimler veya animasyonlar da kabul edilir. Kazanan en iyi puanı alan robot olacak.

Diğer Kurallar

  • Ortak boşluklar yasaktır.
  • Rastgele bir sayı üreteci kullanıyorsanız, program çalıştırmanızın tekrar üretilebilmesi için programınızdaki bir tohumu kodlamalısınız. Başka biri programınızı çalıştırıp aynı son mayın imajını ve skorunu elde edebilmelidir.
  • Programınız herhangi bir mayın görüntüsü için programlanmalıdır . Programınızı bu veri dosyaları veya bu görüntü boyutu, mineral düzeni, tünel düzeni vb. İçin kodlamamalısınız. Bir robotun bu kuralı ihlal ettiğinden şüpheleniyorsam, mayın görüntüsünü ve / veya veri dosyalarını değiştirme hakkını saklı tutarım.

Düzenlemeler

  • 0.1 saniyelik yanıt kuralı açıklandı.
  • Robot başlatma komut satırı seçenekleri ve dosyalarında genişletildi.
  • Daha iyi hata yakalama özelliğine sahip yeni denetleyici sürümü eklendi.
  • Robot.log notu eklendi.
  • Açıklanan varsayılan mineral sertliği ve değeri.
  • Açıklayıcı pil vs kesici ekipman.
  • Robot boyutunu 11 açık hale getirdi.
  • Zaman, kesici aşınması ve pil için hesaplamalar eklendi.

2
@TApicella 1. Robotlar görüntü dosya adını argüman olarak alırlar ve istedikleri gibi okuyabilir ve işleyebilirler. Robot hareket ettikçe kontrolör görüntüsü değişecek ve robot bunu göremeyecektir. Robotlar PIL veya diğer OSS üçüncü taraf kütüphanelerini kullanabilir. 2. Robotların başlatılması için 2 saniye ve komut yanıtı başına 0.1 saniye vardır.
Mantık Şövalyesi

1
Sorudaki komut yanıtı başına 0,1 saniyeyi belgelemelisiniz.
Peter Taylor

1
@KeithRandall Hayır. Komut satırında verilen dosya adlarından resim ve 2 veri dosyasını okumalısınız. Bunlar değiştirilebilir.
Mantık Şövalyesi

1
@TApicella Yardımcı olabilecek bir Python çerçevesi ile başka bir cevap ekledim.
Mantık Şövalyesi

2
Bu bir özellik. Mümkünse avantajınıza kullanın :)
Logic Knight

Yanıtlar:


3

Python 2, Örnek Madencisi, 350

Bu bir maden robotu için minimum kodun bir örneğidir. Sadece pili bitene kadar aşağıya doğru kazar (tüm robotlar aşağıya doğru bakmaya başlar). Sadece 350 puan kazanır. Stdout'u yıkamayı unutmayın, aksi takdirde kontrol cihazı asılır.

import sys
# Robots are started with 3 arguments:
mineimage, mineralfile, equipmentfile = sys.argv[1:4]
raw_input()           # ignore first status report
print 'move 1000'     # dig down until battery dies
sys.stdout.flush()    # remember to flush stdout
raw_input()           # wait for end message

örnek madenci yolu


2

Python 2, Robot Madencisi Python Şablonu, 410

Bu, bir robotun nasıl çalıştığını göstermek ve kendi robotlarınızı oluşturmak için bir çerçeve sağlamak için bir madencilik robot şablonu. Mineral verileri analiz etmek için bir bölüm ve eylemlere yanıt vermek için bir bölüm vardır. Yer tutucu algoritmaları iyi sonuç vermez. Robot bazı değerli mineraller bulur, ancak yeterli yedek pil ve kesici satın almak için yeterli değildir. Yüzeye giderken ölü bir pil ile ikinci kez durur.

Daha iyi bir plan, değerli minerallere yaklaşmak ve kazmayı en aza indirmek için mevcut tünelleri kullanmaktır.

Bu robotun aldığı her durum mesajının bir günlük dosyasını yazdığından, çalıştırmadan sonra kararlarını kontrol edebileceğinizi unutmayın.

import sys
from PIL import Image

MINEIMAGE, MINERALFILE, EQUIPMENTFILE = sys.argv[1:4]
image = Image.open(MINEIMAGE)
W,H = image.size
robotwidth = 11
halfwidth = robotwidth / 2

# 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 = [(name, int(cost), float(init)) for 
    name, cost, init in data]
# Find the cheapest battery and cutter for later purchase:
minbatcost, minbatname = min([(c,n) for 
    n,c,v in equipment if n.endswith('battery')])
mincutcost, mincutname = min([(c,n) for 
    n,c,v in equipment if n.endswith('cutter')])

# process the mine image to find good places to mine:
goodspots = [0] * W
for ix in range(W):
    for iy in range(H):
        color = image.getpixel((ix, iy))[:3]   # keep RGB, lose Alpha
        value = mineralvalue.get(color, 0)
        hard = hardness.get(color, 0)
        #
        # -------------------------------------------------------------
        # make a map or list of good areas to mine here
        if iy < H/4:
            goodspots[ix] += value - hard/10.0
        # (you will need a better idea than this)
goodshafts = [sum(goodspots[i-halfwidth : i+halfwidth+1]) for i in range(W)]
goodshafts[:halfwidth] = [-1000]*halfwidth   # stop robot going outside bounds
goodshafts[-halfwidth:] = [-1000]*halfwidth
bestspot = goodshafts.index(max(goodshafts))
# -----------------------------------------------------------------
#

dirmap = dict(right=(1,0), left=(-1,0), up=(0,-1), down=(0,1))
logging = open('mylog.txt', 'wt')
logfmt = '%7s %7s %7s %7s %7s %7s %7s\n'
logging.write(logfmt % tuple('Seconds Cargo Battery Cutter x y Direc'.split()))
surface = None
plan = []

while True:
    status = raw_input().split()
    if status[0] in ('endshift', 'failed'):
        # robot will be terminated soon
        logging.close()
        continue
    logging.write(logfmt % tuple(status))
    direction = status.pop(-1)
    clock, cargo, battery, cutter, rx, ry = map(int, status)
    if surface == None:
        surface = ry    # return to this level to buy equipment
    #
    # -----------------------------------------------------------------
    # Decide here to choose direction, move, buy, or snapshot
    if not plan and rx != bestspot:
        plan.append('direction right' if bestspot > rx else 'direction left')
        plan.append('move %u' % abs(bestspot - rx))
        plan.append('direction down')

    if plan:
        action = plan.pop(0)
    elif battery < 20 and cargo > minbatcost + mincutcost:
        action = 'direction up'
        move = 'move %u' % (ry - surface)
        buybat = 'buy %s' % minbatname
        buycut = 'buy %s' % mincutname
        plan = [move, buybat, buycut, 'direction down', move]
    else:
        action = 'move 1'
    # -----------------------------------------------------------------
    #
    print action
    sys.stdout.flush()

son maden haritası


Çok teşekkür ederim, kontrolör ve robot programı arasındaki etkileşimi yönlendiren döngüyü ortaya çıkarmak gerçekten yararlı.
TApicella
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.