एक खनन रोबोट बनाएँ


12

आपका कार्यक्रम मूल्यवान खनिजों के लिए भूमिगत खोज करने वाले खनन रोबोट को नियंत्रित करेगा। आपका रोबोट उस नियंत्रक को बताएगा जहां आप स्थानांतरित करना चाहते हैं और खोदना चाहते हैं, और नियंत्रक आपके रोबोट की स्थिति पर प्रतिक्रिया प्रदान करेगा।

प्रारंभ में आपके रोबोट को पहले से मौजूद कुछ खनन शाफ्ट के साथ खदान का एक छवि मानचित्र दिया जाएगा, और खदान में खनिजों के मूल्य और कठोरता को निर्दिष्ट करने वाली एक डेटा फ़ाइल। आपका रोबोट तब खदानों के माध्यम से खदान में मूल्यवान खनिजों की तलाश करेगा। आपका रोबोट पृथ्वी के माध्यम से खुदाई कर सकता है, लेकिन हार्ड रॉक द्वारा धीमा हो जाता है।

छोटी खान छवि

24 घंटे की शिफ्ट के बाद सबसे मूल्यवान कार्गो के साथ लौटने वाला रोबोट विजेता होगा। यह एक जटिल चुनौती हो सकती है, लेकिन एक बुनियादी खनन रोबोट बनाना आसान है (नीचे नमूना खनन रोबोट उत्तर देखें)।

ऑपरेशन

आपका कार्यक्रम नियंत्रक द्वारा खान छवि, खनिज डेटा और उपकरण फ़ाइल नाम के साथ शुरू किया जाएगा। रोबोट मूल्यवान अयस्क को खोजने और कठोर चट्टान से बचने के लिए खान छवि और खनिज डेटा का उपयोग कर सकते हैं। रोबोट उपकरण सूची से उपकरण खरीदना भी चाह सकता है।

उदाहरण के लिए: python driller.py mineimage.png minerals.txt equipmentlist.txt

2 सेकंड के प्रारंभिक काल के बाद, नियंत्रक स्टड और स्टडआउट के माध्यम से रोबोट प्रोग्राम के साथ संचार करता है। स्थिति संदेश प्राप्त करने के बाद रोबोट को 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 का उपयोग करता है। तो रोबोट 93 खेल मिनटों में मानक 100 चार्ज पर 5600 यूनिट चला सकता है, अगर वह खनिजों को नहीं काट रहा हो या मोड़ रहा हो।

नई: रोबोट 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

मेरी छवि:

मेरा परीक्षण करो

मेरी छवि में एक अल्फा चैनल हो सकता है, लेकिन इसका उपयोग नहीं किया जाता है।

नियंत्रक

नियंत्रक को 2.7 पायथन के साथ काम करना चाहिए और पीआईएल लाइब्रेरी की आवश्यकता है। मुझे सूचित किया गया है कि पीआईएल छवि मॉड्यूल प्राप्त करने के लिए पायथन तकिया एक विंडोज फ्रेंडली डाउनलोड है।

वर्तमान निर्देशिका में रोबोट प्रोग्राम, cfg.py, छवि और डेटा फ़ाइलों के साथ नियंत्रक प्रारंभ करें। सुझाई गई कमांड लाइन है:

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

उदाहरण के लिए: python controller.py java underminer.class

कंट्रोलर एक रोबोट.लॉग फाइल और रन के अंत में एक फाइनलम.पिंग फाइल लिखेगा।

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

उत्तर प्रारूप

जवाब में प्रोग्रामिंग भाषा, रोबोट का नाम और अंतिम स्कोर (जैसे पायथन 3 , टनल टेरर , 1352 ) सहित एक शीर्षक होना चाहिए । उत्तर निकाय में आपका कोड और अंतिम खदान मानचित्र छवि होनी चाहिए। अन्य छवियों या एनिमेशन का भी स्वागत है। विजेता सर्वश्रेष्ठ स्कोर वाला रोबोट होगा।

अन्य नियम

  • आम खामियों को निषिद्ध है।
  • यदि आप एक यादृच्छिक संख्या जनरेटर का उपयोग करते हैं, तो आपको अपने प्रोग्राम में एक बीज को हार्डकोड करना चाहिए, ताकि आपका प्रोग्राम रन प्रजनन योग्य हो। किसी और को आपके प्रोग्राम को चलाने और उसी अंतिम खान छवि और स्कोर को प्राप्त करने में सक्षम होना चाहिए।
  • आपका प्रोग्राम किसी भी माइन इमेज के लिए प्रोग्राम होना चाहिए । आपको इन डेटा फ़ाइलों या इस छवि आकार, खनिज लेआउट, सुरंग लेआउट, आदि के लिए अपने कार्यक्रम को कोड नहीं करना चाहिए । अगर मुझे संदेह है कि एक रोबोट इस नियम को तोड़ रहा है, तो मैं खान छवि और / या डेटा फ़ाइलों को बदलने का अधिकार सुरक्षित रखता हूं।

संपादित करता

  • 0.1 सेकंड रेस्पॉन्स नियम समझाया।
  • रोबोट पर कमांड लाइन विकल्प और फाइलें शुरू करने का विस्तार।
  • बेहतर त्रुटि पकड़ने के साथ नया नियंत्रक संस्करण जोड़ा गया।
  • जोड़ा गया Robot.log नोट।
  • डिफ़ॉल्ट खनिज कठोरता और मूल्य समझाया।
  • समझाया बैटरी बनाम कटर उपकरण।
  • रोबोट का आकार 11 स्पष्ट किया गया।
  • समय, कटर पहनने और बैटरी के लिए गणना जोड़ा गया।

2
@TApicella 1. रोबोट को एक तर्क के रूप में छवि फ़ाइल नाम मिलता है, और इसे पढ़ सकते हैं और इसे पसंद के रूप में संसाधित कर सकते हैं। रोबोट चलते ही कंट्रोलर्स की इमेज बदल जाएगी और रोबोट उसे देख नहीं पाएगा। रोबोट PIL या अन्य OSS थर्ड पार्टी लाइब्रेरी का उपयोग कर सकते हैं। 2. रोबोट के पास आरंभ करने के लिए 2 सेकंड होते हैं और फिर 0.1 सेकंड प्रति कमांड प्रतिक्रिया होती है।
नाइट

1
आपको प्रश्न में 0.1 सेकंड प्रति कमांड प्रतिक्रिया का दस्तावेज़ देना चाहिए।
पीटर टेलर

1
@KeithRandall No. आपको कमांड लाइन पर दिए गए फ़ाइल नाम से छवि और 2 डेटा फ़ाइलों को पढ़ना चाहिए। उन्हें बदला जा सकता है।
लॉजिक नाइट

1
@TApicella मैंने पायथन फ्रेमवर्क के साथ एक और उत्तर जोड़ा है जो मदद कर सकता है।
नाइट

2
यह एक विशेषता है। अपने लाभ के लिए इसका उपयोग करें यदि आप :)
नाइट नाइट

जवाबों:


3

अजगर 2, नमूना खान, 350

यह खनन रोबोट के लिए न्यूनतम कोड का एक उदाहरण है। यह सीधे नीचे खोदता है जब तक कि इसकी बैटरी बाहर नहीं निकलती (सभी रोबोट नीचे इंगित करना शुरू करते हैं)। यह केवल 350 का स्कोर अर्जित करता है। याद रखें स्टडआउट फ्लश करें अन्यथा नियंत्रक लटका रहेगा।

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

नमूना खनिक पथ


2

पायथन 2, रोबोट माइनर पायथन टेम्प्लेट, 410

यह एक खनन रोबोट टेम्पलेट है जिसमें दिखाया गया है कि एक रोबोट कैसे संचालित होता है और अपने स्वयं के रोबोट के निर्माण के लिए एक रूपरेखा प्रदान करता है। खनिज डेटा का विश्लेषण करने के लिए एक अनुभाग है, और कार्यों के साथ जवाब देने के लिए एक अनुभाग है। प्लेसहोल्डर एल्गोरिदम अच्छा नहीं करते हैं। रोबोट कुछ मूल्यवान खनिज पाता है, लेकिन पर्याप्त प्रतिस्थापन बैटरी और कटर खरीदने के लिए पर्याप्त नहीं है। यह एक मृत बैटरी के साथ सतह पर दूसरी बार जाता है।

एक बेहतर योजना यह है कि मूल्यवान खनिजों के करीब जाने और खुदाई को कम करने के लिए मौजूदा सुरंगों का उपयोग किया जाए।

ध्यान दें कि यह रोबोट प्रत्येक स्थिति संदेश की एक लॉग फ़ाइल लिखता है जो इसे प्राप्त करता है ताकि आप एक रन के बाद निर्णय की जांच कर सकें।

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

अंतिम मेरा नक्शा


आपको बहुत धन्यवाद, नियंत्रक और रोबोट कार्यक्रम के बीच बातचीत को चलाने वाले लूप को उजागर करना वास्तव में सहायक है।
TApicella
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.