112 lines
3.3 KiB
Smalltalk
112 lines
3.3 KiB
Smalltalk
Object subclass: Transaction [
|
|
| updates |
|
|
initialize [ updates := LookupTable new. ]
|
|
updates [^updates]
|
|
|
|
putAll: o
|
|
[ o updates keysAndValuesDo: [
|
|
:pos :new | self at: pos put: new ]]
|
|
|
|
movedFrom: pos [ self at: pos put: $. ]
|
|
at: pos put: new
|
|
[ | old |
|
|
old := updates at: pos ifAbsent: [nil].
|
|
(old isNil or: [old = $.]) ifTrue: [^updates at: pos put: new].
|
|
(new = $. or: [old = new]) ifTrue: [^nil].
|
|
self error: ('Contradictory transaction %1 <- %2: already %3'
|
|
% {pos . new . old}) ]
|
|
|
|
performOn: grid
|
|
[ updates keysAndValuesDo: [
|
|
:pos :new | grid at: pos put: new ] ]
|
|
]
|
|
|
|
Object subclass: Warehouse [
|
|
| grid insns robot insnMap |
|
|
|
|
initialize
|
|
[ insnMap := LookupTable new.
|
|
insnMap at: $< put: Posn left;
|
|
at: $> put: Posn right;
|
|
at: $v put: Posn down;
|
|
at: $^ put: Posn up. ]
|
|
|
|
grid: g [grid := g. self findRobot]
|
|
insns: i [insns := i]
|
|
|
|
printOn: st [ st << grid. ]
|
|
|
|
findRobot
|
|
[ grid allPosnsDo: [:it | (grid at: it) = $@ ifTrue: [^robot := it]].
|
|
self error: 'No robot' ]
|
|
|
|
tryMoveIn: trans from: src by: off
|
|
[ | blk |
|
|
blk := grid at: src.
|
|
blk = $. ifTrue: [^true].
|
|
blk = $# ifTrue: [^false].
|
|
|
|
off x = 0 ifTrue: [
|
|
blk = $[ ifTrue: [^self tryMoveIn0: trans from: src and: src + Posn right by: off].
|
|
blk = $] ifTrue: [^self tryMoveIn0: trans from: src and: src + Posn left by: off].
|
|
].
|
|
^self tryMoveIn0: trans from: src by: off ]
|
|
|
|
tryMoveIn0: trans from: src1 and: src2 by: off
|
|
[ ^(self tryMoveIn0: trans from: src1 by: off) and:
|
|
[self tryMoveIn0: trans from: src2 by: off] ]
|
|
|
|
tryMoveIn0: trans from: src by: off
|
|
[ | dst blk |
|
|
dst := src + off.
|
|
blk := grid at: src.
|
|
(self tryMoveIn: trans from: dst by: off) ifTrue: [
|
|
trans movedFrom: src; at: dst put: blk.
|
|
^true ]. ^false ]
|
|
|
|
followInsn: insn
|
|
[ | dir trans |
|
|
dir := insnMap at: insn ifAbsent: [^false].
|
|
trans := Transaction new.
|
|
(self tryMoveIn: trans from: robot by: dir) ifTrue: [
|
|
trans performOn: grid. robot := robot + dir] ]
|
|
|
|
runInsns [ insns do: [:it | self followInsn: it] ]
|
|
|
|
sumGps
|
|
[ | total | total := 0.
|
|
grid allPosnsDo: [
|
|
:it | | tile | tile := grid at: it.
|
|
(tile = $O or: [tile = $[]) ifTrue: [
|
|
total := total + it gpsCoord ] ].
|
|
^total ]
|
|
|
|
copyExpand: expand
|
|
[ ^expand ifFalse: [ ^self copy ]
|
|
ifTrue: [ ^self copyExpand ] ]
|
|
|
|
postCopy [ grid := grid copy ]
|
|
|
|
copyExpand
|
|
[ | expandMap rows |
|
|
expandMap := LookupTable new.
|
|
expandMap at: $# put: '##';
|
|
at: $O put: '[]';
|
|
at: $@ put: '@.';
|
|
at: $. put: '..'.
|
|
rows := grid rows collect: [
|
|
:row | (row toList collect: [:c | expandMap at: c]) join ].
|
|
self grid: (Grid new rows: rows) ]
|
|
]
|
|
|
|
Posn extend [
|
|
gpsCoord [ ^self y * 100 + x - 101 ]
|
|
]
|
|
|
|
AOC input: [ stdin contents splitDoubleNl letArrayInBlock: [
|
|
:rows :insns |
|
|
Warehouse new grid: (Grid new rows: rows lines);
|
|
insns: insns ] ];
|
|
part1: false; part2: true;
|
|
result: [ :input :part | (input copyExpand: part) runInsns sumGps ];
|
|
finish
|