Ruby, 217
->a{r=''
z=a.index ?@
a.tr!('<^>v',b='awds').scan(/\w/){c=0
e,n=[a[z,c+=1][?\n]?p: c,d=c*a[/.*
/].size,a[z-c,c][?\n]?p: -c,-d].zip(b.chars).reject{|i,k|!i||a[v=i+z]!=k||0>v}.max_by{|q|q&[a[z]]}until n
z+=e
r=n*c+r}
r}
Dies beginnt am @
und geht rückwärts, wobei nach Nachbarn gesucht wird, die auf die aktuelle Position zeigen ( z
). Um an Kreuzungen mit vier Richtungen den richtigen Weg zu wählen, werden Nachbarn bevorzugt, die in dieselbe Richtung zeigen ( max_by{...}
). Wenn keine unmittelbaren Nachbarn gefunden werden, wird davon ausgegangen, dass ein Crossover stattgefunden hat, und es wird jeweils eine Ebene nach der anderen erreicht, bis ein ( until n
und c+=1
) gefunden wird. Dieser Vorgang wiederholt sich für die Anzahl der Körpersegmente (ohne Kopf) ( .scan(/\w/){...}
).
Der Testfall, den ich zu dem Puzzle hinzugefügt habe, hat mich immer wieder aus der Fassung gebracht, also bin ich von 182 Zeichen auf 218 übergegangen. Diese zusätzlichen Charaktere haben alle dafür gesorgt, dass meine horizontalen Züge nicht in die nächsten / vorherigen Zeilen eingingen. Ich frage mich, ob ich besser damit umgehen kann.
Ungolfed:
f=->a{
result=''
position=a.index ?@ # start at the @
a.tr!('<^>v',b='awds') # translate arrows to letters
a.scan(/\w/){ # for each letter found...
search_distance=0
until distance
search_distance+=1
neighbors = [
a[position,search_distance][?\n]?p: search_distance, # look right by search_distance unless there's a newline
width=search_distance*a[/.*\n/].size, # look down (+width)
a[position-search_distance,search_distance][?\n]?p: -search_distance, # look left unless there's a newline
-width # look up (-width)
]
distance,letter = neighbors.zip(b.chars).reject{ |distance, letter_to_find|
!distance || # eliminate nulls
a[new_position=distance+position]!=letter_to_find || # only look for the letter that "points" at me
0>new_position # and make sure we're not going into negative indices
}.max_by{ |q|
# if there are two valid neighbors, we're at a 4-way intersection
# this will make sure we prefer the neighbor who points in the same
# direction we're pointing in. E.g., when position is in the middle of
# the below, the non-rejected array includes both the top and left.
# v
# >>>
# v
# We want to prefer left.
q & [a[position]]
# ['>',x] & ['>'] == ['>']
# ['v',x] & ['>'] == []
# ['>'] > [], so we select '>'.
}
end
position+=distance
result=(letter*search_distance)+result # prepend result
}
result # if anyone has a better way of returning result, I'm all ears
}