Robotlarımızın ışınlayıcıya ulaşmasına yardımcı olun


17

GÜNCELLEME: Başlamak için bir Python çerçevesi eklendi.

Uzay istasyonu kırıcı botlar tarafından ele geçirildi. "Tavşan" adı verilen pahalı ve kırılgan teknoloji botlarımızın çoğunu istasyonun kendi kendini imha etmeden önce bir çıkış ışınlayıcısına yönlendirmelisiniz, ancak kırıcı botlar koridorlarda devriye geziyor.

Programınıza bir ASCII haritası verilir ve her turda kırıcı-botların nerede olduğu ve mevcut tavşanlarınızın olduğu söylenir. Programınız daha sonra kırıcı botlardan kaçınırken tavşanlarınızı çıkış ışınlayıcısına doğru hareket ettirmelidir.

demo animasyonu

infaz

Python 2 kontrol cihazını aşağıdakilerle çalıştırın:

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

Tohum, kırıcı ve program PRNG için kullanılan küçük bir tamsayıdır, böylece çalışmalar tekrarlanabilir. Programınız, kullanılan gerçek tohumdan bağımsız olarak tutarlı bir şekilde çalışmalıdır. Tohum sıfır ise, kontrolör her çalışma için rastgele bir tohum kullanır.

Denetleyici, programınızı harita metin dosyasının adıyla çalıştıracak ve bağımsız değişken olarak ekleyecektir. Örneğin:

perl wandomwabbits.pl large.map 322

Programınız bir PRNG kullanıyorsa, verilen tohumla başlatmalısınız. Kontrolör daha sonra program güncellemelerinizi STDIN aracılığıyla gönderir ve tavşan hareketlerinizi STDOUT aracılığıyla okur.

Her turda kontrolör 3 hat çıkışı verecektir:

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

daha sonra programın bir satır çıkmasını bekler:

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

GÜNCELLEME: Programınızın ilk satırlar denetleyici tarafından gönderilmeden önce başlaması için 2 saniye olacaktır.

Programınızın denetleyici tavşan konumu girdisinden sonraki hareketlere yanıt vermesi 0,5 saniyeden uzun sürerse denetleyici çıkar.

Izgarada tavşan yoksa, tavşan satırının hiçbir değeri olmaz ve programınız çıplak bir "hareket" dize satırı çıkarmalıdır.

Her turda program çıkış akışınızı yıkamayı unutmayın, aksi takdirde kontrol cihazı kilitlenebilir.

Misal

prog girişi:

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

prog çıkışı:

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

Denetleyici mantığı

Her tur için mantık:

  • sola dönüş sıfır ise, baskı puanı ve çıkış.
  • her boş başlangıç ​​hücresi için, görünürde kırıcı yoksa bir tavşan ekleyin.
  • her kırıcı için hareket yönüne karar verin (aşağıya bakın).
  • her kırıcı için mümkünse hareket ettirin.
  • kırıcı bir tavşan konumundaysa tavşanı çıkarın.
  • çıktı dönüş, kırıcı eylemleri ve tavşan yerleri programlamak için.
  • Programdan tavşan taşıma isteklerini okuyun.
  • Bir tavşan yoksa veya hareket edemiyorsa, atlayın.
  • tavşanların her yeni yerini çizin.
  • tavşan bir kırıcıya çarparsa, tavşan yok edilir.
  • tavşan çıkış ışınlayıcısındaysa, tavşan çıkarılır ve skor artar.
  • tavşanlar çarpışırsa, ikisi de yok edilir.

Her kırıcının her zaman bir yön yönü vardır (NSEW'den biri). Bir kırıcı bu navigasyon mantığını her turda takip eder:

  • 4 dikey yönden herhangi birinde bir veya daha fazla tavşan görünüyorsa, yönü en yakın tavşanlardan birine değiştirin. Kırıcıların başka bir kırıcıyı göremediğini unutmayın.
  • aksi takdirde mümkünse açık ileri, sol, sağ seçenekler arasından rastgele seçim yapın.
  • aksi takdirde ön, sol ve sağ önündeki engeller (duvar veya diğer kırıcılar) , yönü arkaya ayarlayın.

Sonra her kırıcı için:

  • Yeni kırıcı yönünde bir engel yoksa hareket edin (ve muhtemelen ezin).

Harita sembolleri

Harita ASCII karakterlerin dikdörtgen şeklinde bir ızgarasıdır. Harita duvarlar #, koridor boşlukları , tavşan başlangıç ​​pozisyonları s, çıkış ışınlayıcıları eve kırıcı başlangıç ​​noktalarından oluşurc . Sol üst köşe konumdur (0,0).

Küçük harita

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

Test haritası

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

Büyük harita çalışması örneği

büyük demo

Puan

Programınızı değerlendirmek için, kontrol cihazını test haritası, 500 tur, 5 koşu ve 0 tohum ile çalıştırın. Skorunuz, başarıyla istasyondan güvenli bir şekilde ışınlanan toplam tavşan sayısıdır. Beraberlik durumunda, en çok oyu alan cevap kazanır.

Cevabınız giriş adı, kullanılan dil ve puan içeren bir başlık içermelidir. Yanıt gövdesinde, diğerlerinin çalışmalarınızı tekrarlayabilmesi için lütfen denetleyici puan çıktısını tohum numaralarıyla birlikte ekleyin. Örneğin:

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

Standart ve serbestçe kullanılabilen kütüphaneleri kullanabilirsiniz, ancak standart boşluklar yasaktır. Programınızı belirli bir tohum, dönüş sayısı, harita özellik seti veya diğer parametreler için optimize etmemelisiniz. Bu kuralın ihlal edildiğinden şüphelenirsem haritayı değiştirme, sayma ve tohumlama hakkını saklı tutarım.

Denetleyici kodu

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

Denetleyici, run.logdizinin içerisindeki alıştırmaların ve bir dizi görüntünün metin günlüğünü oluşturur anim. Python kurulumunuz PIL görüntü kitaplığını bulamazsa (Yastık olarak indir), görüntü oluşturulmaz. ImageMagick ile resim serilerini canlandırıyorum. Örneğin:

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

Cevabınızla ilginç animasyonlar veya resimler yayınlayabilirsiniz.

Denetleyici programının ilk birkaç satırını ayarlayarak GRIDLOG = Falseve / veya ayarlayarak bu özellikleri kapatabilir ve denetleyiciyi hızlandırabilirsiniz MKIMAGE = False.

Önerilen Python çerçevesi

Başlamak için Python'da bir çerçeve var. İlk adım harita dosyasında okumak ve çıkışlara giden yolları bulmaktır. Her dönüşte, kırıcıların bulunduğu yeri saklamak için bazı kodlar ve tavşanlarımızı nereye taşıyacağımıza karar veren kod bulunmalıdır. Başlamak için en basit strateji, tavşanları kırıcıları görmezden gelen bir çıkışa doğru hareket ettirmektir - bazı tavşanlar geçebilir.

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

Aynı RNG ile kontrolörün simülasyonuna izin veriliyor mu? Bu, kırıcıları etkili bir şekilde deterministik hale getirerek davranışlarını tahmin etmenizi ve onlardan kaçınmanızı sağlar. Cehennem, tavşanların rahatsız edilmemiş bir otoyol kurarken kırıcıları meşgul etmek için muhtemelen bir veya birkaç 'yem tavşanı' yapabilirsin
rahatsız edilmemiş

Hayır, RNG'yi simüle edemez (veya belirli bir tohum için kaydedemezsiniz). Kırıcılar, deterministik OLMAYACAK şekilde tasarlanmıştır, bu nedenle bu, onlardan kaçınması muhtemel bir strateji oluşturmak için kod zorluğudur . 'Yem tavşan' fikri kesinlikle olsa Tamam. Kurban tavşanlar içeren bazı stratejiler bekliyorum.
Mantık Şövalyesi

Tohum 0 ise, her çalışma rastgele bir tohum kullanmayacak mı?
TheNumberOne

Evet. Denetleyici tohum sıfırsa, her çalışma için rastgele bir tohum kullanır (ve test programına verir). Bu tohum koşu skoru ile rapor edilir. Bu tohumun kontrolöre geri beslenmesi, kesin çalışmanın (ve skorun) doğrulanmasına neden olmalıdır. Biraz karmaşık, ancak çoğaltma çalışmalarını (deterministik) etkinleştirmek ve denetleyici ve test programı davranışında rasgeleliğe izin vermenin en iyi yoluydu.
Mantık Şövalyesi

Yanıtlar:


2

Çılgın, Python 45

Rastgele tohumla 25 koşu yaptım, bilgisayarım 1000'e gitmek için yeterince hızlı değil (birisi skoru düzeltmek istiyorsa) Python'daki ilk program, benim için hata ayıklamak bir acıydı. Ayrıca iyi kullanıp kullanmadığımı da bilmiyorum.

Biri, kırıcıları hesaba katarak, diğeri olmadan çıkıştan bir genişlik ilk algoritması kullanır. Ben daha karmaşık bir şey (bir kırıcı kaldırma, vb.) İçin gitmedim zaman aşımı bir sürü vardı. Tavşanlar, yanlış bir yola gitme umuduyla yakınlarda bir kırıcı varsa da çıldırırlar.

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

Ortalama bir koşu için animasyon


Bence girintinizde hatalar olabilir. Python'da önde gelen beyaz boşluk önemlidir. örneğin: walkables.add((b,a))çizgiler.
Mantık Şövalyesi

Şimdi cezası çalışmalıdır
Hit

1

Tavşan, Java, 26.385

1 ile 1000 arası puanların ortalamasını aldım ve puanımı almak için 5 ile çarptım. Bunun standart seçeneklerle mümkün olan tüm oyunların ortalama puanına eşdeğer olduğundan eminim.

Skorlar

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));
        }
    }

}

Test edilen en iyi koşu tohum 1000'e sahiptir. İşte bir GIF:

resim açıklamasını buraya girin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.