Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/local/bin/gst -q
- Collection extend [
- apply: method [ ^self collect: [:x | x perform: method] ]
- ]
- Object subclass: HeightMap [
- | grid start end |
- dirs := { 0 @ 1. 0 @ -1. 1 @ 0. -1 @ 0 }.
- HeightMap class >> new: arrayStrings [
- ^super new init: arrayStrings
- ]
- init: mapArray [
- | width |
- width := (mapArray at: 1) size + 2.
- grid := OrderedCollection new.
- mapArray keysAndValuesDo: [ :y :line |
- | row x |
- row := line asOrderedCollection apply: #asInteger.
- row addFirst: 128; addLast: 128. " Add sentinels left/right "
- " Find start "
- (x := row indexOf: $S asInteger) ~= 0 ifTrue: [
- start := x @ (y + 1).
- row at: x put: $a asInteger.
- ].
- " Find end "
- (x := row indexOf: $E asInteger) ~= 0 ifTrue: [
- end := x @ (y + 1).
- row at: x put: $z asInteger.
- ].
- grid add: row asArray.
- ].
- " Add sentinel rows to top and bottom "
- grid addFirst: (Array new: width withAll: 128).
- grid addLast: (Array new: width withAll: 128).
- ^self
- ]
- at: pt [ ^(grid at: pt y) at: pt x ]
- start [ ^start ]
- end [ ^end ]
- " Find path from startPos until endBlock is true, with heightAllow rule "
- pathFrom: startPos endWhen: endBlock moving: heightAllow [
- | visit queue state time pos height move |
- " Initialise visit array "
- visit := (1 to: grid size) collect: [ :i |
- Array new: (grid at: 1) size withAll: false
- ].
- " Queue starts with startPos at time 0 "
- queue := OrderedCollection with: { 0. startPos }.
- " Basic BFS loop: "
- [ queue notEmpty ] whileTrue: [
- state := queue removeFirst.
- time := state first.
- pos := state second.
- (endBlock value: pos) ifTrue: [ ^time ].
- ((visit at: pos y) at: pos x) ifFalse: [
- (visit at: pos y) at: pos x put: true.
- height := self at: pos.
- dirs do: [ :dir |
- move := pos + dir.
- (heightAllow value: height value: (self at: move)) ifTrue: [
- queue addLast: { time + 1. move }.
- ]
- ]
- ]
- ]
- ]
- ]
- "
- | Mainline
- "
- map := HeightMap new: stdin lines contents.
- " Start to end, going up: "
- part1 := map pathFrom: map start
- endWhen: [:pos | pos = map end]
- moving: [:height :targ | (height + 1) >= targ].
- ('Part 1: %1' % {part1}) displayNl.
- " End to level $a, going down: "
- part2 := map pathFrom: map end
- endWhen: [:pos | (map at: pos) = $a asInteger]
- moving: [:height :targ | targ between: (height - 1) and: $z asInteger].
- ('Part 2: %1' % {part2}) displayNl.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement