আপডেট: শুরু করার জন্য একটি পাইথন ফ্রেমওয়ার্ক যুক্ত করা হয়েছে।
স্পেস-স্টেশনটি ক্রাশ-বটগুলি পেরিয়ে গেছে। স্টেশনকে স্ব-ক্ষতিগ্রস্থ করার আগে আপনাকে অবশ্যই "খরগোশ" নামক আমাদের অনেক ব্যয়বহুল এবং ভঙ্গুর টেক-বটগুলি পরিচালনা করতে হবে, তবে ক্রাশার-বটগুলি করিডোরগুলিতে টহল দিচ্ছে।
আপনার প্রোগ্রামকে একটি এএসসিআইআই মানচিত্র দেওয়া হয় এবং প্রতিটি ঘুরে বলা হয় ক্রাশার-বটগুলি কোথায় এবং আপনার বর্তমান খরগোশগুলি। ক্রাশার-বটগুলি এড়িয়ে চলাকালীন আপনার প্রোগ্রামটি তখন আপনার খরগোশকে প্রস্থান টেল্পোর্টারের দিকে নিয়ে যেতে হবে।
ফাঁসি
পাইথন 2 নিয়ামকটি এর সাথে চালান:
python controller.py <mapfile> <turns> <seed> <runs> <prog>...
<prog> can be <interpreter> <yourprog> or similar.
বীজটি একটি ছোট পূর্ণসংখ্যা যা ক্রাশার এবং আপনার প্রোগ্রামের পিআরএনজির জন্য ব্যবহৃত হয় যাতে রানগুলি পুনরাবৃত্তিযোগ্য হয়। আপনার প্রোগ্রামটি ব্যবহার করা আসল বীজ নির্বিশেষে ধারাবাহিকভাবে সম্পাদন করা উচিত। বীজ শূন্য হলে, নিয়ামক প্রতিটি রানের জন্য একটি এলোমেলো বীজ ব্যবহার করবেন।
কন্ট্রোলার আপনার প্রোগ্রামটি মানচিত্রের পাঠ্য ফাইলের নাম এবং যুক্তি হিসাবে বীজের সাথে চালাবে। উদাহরণ:
perl wandomwabbits.pl large.map 322
যদি আপনার প্রোগ্রামটি একটি PRNG ব্যবহার করে, আপনি প্রদত্ত বীজ দিয়ে এটি আরম্ভ করা উচিত। নিয়ামক তারপরে STDIN এর মাধ্যমে আপনার প্রোগ্রামের আপডেটগুলি প্রেরণ করে এবং STDOUT এর মাধ্যমে আপনার খরগোশের গতিবিধিগুলি পড়েন।
প্রতিটি বাঁকটি নিয়ামক 3 লাইন আউটপুট দেবে:
turnsleft <INT>
crusher <x,y> <movesto|crushes> <x,y>; ...
rabbits <x,y> <x,y> ...
তারপরে প্রোগ্রামটি একটি লাইন আউটপুট দেওয়ার জন্য অপেক্ষা করে:
move <x,y> to <x,y>; ...
আপডেট: কন্ট্রোলার দ্বারা প্রথম লাইন প্রেরণের আগে আপনার প্রোগ্রামের শুরুতে 2 সেকেন্ড থাকবে।
যদি আপনার প্রোগ্রামটি নিয়ামক খরগোশের অবস্থান ইনপুটটির পরে চালগুলির সাথে সাড়া দিতে 0.5 সেকেন্ডের বেশি সময় নেয়, তবে নিয়ামকটি প্রস্থান করবে।
যদি গ্রিডে কোনও খরগোশ না থাকে তবে খরগোশের রেখার কোনও মান থাকবে না এবং আপনার প্রোগ্রামটির "খালি" স্ট্রিং লাইন আউটপুট করা উচিত।
প্রতিটি প্রোগ্রামে আপনার প্রোগ্রামের আউটপুট স্ট্রিমটি ফ্লাশ করতে ভুলবেন না বা নিয়ামকটি স্থির থাকতে পারে।
উদাহরণ
অগ্রগতি ইনপুট:
turnsleft 35
crusher 22,3 crushes 21,3; 45,5 movesto 45,4
rabbits 6,4 8,7 7,3 14,1 14,2 14,3
অগ্রগতি আউটপুট:
move 14,3 to 14,4; 14,2 to 14,3; 6,4 to 7,4
নিয়ামক যুক্তি
প্রতিটি টার্নের জন্য যুক্তি:
- যদি বাম দিকে শূন্য হয়, মুদ্রণ স্কোর এবং প্রস্থান করুন।
- প্রতিটি খালি শুরু কক্ষের জন্য, কোনও ক্রাশার চোখে না পড়লে একটি খরগোশ যুক্ত করুন।
- প্রতিটি পেষণকারী জন্য, সরানো দিক সিদ্ধান্ত (নীচে দেখুন)।
- প্রতিটি পেষণকারী জন্য, সম্ভব হলে সরান।
- যদি পেষণকারী কোনও খরগোশের স্থানে থাকে তবে খরগোশটি সরিয়ে ফেলুন।
- আউটপুট টার্নসেলफ्ट, ক্রাশ ক্রিয়া এবং প্রোগ্রামে খরগোশের অবস্থান।
- প্রোগ্রাম থেকে খরগোশের সরানোর অনুরোধগুলি পড়ুন।
- যদি খরগোশের অস্তিত্ব না থাকে বা চালানো সম্ভব না হয় তবে এড়িয়ে যান।
- খরগোশের প্রতিটি নতুন অবস্থান চক্রান্ত।
- খরগোশ যদি কোন ক্রাশকে আঘাত করে তবে খরগোশ ধ্বংস হয়ে যায়।
- খরগোশ যদি প্রস্থান টেলিফোনে থাকে তবে খরগোশ সরানো হয় এবং স্কোর বৃদ্ধি পায়।
- যদি খরগোশ সংঘর্ষ হয় তবে সেগুলি উভয়ই ধ্বংস হয়ে যায়।
প্রতিটি ক্রাশারের সর্বদা একটি শিরোনাম থাকে (এনএসইডাব্লু এর একটি)। একটি পেষণকারী প্রতিটি ঘুরে এই নেভিগেশন যুক্তি অনুসরণ করে:
- যদি একটি বা একাধিক খরগোশ 4 টি অর্থোগোনাল দিকের যে কোনওটিতে দৃশ্যমান হয় তবে নিকটতম খরগোশের একটিতে দিক পরিবর্তন করুন। নোট করুন যে ক্রাশাররা অন্য কোনও পেষণকারীকে অতীতে দেখতে পারে না।
- অন্যথায় সম্ভব হলে ওপেন ফরোয়ার্ড, বাম এবং ডান বিকল্পগুলির মধ্যে এলোমেলোভাবে চয়ন করুন।
- অন্যথায় যদি সামনে, বাম এবং ডানদিকে বাধা (দেয়াল বা অন্যান্য ক্রাশার) থাকে তবে পিছনে দিক নির্ধারণ করুন।
তারপরে প্রতিটি পেষণকারী জন্য:
- নতুন ক্রাশের দিকনির্দেশে যদি কোনও বাধা না থাকে তবে সরান (এবং সম্ভবত পিষ্ট)।
মানচিত্রের প্রতীক
মানচিত্রটি ASCII অক্ষরের একটি আয়তক্ষেত্রাকার গ্রিড। মানচিত্রটি দেয়াল
#
, করিডোরের স্পেস , খরগোশের শুরুর অবস্থান
s
, প্রস্থান টেলিকপোর্টার e
এবং পেষণকারী শুরুর অবস্থান নিয়ে গঠিত c
। উপরের বাম কোণটি অবস্থান (0,0)।
ছোট মানচিত্র
###################
# c #
# # ######## # # ##
# ###s # ####e#
# # # # ## ## #
### # ### # ## # #
# ## #
###################
পরীক্ষার মানচিত্র
#################################################################
#s ############################ s#
## ## ### ############ # ####### ##### ####### ###
## ## ### # # ####### ########## # # #### ###### ###
## ## ### # ############ ####### ########## ##### ####### ###
## ## ## # ####### ########## # # ##### #### #
## ### #### #### ######## ########## ##### #### ## ###
######### #### ######## ################ ####### #### ###
######### ################# ################ c ####### ###
######### ################## ####### ####### ###########
######### ################## ######## ####### ###########
##### ### c ###### ###################
# #### ### # # # # # # # # # # ###### ############## #
# ####### #### ### #### ##### ## #
# #### ### # # # # # # # # # # ### # ### ######### #
##### ### #### ### ##### ### # ######## ####
############## ### # # # # # # # # # # ####### ## ####### ####
#### #### #### ### ### # # ### ###### ####
## ### # # # # # # # # # # ### ### # ### ##### ####
##### ######## ### # # # ##### # # # # ### ### # ##### #### ####
##### ##### ###### c # ### ### ###### ### ####
## c ######################### ### ##### ####### ### ####
##### # ### ####### ######## ### ##### c ## ## ####
##### # ####### ########## ## ######## # ######## ## ####
######### # ####### ## # ## # # # ##### # ####
### ##### # ### # ############## # ### # ### ## # ####
# ## # ### ### # ############## # ### ##### ##### ## ####
### ## ## # ### # ######## #
#s ## ###################################################e#
#################################################################
উদাহরণস্বরূপ বড় মানচিত্র চালানো
স্কোর
আপনার প্রোগ্রামটি মূল্যায়ন করতে, পরীক্ষার মানচিত্র, 500 টার্ন, 5 রান এবং 0 বীজের সাহায্যে কন্ট্রোলার চালান Your টাই হওয়ার সময়ে সর্বাধিক ভোটের উত্তর জিতবে।
আপনার উত্তরে প্রবেশের নাম, ব্যবহৃত ভাষা এবং স্কোর সহ একটি শিরোনাম অন্তর্ভুক্ত করা উচিত। উত্তর সংস্থায়, দয়া করে বীজ সংখ্যার সাথে সম্পূর্ণ নিয়ামক স্কোর আউটপুট অন্তর্ভুক্ত করুন যাতে অন্যরা আপনার রান পুনরাবৃত্তি করতে পারে। উদাহরণ স্বরূপ:
Running: controller.py small.map 100 0 5 python bunny.py
Run Seed Score
1 965 0
2 843 6
3 749 11
4 509 10
5 463 3
Total Score: 30
আপনি স্ট্যান্ডার্ড এবং অবাধে উপলব্ধ লাইব্রেরি ব্যবহার করতে পারেন তবে স্ট্যান্ডার্ড লুফোলগুলি নিষিদ্ধ। প্রদত্ত বীজ, টার্ন গণনা, মানচিত্রের বৈশিষ্ট্য সেট বা অন্যান্য পরামিতিগুলির জন্য আপনার প্রোগ্রামটিকে অনুকূলিত করা উচিত নয়। আমি যদি এই বিধি লঙ্ঘনের সন্দেহ করি তবে আমি মানচিত্র পরিবর্তন, গণনা ঘুরিয়ে দেওয়ার এবং বীজের অধিকার সংরক্ষণ করি।
নিয়ামক কোড
#!/usr/bin/env python
# Control Program for the Rabbit Runner on PPCG.
# Usage: controller.py <mapfile> <turns> <seed> <runs> <prog>...
# Tested on Python 2.7 on Ubuntu Linux. May need edits for other platforms.
# v1.0 First release.
# v1.1 Fixed crusher reporting bug.
# v1.2 Control for animation image production.
# v1.3 Added time delay for program to initialise
import sys, subprocess, time, re, os
from random import *
# Suggest installing Pillow if you don't have PIL already
try:
from PIL import Image, ImageDraw
except:
Image, ImageDraw = None, None
GRIDLOG = True # copy grid to run.log each turn (off for speed)
MKIMAGE = False # animation image creation (much faster when off)
IMGWIDTH = 600 # animation image width estimate
INITTIME = 2 # Allow 2 seconds for the program to initialise
point = complex # use complex numbers as 2d integer points
ORTH = [1, -1, 1j, -1j] # all 4 orthogonal directions
def send(proc, msg):
proc.stdin.write((msg+'\n').encode('utf-8'))
proc.stdin.flush()
def read(proc):
return proc.stdout.readline().decode('utf-8')
def cansee(cell):
# return a dict of visible cells containing robots with distances
see = {} # see[cell] = dist
robots = rabbits | set(crushers)
if cell in robots:
see[cell] = 0
for direc in ORTH:
for dist in xrange(1,1000):
test = cell + direc*dist
if test in walls:
break
if test in robots:
see[test] = dist
if test in crushers:
break # can't see past them
return see
def bestdir(cr, direc):
# Decide in best direction for this crusher-bot
seen = cansee(cr)
prey = set(seen) & rabbits
if prey:
target = min(prey, key=seen.get) # Find closest
vector = target - cr
return vector / abs(vector)
obst = set(crushers) | walls
options = [d for d in ORTH if d != -direc and cr+d not in obst]
if options:
return choice(options)
return -direc
def features(fname):
# Extract the map features
walls, crusherstarts, rabbitstarts, exits = set(), set(), set(), set()
grid = [line.strip() for line in open(fname, 'rt')]
grid = [line for line in grid if line and line[0] != ';']
for y,line in enumerate(grid):
for x,ch in enumerate(line):
if ch == ' ': continue
cell = point(x,y)
if ch == '#': walls.add(cell)
elif ch == 's': rabbitstarts.add(cell)
elif ch == 'e': exits.add(cell)
elif ch == 'c': crusherstarts.add(cell)
return grid, walls, crusherstarts, rabbitstarts, exits
def drawrect(draw, cell, scale, color, size=1):
x, y = int(cell.real)*scale, int(cell.imag)*scale
edge = int((1-size)*scale/2.0 + 0.5)
draw.rectangle([x+edge, y+edge, x+scale-edge, y+scale-edge], fill=color)
def drawframe(runno, turn):
if Image == None:
return
scale = IMGWIDTH/len(grid[0])
W, H = scale*len(grid[0]), scale*len(grid)
img = Image.new('RGB', (W,H), (255,255,255))
draw = ImageDraw.Draw(img)
for cell in rabbitstarts:
drawrect(draw, cell, scale, (190,190,255))
for cell in exits:
drawrect(draw, cell, scale, (190,255,190))
for cell in walls:
drawrect(draw, cell, scale, (190,190,190))
for cell in crushers:
drawrect(draw, cell, scale, (255,0,0), 0.8)
for cell in rabbits:
drawrect(draw, cell, scale, (0,0,255), 0.4)
img.save('anim/run%02uframe%04u.gif' % (runno, turn))
def text2point(textpoint):
# convert text like "22,6" to point object
return point( *map(int, textpoint.split(',')) )
def point2text(cell):
return '%i,%i' % (int(cell.real), int(cell.imag))
def run(number, nseed):
score = 0
turnsleft = turns
turn = 0
seed(nseed)
calltext = program + [mapfile, str(nseed)]
process = subprocess.Popen(calltext,
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=errorlog)
time.sleep(INITTIME)
rabbits.clear()
crushers.clear()
crushers.update( dict((cr, choice(ORTH)) for cr in crusherstarts) )
while turnsleft > 0:
# for each empty start cell, add a rabbit if no crusher in sight.
for cell in rabbitstarts:
if cell in rabbits or set(cansee(cell)) & set(crushers):
continue
rabbits.add(cell)
# write the grid to the runlog and create image frames
if GRIDLOG:
for y,line in enumerate(grid):
for x,ch in enumerate(line):
cell = point(x,y)
if cell in crushers: ch = 'X'
elif cell in rabbits: ch = 'o'
runlog.write(ch)
runlog.write('\n')
runlog.write('\n\n')
if MKIMAGE:
drawframe(number, turn)
# for each crusher, decide move direction.
for cr, direc in crushers.items():
crushers[cr] = bestdir(cr, direc)
# for each crusher, move if possible.
actions = []
for cr, direc in crushers.items():
newcr = cr + direc
if newcr in walls or newcr in crushers:
continue
crushers[newcr] = crushers.pop(cr)
action = ' movesto '
# if crusher is at a rabbit location, remove rabbit.
if newcr in rabbits:
rabbits.discard(newcr)
action = ' crushes '
actions.append(point2text(cr)+action+point2text(newcr))
# output turnsleft, crusher actions, and rabbit locations to program.
send(process, 'turnsleft %u' % turnsleft)
send(process, 'crusher ' + '; '.join(actions))
rabbitlocs = [point2text(r) for r in rabbits]
send(process, ' '.join(['rabbits'] + rabbitlocs))
# read rabbit move requests from program.
start = time.time()
inline = read(process)
if time.time() - start > 0.5:
print 'Move timeout'
break
# if a rabbit not exist or move not possible, no action.
# if rabbit hits a crusher, rabbit is destroyed.
# if rabbit is in exit teleporter, rabbit is removed and score increased.
# if two rabbits collide, they are both destroyed.
newrabbits = set()
for p1,p2 in re.findall(r'(\d+,\d+)\s+to\s+(\d+,\d+)', inline):
p1, p2 = map(text2point, [p1,p2])
if p1 in rabbits and p2 not in walls:
if p2-p1 in ORTH:
rabbits.discard(p1)
if p2 in crushers:
pass # wabbit squished
elif p2 in exits:
score += 1 # rabbit saved
elif p2 in newrabbits:
newrabbits.discard(p2) # moving rabbit collision
else:
newrabbits.add(p2)
# plot each new location of rabbits.
for rabbit in newrabbits:
if rabbit in rabbits:
rabbits.discard(rabbit) # still rabbit collision
else:
rabbits.add(rabbit)
turnsleft -= 1
turn += 1
process.terminate()
return score
mapfile = sys.argv[1]
turns = int(sys.argv[2])
argseed = int(sys.argv[3])
runs = int(sys.argv[4])
program = sys.argv[5:]
errorlog = open('error.log', 'wt')
runlog = open('run.log', 'wt')
grid, walls, crusherstarts, rabbitstarts, exits = features(mapfile)
rabbits = set()
crushers = dict()
if 'anim' not in os.listdir('.'):
os.mkdir('anim')
for fname in os.listdir('anim'):
os.remove(os.path.join('anim', fname))
total = 0
print 'Running:', ' '.join(sys.argv)
print >> runlog, 'Running:', ' '.join(sys.argv)
fmt = '%10s %20s %10s'
print fmt % ('Run', 'Seed', 'Score')
for n in range(runs):
nseed = argseed if argseed else randint(1,1000)
score = run(n, nseed)
total += score
print fmt % (n+1, nseed, score)
print 'Total Score:', total
print >> runlog, 'Total Score:', total
কন্ট্রোলার রান টেক্সট লগ run.log
এবং anim
ডিরেক্টরিতে ইমেজগুলির একটি সিরিজ তৈরি করে । যদি আপনার পাইথন ইনস্টলেশন পিআইএল চিত্র পাঠাগারটি খুঁজে না পায় (বালিশ হিসাবে ডাউনলোড করুন), কোনও চিত্র উত্পন্ন হবে না will আমি ইমেজম্যাগিকের সাথে ইমেজ সিরিজটি অ্যানিমেশন করছি। উদাহরণ:
convert -delay 100 -loop 0 anim/run01* run1anim.gif
আপনার উত্তর সহ আকর্ষণীয় অ্যানিমেশন বা চিত্র পোস্ট করতে আপনাকে স্বাগতম।
আপনি এই বৈশিষ্ট্যগুলি বন্ধ করতে পারেন এবং নিয়ন্ত্রণকারী প্রোগ্রামের প্রথম কয়েকটি লাইনে সেটআপ করে GRIDLOG
= False
এবং / অথবা নিয়ামককে গতি বাড়িয়ে তুলতে পারেন MKIMAGE = False
।
প্রস্তাবিত পাইথন কাঠামো
শুরু করতে সহায়তা করার জন্য, পাইথনের একটি কাঠামো এখানে। প্রথম পদক্ষেপটি হ'ল মানচিত্রের ফাইলে পড়া এবং বেরোনোর পথগুলি সন্ধান করা। প্রতিটি ঘুরে ক্রাশারগুলি কোথায় আছে তা সঞ্চয় করার জন্য কিছু কোড থাকতে হবে এবং কোডটি আমাদের খরগোশগুলিকে কোথায় স্থানান্তরিত করবে তা স্থির করে। শুরু করার সহজ কৌশলটি ক্রুশারদের উপেক্ষা করে খরগোশগুলিকে প্রস্থান করার দিকে চালিত করছে - কিছু খরগোশ এর মধ্যে দিয়ে যেতে পারে।
import sys, re
from random import *
mapfile = sys.argv[1]
argseed = int(sys.argv[2])
seed(argseed)
grid = [line.strip() for line in open(mapfile, 'rt')]
#
# Process grid to find teleporters and paths to get there
#
while 1:
msg = sys.stdin.readline()
if msg.startswith('turnsleft'):
turnsleft = int(msg.split()[1])
elif msg.startswith('crusher'):
actions = re.findall(r'(\d+),(\d+) (movesto|crushes) (\d+),(\d+)', msg)
#
# Store crusher locations and movement so we can avoid them
#
elif msg.startswith('rabbits'):
moves = []
places = re.findall(r'(\d+),(\d+)', msg)
for rabbit in [map(int, xy) for xy in places]:
#
# Compute the best move for this rabbit
newpos = nextmoveforrabbit(rabbit)
#
moves.append('%u,%u to %u,%u' % tuple(rabbit + newpos))
print 'move ' + '; '.join(moves)
sys.stdout.flush()