Advertisement
musifter

AoC 2024 day 12 (smalltalk)

Dec 12th, 2024 (edited)
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Smalltalk 3.78 KB | Source Code | 0 0
  1. #!/usr/local/bin/gst -q
  2.  
  3. " Structure class for a Field of field of a plant: "
  4. Object subclass: Field [
  5.     | plant plots neigh |
  6.     Field class >> new: chr  [^super new init: chr]
  7.     init: chr [
  8.         plant := chr.
  9.         plots := Set new.
  10.         neigh := Dictionary new.
  11.         ^self
  12.     ]
  13.  
  14.     addPlot: coord  [^plots add: coord]
  15.  
  16.     addNeighbour: coord from: dir [
  17.         ^(neigh at: coord ifAbsentPut: [Set new]) add: dir.
  18.     ]
  19.  
  20.     " Perimeter is the number of ways into a neighbour: "
  21.     perimeter   [^neigh inject: 0 into: [:a :n | a + n size]]
  22.  
  23.     plant       [^plant]
  24.     plots       [^plots]
  25.     neighbours  [^neigh]
  26. ]
  27.  
  28. Object subclass: GardenGrid [
  29.     | grid dirs dimX dimY |
  30.  
  31.     " Constructor: "
  32.     GardenGrid class >> new: mapArray  [^super new init: mapArray]
  33.  
  34.     init: mapArray [
  35.         | sentinel |
  36.         dimY := mapArray size + 2.
  37.         dimX := mapArray first size + 2.
  38.         dirs := {dimX. 1. -1 * dimX. -1}.
  39.  
  40.         " Add sentinels to all sides "
  41.         sentinel := (1 to: dimX) inject: '' into: [:a :b | a, '.'].
  42.         grid := sentinel, (mapArray collect: [:row | '.', row, '.']) join, sentinel.
  43.         ^self
  44.     ]
  45.  
  46.     " Returns direction left of dir: "
  47.     widdershins: dir [
  48.         ^dirs at: (dirs findFirst: [:el | el == dir]) \\ 4 + 1.
  49.     ]
  50.  
  51.     " Find all Fields in grid and return a Set of them: "
  52.     getFields [
  53.         | fields field visited plant queue pos move |
  54.         fields  := Set new.
  55.         visited := Set new.
  56.         queue   := OrderedCollection new.
  57.  
  58.         grid keysAndValuesDo: [:idx :plant |
  59.             (plant == $.) | (visited includes: idx) ifFalse: [
  60.                 " Found a new Field, create it: "
  61.                 field := (Field new: plant) addPlot: idx; yourself.
  62.                 fields add: field.
  63.  
  64.                 " BFS to find entire field and its neighbours: "
  65.                 queue add: idx.
  66.                 [queue notEmpty] whileTrue: [
  67.                     pos := queue removeFirst.
  68.  
  69.                     (visited includes: pos) ifFalse: [
  70.                         dirs do: [:dir |
  71.                             move := pos + dir.
  72.                             ((grid at: move) == plant) ifTrue: [
  73.                                 field addPlot: move.
  74.                                 queue add: move.
  75.                             ] ifFalse: [
  76.                                 field addNeighbour: move from: dir.
  77.                             ]
  78.                         ]
  79.                     ].
  80.                     visited add: pos.
  81.                 ]
  82.             ]
  83.         ].
  84.         ^fields
  85.     ]
  86.  
  87.     " Access: "
  88.     at: idx  [^grid at: idx]
  89.  
  90.     " Print grid on stream "
  91.     printOn: aStream [
  92.         (1 to: grid size) do: [:y |
  93.             aStream nextPut: (grid at: y).
  94.             (y \\ dimX = 0) ifTrue: [aStream nl].
  95.         ]
  96.     ]
  97. ]
  98.  
  99. "
  100. | Mainline
  101. "
  102. grid   := GardenGrid new: stdin lines contents.
  103. fields := grid getFields.
  104.  
  105. part1 := fields inject: 0 into: [:a :f | a + (f plots size * f perimeter)].
  106.  
  107. part2 := 0.
  108. fields do: [ :field |
  109.     plant   := field plant.
  110.     corners := Set new.
  111.  
  112.     " Get corners of this field by going left around the perimeter: "
  113.     field neighbours keysAndValuesDo: [:pos :dirs |
  114.         dirs do: [:dir |
  115.             left   := grid widdershins: dir.
  116.             corner := pos.
  117.  
  118.             [(field neighbours includesKey: corner) & ((grid at: corner - dir) == plant)] whileTrue: [
  119.                 corner := corner + left.
  120.             ].
  121.  
  122.             " Plot found might have multiple corners, track directions we slide in: "
  123.             corners add: (corner -> left).
  124.         ]
  125.     ].
  126.  
  127.     part2 := part2 + (field plots size * corners size).
  128. ].
  129.  
  130. ('Part 1: %1' % {part1}) displayNl.
  131. ('Part 2: %1' % {part2}) displayNl.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement