Advertisement
musifter

AoC 2022, day 21 (smalltalk)

Dec 21st, 2022
2,592
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Smalltalk 3.56 KB | Source Code | 0 0
  1. #!/usr/local/bin/gst -q
  2.  
  3. Object subclass: Monkey [
  4.     | name op args value |
  5.  
  6.     Monkey class >> new: name with: exp [
  7.         ^super new init: name with: exp
  8.     ]
  9.  
  10.     init: nameString with: expString [
  11.         | exp |
  12.         name := nameString.
  13.         exp  := expString substrings.
  14.  
  15.         (exp size = 1) ifTrue: [
  16.             value := exp first asNumber.
  17.         ] ifFalse: [
  18.             op   := exp second.
  19.             args := {exp first. exp third}.
  20.         ].
  21.         ^self
  22.     ]
  23.  
  24.     isSolved    [ ^value notNil ]
  25.     value: num  [ ^value := num ]
  26.     value       [ ^value ]
  27.  
  28.     hasExp      [ ^op notNil    ]
  29.     op          [ ^op           ]
  30.     args        [ ^args         ]
  31.  
  32.     printOn: aStream [
  33.         aStream nextPutAll: ('Monkey: %1 ' % {value}).
  34.         (self hasExp) ifTrue: [
  35.             aStream nextPutAll: ('(%1 %2 %3)' % {args first. op. args second})
  36.         ].
  37.     ]
  38. ]
  39.  
  40. Dictionary subclass: MonkeyDictionary [
  41.     <shape: #pointer>
  42.  
  43.     clear [self do: [:monk | (monk hasExp) ifTrue: [monk value: nil]]]
  44.  
  45.     " Part 1: little recursive solving of the expression tree "
  46.     solve: monkName [
  47.         | monk args |
  48.         monk := self at: monkName.
  49.         (monk isSolved) ifTrue: [
  50.             ^monk value
  51.         ] ifFalse: [
  52.             args := monk args collect: [:arg | self solve: arg].
  53.             ^monk value: (args first perform: monk op asSymbol
  54.                                         with: args second).
  55.         ]
  56.     ]
  57.  
  58.     " Part 2: Like above, but leaves humn as a variable "
  59.     getExpString: monkName [
  60.         | monk args |
  61.         monk := self at: monkName.
  62.         (monkName = 'humn') ifTrue: [ ^monkName ].
  63.         (monk isSolved)     ifTrue: [ ^monk value ].
  64.  
  65.         args := monk args collect: [:arg | self getExpString: arg].
  66.  
  67.         (args conform: [:a | a isNumber]) ifTrue: [
  68.             ^args first perform: monk op asSymbol with: args second.
  69.         ].
  70.         ^'(', args first asString, monk op, args second asString, ')'
  71.     ]
  72. ]
  73.  
  74. "
  75. | Mainline
  76. "
  77. monkeys := MonkeyDictionary new.
  78.  
  79. stdin linesDo: [ :line |
  80.     parts := line tokenize: ': '.
  81.     monkeys at: parts first put: (Monkey new: parts first with: parts second).
  82. ].
  83.  
  84. ('Part 1: %1' % {monkeys solve: 'root'}) displayNl.
  85. monkeys clear.
  86.  
  87. " Get the two halves of root to equal: One is a number, the other
  88.   an expression with the humn variable "
  89. exp := nil.
  90. num := nil.
  91. (monkeys at: 'root') args do: [:targ |
  92.     res := (monkeys getExpString: targ).
  93.     (res isNumber) ifTrue: [
  94.         num := res.
  95.     ] ifFalse: [
  96.         exp := res.
  97.     ]
  98. ].
  99.  
  100. ('Number to balance: %1' % {num}) displayNl.
  101. ('Expression: %1' % {exp}) displayNl.
  102.  
  103. " Build block from expression for sampling/testing "
  104. block := Behavior evaluate: ('[:humn | ', exp, ']').
  105.  
  106. " Two sample points will allow us to interpolate: "
  107. atZero := block value: 0.
  108. ('Result at humn = 0: %1' % {atZero}) displayNl.
  109.  
  110. atOne  := block value: 1.
  111. ('Result at humn = 1: %1' % {atOne}) displayNl.
  112. ('Difference: %1' % {diff := atOne - atZero}) displayNl.
  113.  
  114. ('Interpolation: %1' % {part2 := (num - atZero) / diff}) displayNl.
  115.  
  116. " If our interpolation isn't an integer then something went wrong "
  117. (part2 denominator = 1) ifTrue: [
  118.     part2 := part2 numerator.
  119.     '>> Good!  Is an integer!' displayNl.
  120.  
  121.     " DOuble check: "
  122.     verify := block value: part2.
  123.     (verify = num) ifTrue: [
  124.         ('Part 2: %1' % {part2}) displayNl.
  125.     ] ifFalse: [
  126.         'Did not verify!' displayNl.
  127.     ]
  128. ] ifFalse: [
  129.     '>> Problem! Interpolation not an integer!' displayNl.
  130. ]
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement