Day 21
This commit is contained in:
parent
ae355f1a54
commit
bf7f2fede6
2 changed files with 202 additions and 9 deletions
185
days/day21.st
Normal file
185
days/day21.st
Normal 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.
|
||||||
|
|
@ -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 [
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue