Advertisement
musifter

AoC 2021 day 18 (smalltalk)

Dec 18th, 2021
1,810
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/local/bin/gst -q
  2.  
  3. Object subclass: SFNode [
  4.     | parent value left right |
  5.     " Constructors "
  6.     SFNode class >> new: aStream parent: node [
  7.         ^super new initFrom: aStream parent: node
  8.     ]
  9.  
  10.     initFrom: aStream parent: node [
  11.         parent := node.
  12.         ^self parseNode: aStream.
  13.     ]
  14.  
  15.     SFNode class >> left: lnode right: rnode [
  16.         ^super new init: lnode with: rnode
  17.     ]
  18.  
  19.     init: lnode with: rnode [
  20.         parent := nil.
  21.         left  := lnode parent: self; yourself.
  22.         right := rnode parent: self; yourself.
  23.         ^self
  24.     ]
  25.  
  26.     SFNode class >> leaf: val parent: node [
  27.         ^super new initLeaf: val parent: node
  28.     ]
  29.  
  30.     initLeaf: val parent: node [
  31.         parent := node.
  32.         value  := val.
  33.         left   := nil.
  34.         right  := nil.
  35.         ^self
  36.     ]
  37.  
  38.     " Tree parser and builder "
  39.     parseNode: aStream [
  40.         | chr |
  41.         [ aStream atEnd not ] whileTrue: [
  42.             chr := aStream next.
  43.  
  44.             " NOTE: Assuming single digit numbers only in input! "
  45.             (chr isDigit) ifTrue: [ ^SFNode leaf: chr digitValue parent: self parent ].
  46.             (chr = $])    ifTrue: [ ^self ].
  47.  
  48.             (chr = $[) ifTrue: [
  49.                 left  := SFNode new: aStream parent: self.
  50.             ] ifFalse: [ " chr = $, "
  51.                 right := SFNode new: aStream parent: self.
  52.             ]
  53.         ].
  54.         ^self
  55.     ]
  56.  
  57.     " Access methods "
  58.     left    [ ^left   ]
  59.     right   [ ^right  ]
  60.     parent  [ ^parent ]
  61.     value   [ ^value  ]
  62.  
  63.     left:  val  [ left   := val ]
  64.     right: val  [ right  := val ]
  65.     parent: val [ parent := val ]
  66.     value: val  [ value  := val ]
  67.  
  68.     isLeaf  [ ^value notNil ]
  69.  
  70.     magnitude [
  71.         (self isLeaf) ifTrue: [ ^value ].
  72.         ^(3 * left magnitude) + (2 * right magnitude)
  73.     ]
  74.  
  75.     depth [
  76.         | dep curr |
  77.         dep := -1.
  78.         curr := self.
  79.         [curr notNil] whileTrue: [
  80.             dep := dep + 1.
  81.             curr := curr parent.
  82.         ].
  83.         ^dep
  84.     ]
  85.  
  86.     " For display "
  87.     printOn: aStream [
  88.         (self isLeaf) ifTrue: [
  89.             aStream nextPutAll: value asString.
  90.         ] ifFalse: [
  91.             aStream nextPutAll: '['.
  92.             left printOn: aStream.
  93.             aStream nextPutAll: ','.
  94.             right printOn: aStream.
  95.             aStream nextPutAll: ']'.
  96.         ]
  97.     ]
  98. ]
  99.  
  100. Object subclass: SnailfishNumber [
  101.     | root |
  102.     SnailfishNumber class >> from: aString [
  103.         ^super new init: (SFNode new: (ReadStream on: aString) parent: nil)
  104.     ]
  105.  
  106.     SnailfishNumber class >> left: snLeft right: snRight [
  107.         ^super new init: (SFNode left: snLeft right: snRight)
  108.     ]
  109.  
  110.     init: node [
  111.         root := node.
  112.         ^self
  113.     ]
  114.  
  115.     root      [ ^root ]
  116.     magnitude [ ^root magnitude ]
  117.  
  118.     + sfNum [
  119.         ^(SnailfishNumber left: root right: sfNum root) reduce
  120.     ]
  121.  
  122.     " Walk tree looking for first explode.  Returns true if valid, false if explode done. "
  123.     validatorExplode [
  124.         | curr stack prevLeaf explode |
  125.         stack   := OrderedCollection with: root.
  126.         explode := nil.
  127.  
  128.         [stack notEmpty] whileTrue: [
  129.             curr := stack removeLast.
  130.  
  131.             (curr isLeaf) ifTrue: [
  132.                 (explode) ifNotNil: [
  133.                     " Exploding!  Finish and quit. "
  134.                     curr value: (curr value + explode).
  135.                     ^false
  136.                 ] ifNil: [
  137.                     " Not exploding!  Track most recent leaf in case we do. "
  138.                     prevLeaf := curr.
  139.                 ]
  140.  
  141.             ] ifFalse: [
  142.                 ((curr depth >= 4) and: [explode isNil]) ifTrue: [
  143.                     " Exploding current node "
  144.                     " Add to previous if we've seen one: "
  145.                     (prevLeaf) ifNotNil: [
  146.                         prevLeaf value: (prevLeaf value + curr left value)
  147.                     ].
  148.  
  149.                     " Mark that we're in exploding state with value to add to next "
  150.                     explode := curr right value.
  151.  
  152.                     " Replace current node with 0 leaf node "
  153.                     curr value: 0; left: nil; right: nil.
  154.                 ]
  155.             ].
  156.  
  157.             (curr right) ifNotNil: [stack addLast: curr right].
  158.             (curr left)  ifNotNil: [stack addLast: curr left ].
  159.         ].
  160.  
  161.         ^(explode isNil)
  162.     ]
  163.  
  164.     " Walk tree looking for first split.  Returns true if valid, false if split done. "
  165.     validatorSplit [
  166.         | curr stack |
  167.         stack   := OrderedCollection with: root.
  168.  
  169.         [stack notEmpty] whileTrue: [
  170.             curr := stack removeLast.
  171.  
  172.             (curr isLeaf) ifTrue: [
  173.                 | val |
  174.                 val := curr value.
  175.                 (val > 9) ifTrue: [
  176.                     " Splitting current node "
  177.                     curr left:  (SFNode leaf: (val / 2) floor   parent: curr);
  178.                          right: (SFNode leaf: (val / 2) ceiling parent: curr);
  179.                          value: nil.
  180.                     ^false
  181.                 ]
  182.             ].
  183.  
  184.             (curr right) ifNotNil: [stack addLast: curr right].
  185.             (curr left)  ifNotNil: [stack addLast: curr left ].
  186.         ].
  187.  
  188.         ^true
  189.     ]
  190.  
  191.     reduce [
  192.         [
  193.             (self validatorExplode) and: [self validatorSplit]
  194.         ] whileFalse.
  195.     ]
  196. ]
  197.  
  198. "
  199. | Mainline
  200. "
  201. input := stdin lines contents.
  202.  
  203. " Part 1 "
  204. sum := (input collect: [:line | SnailfishNumber from: line]) fold: [:a :b | a + b].
  205.  
  206. ('Final sum: %1' % {sum root}) displayNl.
  207. ('Part 1: %1' % {sum magnitude}) displayNl.
  208.  
  209. " Part 2 "
  210. count := 0.
  211. maxMag := 0.
  212. input do: [ :i |
  213.     stderr nextPutAll: ('Working: %1' % {count := count + 1}); cr; flush.
  214.     input do: [ :j |
  215.         (i ~= j) ifTrue: [
  216.             maxMag := maxMag max: ((SnailfishNumber from: i)
  217.                                     + (SnailfishNumber from: j)) magnitude.
  218.         ]
  219.     ]
  220. ].
  221.  
  222. stdout nl.
  223. ('Part 2: %1' % {maxMag}) displayNl.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement