Membangun Robot Penambangan

12

Program Anda akan mengontrol robot penambangan yang mencari mineral berharga di bawah tanah. Robot Anda akan memberi tahu pengontrol di mana Anda ingin bergerak dan menggali, dan pengontrol akan memberikan umpan balik tentang status robot Anda.

Awalnya robot Anda akan diberi peta gambar tambang dengan beberapa poros penambangan sudah ada, dan file data yang menentukan nilai dan kekerasan mineral di tambang. Robot Anda kemudian akan bergerak melalui poros mencari mineral berharga untuk ditambang. Robot Anda dapat menggali melalui bumi, tetapi diperlambat oleh hard rock.

gambar tambang kecil

Robot yang kembali dengan kargo paling berharga setelah shift 24 jam akan menjadi pemenang. Ini mungkin tampaknya menjadi tantangan yang rumit tetapi mudah untuk membuat robot penambangan dasar (lihat contoh Robot Penambangan contoh di bawah).

Operasi

Program Anda akan dimulai oleh pengontrol dengan gambar tambang, data mineral, dan nama file peralatan. Robot dapat menggunakan gambar tambang dan data mineral untuk menemukan bijih berharga dan menghindari hard rock. Robot juga mungkin ingin membeli peralatan dari daftar peralatan.

misalnya: python driller.py mineimage.png minerals.txt equipmentlist.txt

Setelah periode inisialisasi 2 detik, controller berkomunikasi dengan program robot melalui stdin dan stdout. Robot harus merespons dengan tindakan dalam 0,1 detik setelah menerima pesan status.

Setiap belokan, pengontrol mengirimkan robot garis status:

timeleft cargo battery cutter x y direction

misalnya: 1087 4505 34.65 88.04 261 355 right

Bilangan bulat timeleftadalah detik permainan tersisa sebelum akhir shift. Nilai cargointeger dari mineral yang telah Anda tambang sejauh ini lebih sedikit dari yang Anda bayarkan untuk peralatan. The batterylevel persentase bilangan bulat dari sisa daya baterai Anda. The cuttertingkat integer adalah ketajaman saat ini cutter sebagai persentase dari nilai standar. Nilai xdan yadalah bilangan bulat positif dengan posisi robot yang dirujuk dari sudut kiri atas pada (0, 0). Arahnya adalah arah saat robot menghadap (kiri, kanan, atas, bawah).

Ketika robot Anda menerima input 'pergeseran gigi' atau 'gagal', program Anda akan segera dihentikan. Anda mungkin ingin robot Anda menulis data debug / kinerja ke file terlebih dahulu.

Ada 4 perintah yang mungkin diterima oleh pengontrol. direction left|right|up|downakan mengarahkan robot Anda ke arah itu, dan membutuhkan 15 detik permainan. move <integer>akan menginstruksikan robot Anda untuk bergerak atau menggali banyak unit ke depan yang membutuhkan waktu tergantung pada kekerasan memotong mineral dan ketajaman pemotong Anda (lihat di bawah). buy <equipment>akan memasang peralatan yang ditentukan dan mengurangi biaya dari nilai muatan Anda, tetapi hanya jika robot ada di permukaan (nilai y <= mulai nilai y). Instalasi peralatan membutuhkan 300 detik permainan. Perintah khusus snapshotmenulis gambar tambang saat ini ke disk dan tidak memerlukan waktu permainan. Anda dapat menggunakan snapshot untuk men-debug robot Anda atau membuat animasi.

Robot Anda akan mulai dengan 100 baterai dan ketajaman 100 pemotong. Bergerak dan berputar menggunakan sedikit daya baterai. Menggali lebih banyak menggunakan dan merupakan fungsi dari kekerasan mineral dan ketajaman saat pemotong. Saat robot Anda menggali mineral, pemotong akan kehilangan ketajamannya, tergantung pada waktu yang diambil dan kekerasan mineral. Jika robot Anda memiliki nilai muatan yang cukup, ia dapat kembali ke permukaan untuk membeli baterai atau pemotong baru. Perhatikan bahwa peralatan berkualitas tinggi memiliki efektivitas awal lebih dari 100%. Baterai memiliki string "baterai" dalam nama dan pemotong (kejutan) memiliki "pemotong" dalam nama.

Hubungan berikut menentukan pemindahan dan pemotongan:

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

Perhatikan bahwa memindahkan 1 unit tanpa memotong mineral apa pun membutuhkan waktu 1 game detik dan menggunakan 0,0178 baterai. Jadi robot dapat menggerakkan 5600 unit dalam 93 menit permainan dengan biaya 100 standar, jika tidak memotong mineral atau berputar.

BARU: Robot ini memiliki lebar 11 piksel sehingga akan memotong hingga 11 piksel dengan setiap piksel gerakan. Jika ada kurang dari 11 piksel untuk dipotong, robot akan membutuhkan waktu lebih sedikit untuk bergerak, dan menyebabkan keausan pada pemotong lebih sedikit. Jika warna piksel tidak ditentukan dalam file data mineral, itu adalah ruang kosong tanpa kekerasan dan nilai nol.

Berlari dihentikan ketika waktu habis, baterai robot habis, bagian dari robot melebihi batas gambar, perintah ilegal dikirim, atau waktu komunikasi robot habis.

Skor Anda adalah nilai akhir dari kargo robot. Pengontrol akan menampilkan skor Anda dan gambar peta akhir. Output stderr dari program Anda dicatat dalam file robot.log. Jika robot Anda mati, kesalahan fatal mungkin ada di log.

Data Tambang

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

gambar tambang:

tes milikku

Gambar tambang mungkin memiliki saluran alfa, tetapi ini tidak digunakan.

Pengendali

Pengontrol harus bekerja dengan Python 2.7 dan membutuhkan pustaka PIL. Saya telah diberi tahu bahwa Bantal Python adalah unduhan ramah Windows untuk mendapatkan modul gambar PIL.

Mulai pengontrol dengan program robot, cfg.py, file gambar dan data di direktori saat ini. Baris perintah yang disarankan adalah:

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

Misalnya: python controller.py java underminer.class

Pengontrol akan menulis file robot.log dan file finalmine.png di akhir proses.

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

File konfigurasi yang ditautkan (tidak akan diubah):

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

Format Jawaban

Jawaban harus memiliki judul termasuk bahasa pemrograman, nama robot, dan skor akhir (seperti Python 3 , Tunnel Terror , 1352 ). Badan jawaban harus memiliki kode Anda dan gambar peta tambang terakhir. Gambar atau animasi lain juga diperbolehkan. Pemenang akan menjadi robot dengan skor terbaik.

Peraturan Lainnya

  • Celah umum dilarang.
  • Jika Anda menggunakan penghasil angka acak, Anda harus meng-hardcode sebuah seed dalam program Anda, agar program Anda berjalan dapat direproduksi. Orang lain harus dapat menjalankan program Anda dan mendapatkan gambar dan skor akhir tambang yang sama.
  • Program Anda harus diprogram untuk gambar tambang apa pun . Anda tidak boleh membuat kode program Anda untuk file data ini atau ukuran gambar ini , tata letak mineral, tata letak terowongan, dll. Jika saya menduga robot melanggar aturan ini, saya berhak mengubah gambar tambang dan / atau file data.

Suntingan

  • Menjelaskan aturan respons 0,1 detik.
  • Diperluas pada robot mulai opsi baris perintah dan file.
  • Menambahkan versi pengontrol baru dengan penangkapan kesalahan yang lebih baik.
  • Menambahkan catatan robot.log.
  • Dijelaskan kekerasan dan nilai mineral default.
  • Dijelaskan baterai vs peralatan pemotong.
  • Dibuat robot ukuran 11 eksplisit.
  • Menambahkan perhitungan untuk waktu, keausan pemotong, dan baterai.
Ksatria Logika
sumber
2
@TApicella 1. Robot mendapatkan nama file gambar sebagai argumen, dan dapat membaca dan memprosesnya sesuka mereka. Gambar pengendali akan berubah saat robot bergerak dan robot tidak akan dapat melihatnya. Robot dapat menggunakan PIL atau pustaka pihak ketiga OSS lainnya. 2. Robot memiliki 2 detik untuk menginisialisasi dan kemudian 0,1 detik per respons perintah.
Logic Knight
1
Anda harus mendokumentasikan 0,1 detik per respons perintah dalam pertanyaan.
Peter Taylor
1
@KeithRandall No. Anda harus membaca gambar dan 2 file data dari nama file yang diberikan pada baris perintah. Mereka mungkin berubah.
Logic Knight
1
@TApicella Saya telah menambahkan jawaban lain dengan kerangka kerja Python yang mungkin membantu.
Logic Knight
2
Itu fitur. Gunakan untuk keuntungan Anda jika Anda bisa :)
Logic Knight

Jawaban:

3

Python 2, Sample Miner, 350

Ini adalah contoh kode minimum untuk robot penambangan. Itu hanya menggali langsung ke bawah sampai baterai habis (semua robot mulai menunjuk ke bawah). Ini hanya menghasilkan skor 350. Ingat untuk menyiram stdout atau controller akan menggantung.

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

jalur sampel penambang

Ksatria Logika
sumber
2

Python 2, Robot Miner Template Python, 410

Ini adalah templat robot penambangan untuk menunjukkan bagaimana robot beroperasi dan menyediakan kerangka kerja untuk membangun robot Anda sendiri. Ada bagian untuk menganalisis data mineral, dan bagian untuk merespons dengan tindakan. Algoritma placeholder tidak bekerja dengan baik. Robot menemukan beberapa mineral berharga, tetapi tidak cukup untuk membeli baterai dan pemotong pengganti yang cukup. Itu berhenti dengan baterai mati dalam perjalanan ke permukaan untuk kedua kalinya.

Rencana yang lebih baik adalah menggunakan terowongan yang ada untuk mendekati mineral berharga dan meminimalkan penggalian.

Perhatikan bahwa robot ini menulis file log dari setiap pesan status yang diterimanya sehingga Anda dapat memeriksa keputusannya setelah dijalankan.

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()

peta tambang terakhir

Ksatria Logika
sumber
Terima kasih banyak, mengekspos loop yang mendorong interaksi antara pengontrol dan program robot sangat membantu.
TApicella