aoc2024/days/day14.st
2024-12-14 12:28:42 +00:00

108 lines
3.3 KiB
Smalltalk

Object subclass: Robot [
| pos vel |
parse: line
[ line scanf: 'p=%d,%d v=%d,%d' with: [
:px :py :vx :vy |
pos := Posn x: px y: py.
vel := Posn x: vx y: vy ]]
printOn: st [ st << '{p=' << pos << ' v=' << vel << '}' ]
posAt: time in: br
[ ^Posn
x: (pos x + (vel x * (time \\ br w))) \\ br w
y: (pos y + (vel y * (time \\ br h))) \\ br h ]
]
Array extend [
incAt: pos [ self at: pos put: 1 + (self at: pos) ]
]
Posn subclass: Bathroom [
| midx midy |
w [^x] h [^y]
x: n [super x: n. midx := x // 2]
y: n [super y: n. midy := y // 2]
countQuadrants: posns
[ | qs |
qs := Array new: 4 withAll: 0.
posns do: [ :p | self putPosn: p toQuad: qs ].
^qs inject: 1 into: [:l :r | l * r] ]
putPosn: p toQuad: qs
[ | top bot |
top := p y < midy.
bot := p y > midy.
p x < midx ifTrue:
[ top ifTrue: [^qs incAt: 1].
bot ifTrue: [^qs incAt: 2].
^nil ].
p x > midx ifTrue:
[ top ifTrue: [^qs incAt: 3].
bot ifTrue: [^qs incAt: 4].
^nil ] ]
findMaxOf: robots inPeriod: p withTrue: filter
[ | best bestTime |
best := -1.
1 to: p do: [
:time | | cnt |
cnt := robots count: [:it | filter value: (it posAt: time in: self)].
cnt > best ifTrue: [best := cnt. bestTime := time] ].
^bestTime ]
plot: robots at: time
[ | grid orig |
grid := 1 to: self h collect: [:i | String new: self w withAll: $.].
grid := Grid new rows: grid.
orig := Posn x: 1 y: 1.
robots do: [:r | grid at: orig + (r posAt: time in: self) put: $#].
stdout << 'At ' << time << ':'; nl; << grid; nl; nl. ]
betweenPercentile: min and: max by: getKey
[ | mine minV maxV |
mine := getKey value: self.
minV := mine * min.
maxV := mine * max.
^[ :it | | its | its := getKey value: it.
minV <= its and: [its <= maxV] ] ]
inMiddleBy: getKey
[ ^self betweenPercentile: 0.4 and: 0.6 by: getKey ]
findMaxRobots: robots inMiddleBy: getKey
[ ^self findMaxOf: robots
inPeriod: (getKey value: self)
withTrue: (self inMiddleBy: getKey) ]
findTreeTimeOf: robots
[ | bestx besty |
"The tree is a little pictogram in the center of the image -- we
find the offset with which the robots condense here on both the
X and Y axes, then use CRT to compute where these coincide."
bestx := self findMaxRobots: robots inMiddleBy: [:it | it x].
besty := self findMaxRobots: robots inMiddleBy: [:it | it y].
(self w gcd: self h) = 1 ifFalse: [self error: 'Not coprime'].
^(self w egcd: self h) letArrayInBlock:
[ :cx :cy |
(bestx * cy * self h)
+ (besty * cx * self w)
\\ (self w * self h) ] ]
]
Bathroom class extend [
width: w height: h [^self x: w y: h]
]
theBathroom := Bathroom width: 101 height: 103.
AOC input: [ stdin toLines asArray collect: [ :it | Robot new parse: it ] ];
part1: [ :robots | | posns |
posns := robots collect: [:it | it posAt: 100 in: theBathroom].
theBathroom countQuadrants: posns ];
part2: [ :robots | theBathroom findTreeTimeOf: robots ];
result: [ :robots :part | part value: robots. ];
finish.