diff --git a/days/day15.st b/days/day15.st new file mode 100644 index 0000000..6fcaf39 --- /dev/null +++ b/days/day15.st @@ -0,0 +1,137 @@ +Object subclass: Transaction [ + | updates | + initialize [ updates := LookupTable new. ] + updates [^updates] + + putAll: o + [ o updates keysAndValuesDo: [ + :pos :new | self at: pos put: new ]] + + 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' ] + + tryMove: src by: off + [ | dst blk | + blk := grid at: src. + blk = $. ifTrue: [^true]. + blk = $# ifTrue: [^false]. + dst := src + off. + (self tryMove: dst by: off) + ifFalse: [^false] + ifTrue: [ + grid at: src put: $.. + grid at: dst put: blk. + ^true ] ] + + tryMoveTrans: src by: off + [ | dst blk | + blk := grid at: src. + blk = $. ifTrue: [^Transaction new]. + blk = $# ifTrue: [^nil]. + + off x = 0 ifTrue: [ + blk = $[ ifTrue: [^self tryMoveTrans0: src and: src + Posn right by: off]. + blk = $] ifTrue: [^self tryMoveTrans0: src and: src + Posn left by: off]. + ]. + ^self tryMoveTrans0: src by: off ] + + tryMoveTrans0: src1 and: src2 by: off + [ | dst1 dst2 blk1 blk2 | + dst1 := src1 + off. dst2 := src2 + off. + blk1 := grid at: src1. blk2 := grid at: src2. + ^(self tryMoveTrans: dst1 by: off) ifNotNil: [ + :th | (self tryMoveTrans: dst2 by: off) ifNotNil: [ + :th2 | + th putAll: th2. + th at: src1 put: $.. + th at: src2 put: $.. + th at: dst1 put: blk1. + th at: dst2 put: blk2. + th ]]] + + tryMoveTrans0: src by: off + [ | dst blk | + dst := src + off. + blk := grid at: src. + ^(self tryMoveTrans: dst by: off) ifNotNil: [ + :th | + th at: src put: $.. + th at: dst put: blk. + th ]] + + followInsn: insn + [ | dir | + dir := insnMap at: insn ifAbsent: [^false]. + (self tryMoveTrans: robot by: dir) ifNotNil: [ + :th | th 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 diff --git a/days/utils.st b/days/utils.st index 6ed35a1..1b16079 100644 --- a/days/utils.st +++ b/days/utils.st @@ -177,12 +177,18 @@ Stream extend [ whileTrue: [ block value: self next ] ] ] -String extend [ +CharacterArray extend [ scanf: fmt [ ^(ReadStream on: self) scanf: fmt ] scanf: fmt with: block [ ^(ReadStream on: self) scanf: fmt with: block ] trim [ ^self copyReplacingRegex: '\s*(.*)\s*' asRegex with: [:m | m at: 1] ] trimLines [ ^(self lines collect: [:it | it trim]) join: ' ' ] + + splitWords [ ^self tokenize: ' ' ] + splitDoubleNl [ ^self tokenize: String doubleNl ] +] +CharacterArray class extend [ + doubleNl [ ^self with: $<10> with: $<10> ] ] BlockClosure extend [ @@ -309,6 +315,8 @@ Object subclass: Grid [ :p | block value: p value: (self at: p) ] ] printOn: st [ rows do: [ :r | st << r; nl ] ] + + postCopy [ rows := rows collect: [:it | it copy] ] ] Grid class extend [ width: w height: h initWith: block