108 lines
3.3 KiB
Smalltalk
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.
|