Giúp robot của chúng tôi tiếp cận dịch chuyển tức thời


17

CẬP NHẬT: Đã thêm một khung Python để bắt đầu.

Trạm vũ trụ đã bị vượt qua bởi các máy nghiền-bot. Bạn phải hướng dẫn nhiều bot công nghệ đắt tiền và dễ vỡ của chúng tôi gọi là "thỏ" đến một dịch chuyển tức thời trước khi trạm tự hủy, nhưng các bot-máy nghiền đang tuần tra trên các hành lang.

Chương trình của bạn được cung cấp một bản đồ ASCII và mỗi lượt được cho biết nơi mà các máy nghiền và các con thỏ hiện tại của bạn đang ở. Chương trình của bạn sau đó sẽ di chuyển những con thỏ của bạn về phía dịch chuyển tức thời trong khi tránh các máy nghiền-bot.

hoạt hình demo

Chấp hành

Chạy bộ điều khiển Python 2 với:

python controller.py <mapfile> <turns> <seed> <runs> <prog>...
<prog> can be <interpreter> <yourprog> or similar.

Hạt giống là một số nguyên nhỏ được sử dụng cho máy nghiền và PRNG chương trình của bạn để các lần chạy được lặp lại. Chương trình của bạn nên thực hiện nhất quán bất kể hạt giống thực tế được sử dụng. Nếu hạt giống bằng 0, bộ điều khiển sẽ sử dụng một hạt giống ngẫu nhiên cho mỗi lần chạy.

Bộ điều khiển sẽ chạy chương trình của bạn với tên của tệp văn bản bản đồ và khởi tạo làm đối số. Ví dụ:

perl wandomwabbits.pl large.map 322

Nếu chương trình của bạn sử dụng PRNG, bạn nên khởi tạo nó với hạt giống đã cho. Sau đó, bộ điều khiển sẽ gửi các cập nhật chương trình của bạn thông qua STDIN và đọc chuyển động của thỏ thông qua STDOUT.

Mỗi lượt điều khiển sẽ xuất ra 3 dòng:

turnsleft <INT>
crusher <x,y> <movesto|crushes> <x,y>; ...
rabbits <x,y> <x,y> ...

sau đó chờ chương trình xuất ra một dòng:

move <x,y> to <x,y>; ...

CẬP NHẬT: Chương trình của bạn sẽ có 2 giây để khởi tạo trước khi các dòng đầu tiên được gửi bởi bộ điều khiển.

Nếu chương trình của bạn mất hơn 0,5 giây để phản hồi với các di chuyển sau khi nhập vị trí thỏ của bộ điều khiển, bộ điều khiển sẽ thoát.

Nếu không có thỏ trên lưới, dòng thỏ sẽ không có giá trị và chương trình của bạn sẽ xuất ra một chuỗi chuỗi "di chuyển" trần.

Nhớ xả luồng đầu ra chương trình của bạn mỗi lượt hoặc bộ điều khiển có thể bị treo.

Thí dụ

đầu vào prog:

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

đầu ra prog:

move 14,3 to 14,4; 14,2 to 14,3; 6,4 to 7,4

Bộ điều khiển logic

Logic cho mỗi lượt:

  • nếu rẽ trái bằng 0, in điểm và thoát.
  • đối với mỗi ô bắt đầu trống, thêm một con thỏ nếu không có máy nghiền trong tầm nhìn.
  • cho mỗi máy nghiền, quyết định hướng di chuyển (xem bên dưới).
  • cho mỗi máy nghiền, di chuyển nếu có thể.
  • nếu máy nghiền ở vị trí thỏ, loại bỏ thỏ.
  • đầu ra quay vòng, hành động máy nghiền và vị trí thỏ để lập trình.
  • đọc yêu cầu di chuyển thỏ từ chương trình.
  • Nếu một con thỏ không tồn tại hoặc di chuyển không thể, bỏ qua.
  • vẽ từng vị trí mới của thỏ.
  • nếu thỏ đâm vào máy nghiền, thỏ bị phá hủy.
  • nếu thỏ ở trong dịch chuyển tức thời, thỏ sẽ bị loại bỏ và tăng điểm.
  • nếu thỏ va chạm, cả hai đều bị tiêu diệt.

Mỗi máy nghiền luôn có một hướng tiêu đề (một trong NSEW). Một máy nghiền tuân theo logic điều hướng này mỗi lượt:

  • Nếu một hoặc nhiều con thỏ có thể nhìn thấy theo bất kỳ hướng nào trong 4 hướng trực giao, hãy đổi hướng sang một trong những con thỏ gần nhất. Lưu ý rằng máy nghiền không thể nhìn qua máy nghiền khác.
  • khác chọn ngẫu nhiên giữa các tùy chọn mở về phía trước, bên trái, bên phải nếu có thể.
  • khác nếu chướng ngại vật (tường hoặc máy nghiền khác) ở phía trước, bên trái bên phải, đặt hướng về phía sau.

Sau đó cho mỗi máy nghiền:

  • Nếu không có chướng ngại vật trong hướng máy nghiền mới, di chuyển (và có thể nghiền nát).

Các biểu tượng bản đồ

Bản đồ là một lưới hình chữ nhật gồm các ký tự ASCII. Bản đồ được tạo thành từ các bức tường #, không gian hành lang , vị trí bắt đầu của thỏ s, dịch chuyển tức thời evà các vị trí bắt đầu máy nghiền c. Góc trên bên trái là vị trí (0,0).

Bản đồ nhỏ

###################
#        c        #
# # ######## # # ##
# ###s    #  ####e#
#   # # # ## ##   #
### # ###  # ## # #
#         ##      #
###################

Bản đồ kiểm tra

#################################################################
#s                       ############################          s#
## ## ### ############ # #######                ##### ####### ###
## ## ### #            # ####### ########## # # ####   ###### ###
## ## ### # ############ ####### ##########     ##### ####### ###
## ## ##  #              ####### ########## # # ##### ####      #
##    ### #### #### ########     ##########     ##### #### ## ###
######### ####      ######## ################ ####### ####    ###
#########  ################# ################   c     ####### ###
######### ##################          ####### ####### ###########
######### ################## ######## #######         ###########
##### ###   c                          ###### ###################
#         #### ### # # # # # # # # # # ###### ##############    #
# ####### ####                         ###    ####     ##### ## #
#         #### ### # # # # # # # # # # ### # ###   #########    #
##### ### #### ###                   #####   ### #  ######## ####
############## ### # # # # # # # # # # #######   ##  ####### ####
#### #### #### ###                     ###   # # ###  ###### ####
##             ### # # # # # # # # # # ### ### #  ###  ##### ####
##### ######## ### # # # ##### # # # # ### ### # #####  #### ####
##### ##### ######         c   #       ### ###   ######  ### ####
##       c   ######################### ### ##### ####### ### ####
##### # ### #######   ########         ### ##### c  ##    ## ####
#####   #   ####### ########## ## ######## #     ######## ## ####
######### # #######            ## #     ## # # # #####     # ####
### ##### #     ### # ############## # ### #      ###  ## #  ####
#      ## # ### ### # ############## # ### ##### #####    ## ####
### ## ## #     ###                  #           ########       #
#s  ##      ###################################################e#
#################################################################

Ví dụ chạy bản đồ lớn

bản demo lớn

Ghi bàn

Để đánh giá chương trình của bạn, hãy chạy bộ điều khiển với bản đồ kiểm tra, 500 lượt, 5 lần chạy và hạt giống 0. Điểm của bạn là tổng số thỏ được dịch chuyển thành công ra khỏi trạm đến nơi an toàn. Trong trường hợp hòa, câu trả lời có nhiều phiếu nhất sẽ giành chiến thắng.

Câu trả lời của bạn nên bao gồm một tiêu đề với tên mục nhập, ngôn ngữ được sử dụng và điểm số. Trong phần thân câu trả lời, vui lòng bao gồm đầu ra điểm của bộ điều khiển hoàn thành với số hạt giống để những người khác có thể lặp lại các lần chạy của bạn. Ví dụ:

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

Bạn có thể sử dụng các thư viện tiêu chuẩn và có sẵn miễn phí nhưng các lỗ hổng tiêu chuẩn bị cấm. Bạn không được tối ưu hóa chương trình của mình cho một hạt giống nhất định, số lần lượt, bộ tính năng bản đồ hoặc các tham số khác. Tôi bảo lưu quyền thay đổi bản đồ, số lượt và hạt giống nếu tôi nghi ngờ vi phạm quy tắc này.

Mã điều khiển

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

Bộ điều khiển tạo một bản ghi văn bản của các lần chạy run.logvà một loạt các hình ảnh trong animthư mục. Nếu cài đặt Python của bạn không thể tìm thấy thư viện hình ảnh PIL (tải xuống dưới dạng Gối), sẽ không có hình ảnh nào được tạo. Tôi đã làm hoạt hình cho loạt hình ảnh với ImageMagick. Ví dụ:

convert -delay 100 -loop 0 anim/run01* run1anim.gif

Bạn được chào đón để gửi hình ảnh động thú vị hoặc hình ảnh với câu trả lời của bạn.

Bạn có thể tắt các tính năng này và tăng tốc bộ điều khiển bằng cách cài đặt GRIDLOG = Falsevà / hoặc MKIMAGE = Falsetrong một vài dòng đầu tiên của chương trình điều khiển.

Khung Python được đề xuất

Để giúp bắt đầu, đây là một khung trong Python. Bước đầu tiên là đọc trong tệp bản đồ và tìm đường dẫn đến lối thoát hiểm. Trong mỗi lượt nên có một số mã để lưu trữ nơi máy nghiền và mã quyết định nơi di chuyển thỏ của chúng tôi. Chiến lược đơn giản nhất để bắt đầu là di chuyển những con thỏ về phía lối ra bỏ qua những kẻ nghiền nát - một số con thỏ có thể vượt qua.

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

Có được phép mô phỏng bộ điều khiển, với cùng RNG không? Điều này sẽ có hiệu quả làm cho các máy nghiền có tính quyết định, cho phép bạn dự đoán hành vi của chúng và tránh chúng. Quỷ thần, có lẽ bạn có thể tạo ra một hoặc một vài 'con thỏ mồi' để giữ cho những kẻ nghiền nát bận rộn trong khi thiết lập một đường cao tốc không bị làm lạnh của thỏ
orlp

Không, bạn không thể mô phỏng RNG (hoặc ghi lại nó cho một hạt giống cụ thể). Các máy nghiền được thiết kế để KHÔNG mang tính quyết định, vì vậy đây là một thách thức về mã để thực hiện một chiến lược có khả năng tránh chúng. Ý tưởng 'mồi thỏ' chắc chắn là ok. Tôi đang mong đợi một số chiến lược liên quan đến thỏ hiến tế.
Logic Knight

Nếu hạt giống bằng 0, mỗi lần chạy sẽ sử dụng một hạt giống ngẫu nhiên?
TheNumberOne

Đúng. Nếu hạt giống bộ điều khiển bằng không, nó sẽ sử dụng (và cấp cho chương trình thử nghiệm) một hạt giống ngẫu nhiên cho mỗi lần chạy. Hạt giống này được báo cáo với số điểm của cuộc chạy. Cho hạt giống này trở lại bộ điều khiển sẽ khiến cho lần chạy chính xác (và điểm số) được xác minh. Nó hơi phức tạp, nhưng đó là cách tốt nhất tôi có thể hình dung để cho phép sao chép các lần chạy (xác định) và cho phép tính ngẫu nhiên trong bộ điều khiển và hành vi chương trình thử nghiệm.
Logic Knight

Câu trả lời:


2

Điên rồ, Python 45

Tôi đã thực hiện 25 lần chạy với hạt giống ngẫu nhiên, máy tính của tôi không đủ nhanh để đạt 1000 (nếu ai đó muốn sửa điểm) Chương trình đầu tiên ở python, thật khó để gỡ lỗi cho tôi. Ngoài ra tôi không biết nếu tôi sử dụng nó tốt.

Nó sử dụng thuật toán đầu tiên từ lối ra, một thuật toán có tính đến các máy nghiền, cái còn lại không có. Tôi đã có rất nhiều thời gian chờ vì vậy tôi đã không đi đến một cái gì đó phức tạp hơn (loại bỏ một máy nghiền, v.v.). Những con thỏ cũng phát điên nếu có một máy nghiền gần đó với hy vọng làm cho nó đi sai đường.

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')]
width = len(grid[0])
height = len(grid)

starts = set([])
end = ()
walkables = set([])
crushers = set([])
#
# Process grid to find teleporters and paths to get there
#
for a in range(height):
    for b in range(width):
        if grid[a][b] == 'e':
            end = (b,a)
            walkables.add((b,a))
        elif grid[a][b] == 's':
            starts.add((b,a))
            walkables.add((b,a))
        elif grid[a][b] == 'c':
            crushers.add((b,a))
            walkables.add((b,a))
        elif grid[a][b] == ' ':
            walkables.add((b,a))

toSearch = [ (end, 0) ]
inSearch = [ end ]
visited = set([])
gradient = [[0]*height for x in range(width)]
while len(toSearch) > 0 :
    current = toSearch.pop(0)
    (row, col) = current[0]
    length = current[1]
    visited.add(current[0])
    neighbors = {(row+1,col),(row-1,col),(row,col+1),(row,col-1)}
    neighborSpaces = walkables & neighbors
    unvisited = neighborSpaces - visited
    for node in unvisited:
        if not node in inSearch:
            gradient[node[0]][node[1]]=[current[0][0],current[0][1]]
            inSearch.append(node)
            toSearch.append((node, length+1))
    toSearch.sort(key=lambda node: node[1])

while 1:
    msg = sys.stdin.readline()

    if msg.startswith('turnsleft'):
        turnsleft = int(msg.split()[1])

    elif msg.startswith('crusher'):
        # Update crushers
        actions = re.findall(r'(\d+),(\d+) (movesto|crushes) (\d+),(\d+)', msg)
        for one_action in actions:
            crushers.discard((int(one_action[0]),int(one_action[1])))
            crushers.add((int(one_action[3]),int(one_action[4])))

    elif msg.startswith('rabbits'):
        toSearch = [ (end, 0) ]
        inSearch = [ end ]
        visited = set([])
        gradient2 = [[0]*height for x in range(width)]
        while len(toSearch) > 0 :
            current = toSearch.pop(0)
            (row, col) = current[0]
            length = current[1]
            visited.add(current[0])
            neighbors = {(row+1,col),(row-1,col),(row,col+1),(row,col-1)}
            neighborSpaces = (walkables - crushers) & neighbors
            unvisited = neighborSpaces - visited
            for node in unvisited:
                if not node in inSearch:
                    gradient2[node[0]][node[1]]=[current[0][0],current[0][1]]
                    inSearch.append(node)
                    toSearch.append((node, length+1))
            toSearch.sort(key=lambda node: node[1])
        moves = []
        places = re.findall(r'(\d+),(\d+)', msg)
        for rabbit in [map(int, xy) for xy in places]:
            # If any crushers insight, go crazy to lose him
            directions = [(1,0),(-1,0),(0,1),(0,-1)]
            crazy = False
            newpos = 0
            for direction in directions:
                (row, col) = rabbit
                sight = 0
                while len({(row,col)} & walkables)>0 and sight<5 and crazy == False:
                    sight+=1
                    if (row,col) in crushers:
                        directions.remove(direction)
                        crazy = True
                    (row,col) = (row+direction[0],col+direction[1])
            for direction in directions:
                if not (rabbit[0]+direction[0],rabbit[1]+direction[1]) in walkables:
                    directions.remove(direction)
            if len(directions)==0:
                directions = [(1,0),(-1,0),(0,1),(0,-1)]
            direction = choice(directions)
            newpos = [rabbit[0]+direction[0],rabbit[1]+direction[1]]
            # Else use gradients
            if crazy == False:
                newpos = gradient2[rabbit[0]][rabbit[1]]
                if newpos == 0:
                    newpos = gradient[rabbit[0]][rabbit[1]]
            moves.append('%u,%u to %u,%u' % tuple(rabbit + newpos))
        print 'move ' + '; '.join(moves)
        sys.stdout.flush()

Hoạt hình cho một hoạt động trung bình


Tôi nghĩ rằng bạn có thể có lỗi trong thụt lề của bạn. Không gian trắng hàng đầu rất quan trọng trong Python. vd: các walkables.add((b,a))dòng.
Logic Knight

nên hoạt động tốt ngay bây giờ
Lượt

1

Bunny, Java, 26.385

Tôi đã tính trung bình điểm số của các lần chạy từ 1 đến 1000 và nhân với 5 để có được điểm số của mình. Tôi khá chắc chắn rằng điều này tương đương với điểm trung bình trên tất cả các trò chơi có thể với các tùy chọn tiêu chuẩn.

Điểm số

import java.awt.Point;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.*;
import java.util.stream.Collectors;

public class Main {

    private static final char WALL = '#';
    private static final char CRUSHER = 'c';
    private static final char ESCAPE = 'e';
    private static final char HUTCH = 's';

    private int height;
    private int width;

    private char[][] map;
    private List<Point> escapes = new ArrayList<>();
    private List<Point> crushers = new ArrayList<>();
    private List<Point> rabbits = new ArrayList<>();
    private List<Point> hutches = new ArrayList<>();

    private BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    private PrintStream out = System.out;
    private int[][] distances;

    public Main(String[] args) throws Exception {
        loadMap(args[0]);
    }

    private void loadMap(String mapFileName) throws Exception {
        char[][] preMap = new BufferedReader(new FileReader(mapFileName))
                .lines()
                .map(String::toCharArray)
                .toArray(char[][]::new);

        width = preMap[0].length;
        height = preMap.length;

        map = new char[width][height];    //tranpose

        for (int x = 0; x < width; x++){
            for (int y = 0; y < height; y++){
                map[x][y] = preMap[y][x];
            }
        }

        processMap();

        distances = dijkstra();

    }

    private void processMap() {
        for (int x = 0; x < width; x++){
            for (int y = 0; y < height; y++){
                char c = map[x][y];
                Point p = new Point(x, y);
                if (c == CRUSHER){
                    crushers.add(p);
                }
                if (c == ESCAPE){
                    escapes.add(p);
                }
                if (c == HUTCH){
                    hutches.add(p);
                }
            }
        }
    }

    public static void main(String[] args) throws Exception {
        new Main(args).run();
    }

    private void run() throws Exception{
        while (true) {
            in.readLine();
            readCrushers();
            readRabbits();
            makeDecision();
        }
    }

    private void makeDecision() {
        Map<Point, Point> moves = new HashMap<>();

        for (Point rabbit : rabbits){
            Point bestDirection = null;
            for (Point p : pointsAroundInclusive(rabbit)){
                if (
                        (bestDirection == null ||
                                distances[p.x][p.y] < distances[bestDirection.x][bestDirection.y]
                        ) && !moves.entrySet().contains(p)){
                    bestDirection = p;
                }
            }
            if (bestDirection != null) {
                moves.put(rabbit, bestDirection);
            }
        }

        out.println("move" +
                moves.entrySet().stream().map(a -> {
                    Point l0 = a.getKey();
                    Point l1 = a.getValue();
                    return " " + l0.x + "," + l0.y + " to " + l1.x + "," + l1.y;
                }).collect(Collectors.joining(";")));
    }

    private List<Point> pointsAroundInclusive(Point point) {
        List<Point> result = pointsAroundExclusive(point);
        result.add(point);
        return result;
    }

    private int[][] dijkstra() {
        Queue<Point> queue = new LinkedList<>();
        Set<Point> scanned = new HashSet<>();
        queue.addAll(escapes);
        scanned.addAll(escapes);

        int[][] distances = new int[width][height];

        while (!queue.isEmpty()) {
            Point next = queue.remove();
            int distance = distances[next.x][next.y];

            pointsAroundExclusive(next).stream()
                    .filter(p -> !scanned.contains(p))
                    .forEach(p -> {
                        distances[p.x][p.y] = distance + 1;
                        scanned.add(p);
                        queue.add(p);
                    });
        }

        return distances;
    }

    private List<Point> pointsAroundExclusive(Point p) {
        Point[] around = new Point[]{
                new Point(p.x - 1, p.y),
                new Point(p.x + 1, p.y),
                new Point(p.x, p.y - 1),
                new Point(p.x, p.y + 1)
        };

        List<Point> result = new ArrayList<>(Arrays.asList(around));
        result.removeIf(a -> {
            if (a.x < 0 || a.x >= width){
                return true;
            }
            if (a.y < 0 || a.y >= height){
                return true;
            }
            char c = map[a.x][a.y];
            return c == WALL;
        });

        return result;
    }

    private void readRabbits() throws Exception {
        String[] locations = in.readLine().substring("rabbits".length()).trim().split("\\s");
        rabbits.clear();

        for (String location : locations){

            if (location.equals("")){
                continue;
            }

            String[] decomposed = location.split(",");

            int x = Integer.parseInt(decomposed[0]);
            int y = Integer.parseInt(decomposed[1]);

            rabbits.add(new Point(x, y));
        }

    }

    private void readCrushers() throws Exception {
        String[] locations = in.readLine().substring("crusher".length()).trim().split("(; )?\\d+,\\d+ (movesto|crushes) ");
        crushers.clear();

        for (String location : locations){

            if (location.equals("")){
                continue;
            }

            String[] decomposed = location.split(",");

            int x = Integer.parseInt(decomposed[0]);
            int y = Integer.parseInt(decomposed[1]);

            crushers.add(new Point(x, y));
        }
    }

}

Chạy tốt nhất đã thử nghiệm có hạt 1000. Đây là một GIF của nó:

nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.