diff --git a/days/day20.st b/days/day20.st index e861d02..64c8aff 100644 --- a/days/day20.st +++ b/days/day20.st @@ -114,79 +114,6 @@ Object subclass: Racetrack [ block value: dpos value: ddist ] asSpreader ] ] -Object subclass: KDTree [ - from: min to: max do: block - [ self subclassResponsibility ] -] -KDTree class extend [ - fromPoints: points - [ ^self fromShuffledPoints: (Random new shuffle: points asArray) ] - - fromShuffledPoints: points - [ ^self fromShuffledPoints: points axis: 1 ] - - leafMaxSize [ ^5 ] - fromShuffledPoints: points axis: ax - [ | med splits dims nextAx value | - points size <= self leafMaxSize ifTrue: [^KDLeaf new points: points asArray]. - med := self guessMedian: points axis: ax. - dims := med size. - nextAx := ax \\ dims + 1. - value := med at: ax. - splits := self splitPoints: points axis: ax on: value. - ^KDInner new - left: (self fromShuffledPoints: (splits at: 1) axis: nextAx) - right: (self fromShuffledPoints: (splits at: 2) axis: nextAx) - axis: ax - value: value ] - - splitPoints: points axis: ax on: val - [ | l r fairLeft | - l := OrderedCollection new. - r := OrderedCollection new. - fairLeft := true. - points do: [ - :point | | v onLeft | - v := point at: ax. - onLeft := (v < val) or: [ - v = val and: [fairLeft := fairLeft not. fairLeft]]. - (onLeft ifTrue: [l] ifFalse: [r]) add: point ]. - ^{l . r} ] - - medianGuessSize [ ^5 ] - guessMedian: points axis: ax - [ | arr | - arr := 1 to: (points size min: self medianGuessSize) - collect: [:i | points at: i]. - arr sort: [:l :r | (l at: ax) <= (r at: ax)]. - ^arr at: arr size // 2 + 1 ] -] - -KDTree subclass: KDLeaf [ - | points | - points: n [points := n. "self class leafSize: points size"] - from: min to: max do: block [ points do: block ] - - printOn: st [ st << 'lf' << points ] -] -KDLeaf class extend [ - | leafSizes | - leafSizes [ ^leafSizes ifNil: [leafSizes := Bag new] ] - leafSize: sz [ self leafSizes add: sz ] -] - -KDTree subclass: KDInner [ - | left right axis value | - left: l right: r axis: ax value: v - [left:=l. right:=r. axis:=ax. value:=v] - from: min to: max do: block - [ (min at: axis) <= value ifTrue: [ left from: min to: max do: block ]. - (max at: axis) >= value ifTrue: [ right from: min to: max do: block ] ] - - printOn: st [ st << '{' << left << ' <= [' << axis << '] ' - << value << ' <= ' << right << '}' ] -] - AOC input: [ Racetrack new rows: stdin toLines asArray ]; part1: 2; part2: 20; result: [ :track :time | track countCheatsWithTime: time ]; diff --git a/days/day25.st b/days/day25.st new file mode 100644 index 0000000..ad6882d --- /dev/null +++ b/days/day25.st @@ -0,0 +1,36 @@ +Object subclass: KeyOrLock [ + | isLock height value | + value [^value] + isLock [^isLock] + + rows: r + [ | cols | + cols := r lines transposed. + isLock := cols allSatisfy: [:it | (it at: 1) = $#]. + height := (cols at: 1) size. + value := cols collect: [ + :it | | first | first := it at: 1. + it count: [:c | c = first]] ] +] + +AOC input: [ stdin contents splitDoubleNl collect: + [:it | KeyOrLock new rows: it] ]; + part1: [ :input | | locks keys minPos total | + locks := OrderedCollection new. + keys := OrderedCollection new. + input do: [:it | it isLock + ifTrue: [locks add: it value] + ifFalse: [keys add: it value]]. + locks := KDTree fromPoints: locks. + + total := 0. + minPos := Array new: (keys at: 1) size withAll: 0. + keys do: [ + :key | locks from: minPos to: key do: [ + :lock | + ((key with: lock) allSatisfy: [ + :k :l | k >= l ] asSpreader) + ifTrue: [total := total + 1]]]. + total ]; + result: [ :input :part | part value: input ]; + finish. diff --git a/days/utils.st b/days/utils.st index a51825d..97f12c5 100644 --- a/days/utils.st +++ b/days/utils.st @@ -419,3 +419,77 @@ Random extend [ ]. ^coll ] ] + +"--- KDTree ---" +Object subclass: KDTree [ + from: min to: max do: block + [ self subclassResponsibility ] +] +KDTree class extend [ + fromPoints: points + [ ^self fromShuffledPoints: (Random new shuffle: points asArray) ] + + fromShuffledPoints: points + [ ^self fromShuffledPoints: points axis: 1 ] + + leafMaxSize [ ^5 ] + fromShuffledPoints: points axis: ax + [ | med splits dims nextAx value | + points size <= self leafMaxSize ifTrue: [^KDLeaf new points: points asArray]. + med := self guessMedian: points axis: ax. + dims := med size. + nextAx := ax \\ dims + 1. + value := med at: ax. + splits := self splitPoints: points axis: ax on: value. + ^KDInner new + left: (self fromShuffledPoints: (splits at: 1) axis: nextAx) + right: (self fromShuffledPoints: (splits at: 2) axis: nextAx) + axis: ax + value: value ] + + splitPoints: points axis: ax on: val + [ | l r fairLeft | + l := OrderedCollection new. + r := OrderedCollection new. + fairLeft := true. + points do: [ + :point | | v onLeft | + v := point at: ax. + onLeft := (v < val) or: [ + v = val and: [fairLeft := fairLeft not. fairLeft]]. + (onLeft ifTrue: [l] ifFalse: [r]) add: point ]. + ^{l . r} ] + + medianGuessSize [ ^5 ] + guessMedian: points axis: ax + [ | arr | + arr := 1 to: (points size min: self medianGuessSize) + collect: [:i | points at: i]. + arr sort: [:l :r | (l at: ax) <= (r at: ax)]. + ^arr at: arr size // 2 + 1 ] +] + +KDTree subclass: KDLeaf [ + | points | + points: n [points := n. "self class leafSize: points size"] + from: min to: max do: block [ points do: block ] + + printOn: st [ st << 'lf' << points ] +] +KDLeaf class extend [ + | leafSizes | + leafSizes [ ^leafSizes ifNil: [leafSizes := Bag new] ] + leafSize: sz [ self leafSizes add: sz ] +] + +KDTree subclass: KDInner [ + | left right axis value | + left: l right: r axis: ax value: v + [left:=l. right:=r. axis:=ax. value:=v] + from: min to: max do: block + [ (min at: axis) <= value ifTrue: [ left from: min to: max do: block ]. + (max at: axis) >= value ifTrue: [ right from: min to: max do: block ] ] + + printOn: st [ st << '{' << left << ' <= [' << axis << '] ' + << value << ' <= ' << right << '}' ] +]