"Squeak/Pharo Smalltalk
お題
N×Mのフィールドが与えられる。各マスの意味は以下の通りとする。
'S':始点
'G':終点
'.':通行可
'#':通行不可
連続して同じ方向に進むことができないという制約下で、
始点から終点までの最短距離を求めよ。
[example 1]
'S....
#....
..#..
....G'
=> 9
[example 2]
'S.....G
.......'
=> 12
"
| solve |
solve := [:map |
| N M memo defaultDict goal fromDirs pos queue |
N := map lines size.
M := map lines first size.
memo := Matrix rows: N columns: M contents: (map asArray copyWithout: Character cr).
fromDirs := (0@0) fourNeighbors.
defaultDict := (fromDirs collect: [:dir | dir -> Float infinity]) as: Dictionary.
memo replaceAll: $. with: defaultDict.
memo := memo deepCopy.
goal := memo indexOf: $G.
memo at: goal x at: goal y put: defaultDict copy.
pos := memo indexOf: $S.
memo at: pos x at: pos y put: ((fromDirs collect: [:dir | dir -> 0]) as: Dictionary).
queue := OrderedCollection withAll: (fromDirs collect: [:dir | dir -> pos]).
[queue isEmpty] whileFalse: [
| assoc dist |
assoc := queue removeFirst.
pos := assoc value.
dist := ((memo at: pos x at: pos y) at: assoc key) + 1.
(fromDirs copyWithout: assoc key) do: [:dir | [:exit |
| next dict |
next := pos + dir.
(dict := memo at: next x at: next y ifInvalid: $#) isDictionary ifFalse: [exit value].
(dict at: dir) > dist ifTrue: [
dict at: dir put: dist.
next = goal ifFalse: [queue add: dir -> next]
]
] valueWithExit]
].
(memo at: goal x at: goal y) values min
].
solve value:
'S....
#....
..#..
....G'. "=> 9 "
solve value:
'S.....G
.......'. "=> 12 "
solve value:
'S.#G
....'. "=> Infinity "
solve value:
'#.#.#
S...G
##.#.'. "=> 10 "
solve value:
'S#G'. "=> Infinity "