This commit is contained in:
Beatrice Szilvasy 2024-12-21 09:26:43 +00:00
parent ae355f1a54
commit bf7f2fede6
2 changed files with 202 additions and 9 deletions

185
days/day21.st Normal file
View file

@ -0,0 +1,185 @@
Object subclass: KeyseqSet [
| seqs size length |
size [^size]
length [^length]
seqs: s
[ s do: [
:e | | len sz |
len := self lengthOf: e.
sz := self sizeOf: e.
length
ifNil: [
length := len. size := sz.
seqs := OrderedCollection with: e.
]
ifNotNil: [
:l |
len = l ifTrue: [
size := size + 1.
seqs add: e.
] ifFalse: [
len < l ifTrue: [
length := len. size := sz.
seqs := OrderedCollection with: e.
]
]]
].
seqs := seqs asArray.
]
sizeOf: e [e isString ifTrue: [^1] ifFalse: [^e size]]
lengthOf: e [e isString ifTrue: [^e size] ifFalse: [^e length]]
allOf: e [e isString ifTrue: [^{e}] ifFalse: [^e allOf]]
allOf
[ | set |
set := Set new.
seqs collect: [:e | set addAll: (self allOf: e)].
^set ]
printOn: st [ st << self class << '['
<< 's=' << size << ',l=' << length
<< ']' << seqs ]
]
KeyseqSet subclass: KeyseqCat [
seqs: s
[ seqs := s asArray.
size := seqs inject: 1 into: [:a :r | a * (self sizeOf: r)].
length := seqs inject: 0 into: [:a :r | a + (self lengthOf: r)] ]
allOf
[ | set |
set := Set new.
self allOfInto: set from: 1 pfx: ''.
^set ]
allOfInto: set from: i pfx: pfx
[ | e | i > seqs size ifTrue: [^set add: pfx].
e := seqs at: i.
(self allOf: e) do: [
:str | self allOfInto: set from: i + 1 pfx: pfx,str]]
]
Object subclass: Keypad [
| grid paths optimal |
grid: g
[ grid := g.
paths := LookupTable new.
grid allPosnsDo: [:pos | self pathsFrom: pos] ]
paths [^paths]
pathsFrom: pos
[ (grid at: pos) = $. ifTrue: [^self].
grid allPosnsDo: [:opos | self pathsFrom: pos to: opos] ]
pathsFrom: pos to: opos
[ | dx dy c1 c2 seqs |
c2 := grid at: opos.
c2 = $. ifTrue: [^self].
c1 := grid at: pos.
dx := opos x - pos x.
dy := opos y - pos y.
seqs := self allPathsFrom: pos by: dx and: dy prefix: ''.
paths at: (String with: c1 with: c2) put: seqs ]
allPathsFrom: pos by: dx and: dy prefix: pfx
[ | set sym oset |
(grid at: pos) = $. ifTrue: [^#()].
(dx = 0 and: [dy = 0]) ifTrue: [^{pfx,'A'}].
set := OrderedCollection new.
dx = 0 ifFalse: [
sym := dx < 0 ifTrue: ['<'] ifFalse: ['>'].
oset := self allPathsFrom: pos + (Posn x: dx sign y: 0)
by: dx - dx sign and: dy prefix: pfx,sym.
set addAll: oset.
].
dy = 0 ifFalse: [
sym := dy < 0 ifTrue: ['^'] ifFalse: ['v'].
oset := self allPathsFrom: pos + (Posn x: 0 y: dy sign)
by: dx and: dy - dy sign prefix: pfx,sym.
set addAll: oset.
].
^set ]
pressPath: key to: okey [ ^paths at: (String with: key with: okey) ]
printOn: st [ st << grid ]
"Replace the path set for each key pair with a singleton set of the
best path, in terms of keypresses required by a sufficiently long chain."
optimisePaths
[ | robot |
optimal ifNotNil: [^self].
optimal := true.
robot := Robot robotChain: 4. "seems to be a fixed point"
paths keysAndValuesDo: [
:key :seqs | | nseqs |
nseqs := seqs collect: [:it | {(robot keyseqFor: it) length . it}].
nseqs sort: [:l :r | (l at: 1) <= (r at: 1)].
paths at: key put: {(nseqs at: 1) at: 2}]]
]
Keypad class extend [
| numpad dirpad |
parse: rows [ ^Keypad new grid: (Grid new rows: rows) ]
numpad [^numpad ifNil: [
numpad := Keypad parse:
#('789'
'456'
'123'
'.0A')]]
dirpad [^dirpad ifNil: [
dirpad := Keypad parse:
#('.^A'
'<v>')]]
]
Object subclass: Robot [
| keypad controlledBy seqCache depth |
keypad: kp [keypad := kp. depth := 0]
keypad: kp controlledBy: robo
[keypad := kp. controlledBy := robo.
depth := robo ifNil: [0] ifNotNil: [:it | it depth + 1]]
depth [^depth]
initialize [seqCache := LookupTable new]
keyseqFor: str
[ ^seqCache at: str ifAbsent: [
^seqCache at: str put: (self computeKeyseqFor: str)] ]
computeKeyseqFor: str
[ | steps |
steps := 0 to: str size - 1 collect: [
:i | | paths |
paths := keypad pressPath: (str at: i ifAbsent: [$A])
to: (str at: i + 1).
controlledBy ifNotNil: [
paths := paths collect: [:it | controlledBy keyseqFor: it]].
KeyseqSet new seqs: paths
].
^KeyseqCat new seqs: steps ]
]
Robot class extend [
robotChain: len
[ len = 0 ifTrue: [^nil].
^self new keypad: Keypad dirpad controlledBy:
(self robotChain: len - 1) ]
fullChain: keypad length: len
[ ^self new keypad: keypad controlledBy: (self robotChain: len) ]
]
AOC input: [ Keypad dirpad optimisePaths.
"Keypad numpad optimisePaths. -- it's not even worth it"
stdin toLines asArray ];
part1: 2; part2: 25; partN: 100 ":D";
result: [ :codes :chainLen | | robot |
robot := Robot fullChain: Keypad numpad length: chainLen.
(codes collect: [
:code | (robot keyseqFor: code) length * code asNumber])
sum ];
finish.

View file

@ -1,23 +1,30 @@
"--- AOC helper class ---" "--- AOC helper class ---"
Object subclass: AOC [] Object subclass: AOC []
AOC class extend [ AOC class extend [
| savedP1 savedP2 mapper getInput actionDict | | savedParts mapper getInput actionDict |
input: inpBlock [ getInput := inpBlock ]
part1: p1Block [ savedP1 := p1Block ] initialize
part2: p2Block [ savedP2 := p2Block ] [ savedParts := Array new: 2.
getInput := OrderedCollection new. ]
input: inpBlock [ getInput add: inpBlock ]
part1: partBlock [ savedParts at: 1 put: partBlock ]
part2: partBlock [ savedParts at: 2 put: partBlock ]
partN: partBlock [ savedParts := savedParts,{partBlock} ]
result: mapBlock [ mapper := mapBlock ] result: mapBlock [ mapper := mapBlock ]
output: value part: part [ stdout << 'Part ' << part << ': ' << value; nl; flush. ] output: value part: part [ stdout << 'Part ' << part << ': ' << value; nl; flush. ]
runPart: saved part: part arg: arg runPart: saved part: part args: args
[ saved ifNotNil: [ [ saved ifNotNil: [
| mapped | mapped := mapper value: arg value: saved. | mapped |
mapped := mapper valueWithArguments: args,{saved}.
self output: mapped part: part ] ] self output: mapped part: part ] ]
run run
[ | inp | inp := getInput value. [ | inps | inps := getInput asArray collect: [:it | it value].
self runPart: savedP1 part: 1 arg: inp. savedParts keysAndValuesDo: [
self runPart: savedP2 part: 2 arg: inp. ] :part :saved | self runPart: saved part: part args: inps ]]
action: name do: block action: name do: block
[ actionDict ifNil: [actionDict := Dictionary new]. [ actionDict ifNil: [actionDict := Dictionary new].
@ -45,6 +52,7 @@ AOC class extend [
file parent createDirectories. file parent createDirectories.
io := file writeStream. [ block value: io ] ensure: [io close] ] io := file writeStream. [ block value: io ] ensure: [io close] ]
] ]
AOC initialize.
"--- Scanf ---" "--- Scanf ---"
Object subclass: ScannerState [ Object subclass: ScannerState [