74 lines
2.1 KiB
Smalltalk
74 lines
2.1 KiB
Smalltalk
Grid extend [
|
|
| guard dir origGuard visitedPosns |
|
|
|
|
visitedPosns: n [visitedPosns:=n]
|
|
visitedPosns [^visitedPosns]
|
|
dir [^dir] guard [^guard]
|
|
|
|
initGuard
|
|
[ self allPosnsDo: [
|
|
:pos |
|
|
((self at: pos) = $^) ifTrue: [
|
|
origGuard := pos.
|
|
self at: pos put: $..
|
|
self resetGuard.
|
|
^guard.
|
|
]]]
|
|
|
|
resetGuard
|
|
[ origGuard ifNil: [self initGuard].
|
|
guard := origGuard.
|
|
dir := Posn up. ]
|
|
|
|
isSolid: p [ ^(self at: p) = $# ]
|
|
isEmpty: p [ ^(self at: p) = $. ]
|
|
|
|
copy [ ^Grid new rows: rows; restore: self state ]
|
|
|
|
stepGuard
|
|
[ [self isSolid: guard + dir] whileTrue:
|
|
[ dir := dir rotateCcw. ].
|
|
guard := guard + dir. ]
|
|
|
|
state [^{guard . dir}]
|
|
restore: st [guard := st at: 1. dir := st at: 2]
|
|
|
|
guardOob [^(self at: guard) isNil]
|
|
|
|
walkDo: block
|
|
[ [self guardOob] whileFalse: [block value. self stepGuard] ]
|
|
|
|
stepToTurn
|
|
[ guard := guard copy.
|
|
[self isSolid: guard + dir] whileTrue: [dir := dir rotateCcw].
|
|
[self isEmpty: guard] whileTrue: [guard += dir].
|
|
(self isSolid: guard) ifTrue: [guard -= dir] ]
|
|
|
|
hasCycleFrom: state
|
|
[ | seen st |
|
|
seen := Set new.
|
|
self restore: state.
|
|
[self guardOob] whileFalse:
|
|
[self stepToTurn. st := self state.
|
|
(seen includes: st) ifTrue: [^true].
|
|
seen add: st].
|
|
^false ]
|
|
]
|
|
|
|
AOC input: [ Grid new rows: stdin toLines asArray ];
|
|
part1: [ :grid | | posns prev |
|
|
posns := Dictionary new. prev := nil.
|
|
grid walkDo: [
|
|
posns at: grid guard ifAbsentPut: [prev].
|
|
prev := grid state].
|
|
grid visitedPosns: posns.
|
|
posns size ];
|
|
part2: [ :grid | | i | i := 1.
|
|
grid visitedPosns removeKey: grid guard.
|
|
grid visitedPosns associations count:
|
|
[ :ass |
|
|
grid at: ass key put: $#.
|
|
[grid hasCycleFrom: ass value]
|
|
ensure: [grid at: ass key put: $.] ] ];
|
|
result: [ :grid :part | part value: grid resetGuard ];
|
|
finish.
|