あなたのプログラムは、貴重な鉱物を地下で検索する採掘ロボットを制御します。ロボットは、移動して掘りたい場所をコントローラーに伝え、コントローラーはロボットの状態に関するフィードバックを提供します。
最初に、いくつかの採掘シャフトがすでに存在する鉱山のイメージマップと、鉱山内の鉱物の値と硬度を指定するデータファイルがロボットに提供されます。次に、ロボットがシャフトを移動して、採掘する貴重な鉱物を探します。ロボットは地球を掘ることができますが、ハードロックによって速度が低下します。
24時間のシフトの後、最も価値のある貨物で戻ってくるロボットが勝者になります。複雑な課題のように思えるかもしれませんが、基本的なマイニングロボットを作成するのは簡単です(以下のサンプルマイニングロボットの回答を参照)。
操作
プログラムは、鉱山の画像、鉱物のデータ、および機器のファイル名を使用して、コントローラーによって開始されます。ロボットは、鉱山の画像と鉱物のデータを使用して貴重な鉱石を見つけ、硬い岩を避けます。ロボットは、機器リストから機器を購入することもできます。
例えば: 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%を超えることに注意してください。バッテリーの名前には「battery」という文字列があり、(サプライズ)カッターの名前には「cutter」があります。
次の関係は、移動と切断を定義します。
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を使用します。したがって、ロボットは、ミネラルを切断したり回転させたりしない場合、標準の100回の充電で93ゲーム分で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
ミネラルデータ.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は、PILイメージモジュールを取得するためのWindowsフレンドリーなダウンロードであることがわかりました。
現在のディレクトリにあるロボットプログラム、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を明示的にしました。
- 時間、カッターの摩耗、およびバッテリーの計算が追加されました。