Advertisement
musifter

AoC 2021 day 15 (smalltalk-heap/flat)

Dec 15th, 2021
2,157
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/local/bin/gst -q
  2.  
  3. Integer extend [
  4.     " Does number % N, but returns residue on interval of 1 to N, not 0 to N-1. "
  5.     %% modulus [ ^self - 1 \\ modulus + 1 ]
  6. ]
  7.  
  8. " Heap class to implement priority queue "
  9. Object subclass: Heap [
  10.     | arr end |
  11.     Heap class >> new: size [
  12.         ^super new init: size
  13.     ]
  14.  
  15.     init: size [
  16.         arr := Array new: size.
  17.         end := 0.
  18.         ^self
  19.     ]
  20.  
  21.     heapify: idx [
  22.         | left right smallest |
  23.         left  := 2 * idx.
  24.         right := 2 * idx + 1.
  25.  
  26.         smallest := idx.
  27.  
  28.         ((left <= end) and: [(arr at: idx) > (arr at: left)]) ifTrue: [
  29.             smallest := left
  30.         ].
  31.  
  32.         ((right <= end) and: [(arr at: smallest) > (arr at: right)]) ifTrue: [
  33.             smallest := right
  34.         ].
  35.  
  36.         (smallest ~= idx) ifTrue: [
  37.             arr swap: idx with: smallest.
  38.             self heapify: smallest.
  39.         ]
  40.     ]
  41.  
  42.     insert: item [
  43.         | i parent |
  44.         end := end + 1.
  45.         (end > arr size) ifTrue: [
  46.             stderr nextPutAll: ('Heap size (%1) exceeded!' % {arr size}); nl.
  47.             Error signal.
  48.         ].
  49.  
  50.         arr at: end put: item.
  51.  
  52.         i := end.
  53.         [(i ~= 1) and: [(arr at: (parent := i // 2)) > (arr at: i)]] whileTrue: [
  54.             arr swap: i with: parent.
  55.             i := parent.
  56.         ].
  57.         ^item
  58.     ]
  59.  
  60.     next [
  61.         | top |
  62.         (end = 0) ifTrue: [ ^nil ].
  63.  
  64.         top := arr at: 1.
  65.         end := end - 1.
  66.  
  67.         (end > 1) ifTrue: [
  68.             arr at: 1 put: (arr at: end + 1).
  69.             self heapify: 1.
  70.         ].
  71.         ^top
  72.     ]
  73. ]
  74.  
  75. "
  76. | PriorityQueue implementation using Heap
  77. "
  78. Object subclass: PriorityItem [
  79.     | priority data |
  80.  
  81.     PriorityItem class >> new: pri data: anArray [ ^super new init: pri data: anArray ]
  82.     init: pri data: array [ priority := pri. data := array. ^self ]
  83.  
  84.     > state   [ ^self priority > state priority ]
  85.     priority  [ ^priority ]
  86.     data      [ ^data     ]
  87. ]
  88.  
  89. Object subclass: PriorityQueue [
  90.     | heap |
  91.     PriorityQueue class >> new [ ^super new init ]
  92.     init  [ heap := Heap new: 10000. ^self ]
  93.  
  94.     at: pri insert: data  [ heap insert: (PriorityItem new: pri data: data) ]
  95.  
  96.     next  [ ^heap next data ]
  97. ]
  98.  
  99. "
  100. |  Class to handle the 2D Grid
  101. "
  102. Object subclass: DigitGrid [
  103.     | grid xsize xwidth ysize dirs end visit |
  104.  
  105.     DigitGrid class >> new: arrayStrings [
  106.         ^(super new) init: arrayStrings.
  107.     ]
  108.  
  109.     init: mapArray [
  110.         | inx iny |
  111.         inx := (mapArray at: 1) size.
  112.         iny := mapArray size.
  113.  
  114.         xsize := inx * 5.
  115.         ysize := iny * 5.
  116.  
  117.         xwidth := xsize + 1.
  118.         dirs   := { 1. xwidth. -1. -1 * xwidth }.
  119.         end    := ysize * (xsize + 1) - 1.
  120.  
  121.         grid := Array new: end.
  122.  
  123.         (1 to: (mapArray at: 1) size) do: [ :y |
  124.             (1 to: mapArray size) do: [ :x |
  125.                 self atPoint: (x@y) put: ((mapArray at: y) at: x) digitValue.
  126.             ]
  127.         ].
  128.  
  129.         (0 to: 4) do: [ :cy |
  130.             (0 to: 4) do: [ :cx |
  131.                 ((cy ~= 0) | (cx ~= 0)) ifTrue: [
  132.                     | inc |
  133.                     inc := cy + cx.
  134.                     (1 to: iny) do: [ :y |
  135.                         (1 to: inx) do: [ :x |
  136.                             self atPoint: ((inx * cx + x) @ (iny * cy + y))
  137.                                  put: (self atPoint: (x@y)) + inc %% 9.
  138.                         ]
  139.                     ]
  140.                 ]
  141.             ]
  142.         ].
  143.  
  144.         visit := Array new: grid size withAll: SmallInteger largest.
  145.         ^self
  146.     ]
  147.  
  148.     " Access to grid by Points "
  149.     atPoint: pt put: val  [ ^grid at: ((pt y - 1) * xwidth + pt x) put: val ]
  150.     atPoint: pt           [ ^grid at: ((pt y - 1) * xwidth + pt x)          ]
  151.  
  152.     " Access to grid by index to flat array "
  153.     at: idx   [ ^grid at: idx ]
  154.  
  155.     visited: idx         [ ^visit at: idx ]
  156.     visit: idx at: risk  [ ^visit at: idx put: risk ]
  157.  
  158.     xsize     [ ^xsize ]
  159.     ysize     [ ^ysize ]
  160.     endIndex  [ ^end   ]
  161.  
  162.     " Get coordinates of neighbours "
  163.     neighbours: idx [
  164.         ^(dirs collect: [:d | idx + d ]) select: [:n |
  165.             (n between: 1 and: end) and: [n \\ xwidth ~= 0]
  166.         ]
  167.     ]
  168. ]
  169.  
  170. "
  171. | Mainline
  172. "
  173. Eval [
  174.     grid := DigitGrid new: (stdin lines contents).
  175.     end  := grid endIndex.
  176.  
  177.     queue := PriorityQueue new.
  178.     queue at: 0 insert: {0. 1}.
  179.  
  180.     time := 0.
  181.  
  182.     [ (state := queue next) notNil ] whileTrue: [
  183.         | pos risk |
  184.         risk  := state first.
  185.         pos   := state second.
  186.  
  187.         ((time := time + 1) \\ 50000 == 1) ifTrue: [
  188.             stderr nextPutAll: ('Risk: %1' % {risk}); cr; flush.
  189.         ].
  190.  
  191.         (pos = end) ifTrue: [
  192.             ^('Part 2: %1' % {risk}) displayNl.
  193.         ].
  194.  
  195.         ((grid visited: pos) > risk) ifTrue: [
  196.             grid visit: pos at: risk.
  197.  
  198.             (grid neighbours: pos) do: [ :move |
  199.                | new_risk |
  200.                 new_risk := risk + (grid at: move).
  201.                 queue at: new_risk insert: {new_risk. move}.
  202.             ]
  203.         ]
  204.     ]
  205. ]
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement