Advertisement
musifter

AoC day 19, Smalltalk

Dec 19th, 2020
1,784
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: Parser [
  4.     | rule_table patt_table |
  5.  
  6.     Parser class >> withRules: rules [
  7.         ^(super new) init: rules
  8.     ]
  9.  
  10.     init: str [
  11.         | section break num rules |
  12.         rule_table := LookupTable new.
  13.         patt_table := LookupTable new.
  14.  
  15.         (str tokenize: '\n') do: [ :r |
  16.             break := r subStrings: ':'.
  17.             num   := break first.
  18.  
  19.             rules := ((break second) subStrings: ' ') collect: [ :tok |
  20.                          ((tok at: 1) = $") ifTrue: [
  21.                              patt_table at: num put: (tok at: 2) asString.
  22.                              nil
  23.                          ] ifFalse: [
  24.                              tok
  25.                          ]
  26.                      ].
  27.  
  28.             rule_table at: num put: rules.
  29.         ].
  30.  
  31.         " Build pattern table: "
  32.         self recurse_rules: '0'.
  33.     ]
  34.  
  35.     recurse_rules: rule_num [
  36.         | regex |
  37.         patt_table at: rule_num ifAbsent: [
  38.             regex := (rule_table at: rule_num) gather: [ :tok |
  39.                 (tok = '|') ifTrue: [ '|' ] ifFalse: [ self recurse_rules: tok ].
  40.             ].
  41.  
  42.             regex := ('(', regex, ')').
  43.             patt_table at: rule_num put: regex.
  44.         ].
  45.         ^patt_table at: rule_num
  46.     ]
  47.  
  48.     getPattern: num [
  49.         ^patt_table at: num asString.
  50.     ]
  51. ]
  52.  
  53. "
  54. |  Mainline
  55. "
  56. section := stdin contents tokenize: '\n\n'.
  57.  
  58. " First section: rules: "
  59. parser := Parser withRules: (section first).
  60.  
  61. " Second section signals: "
  62. signals := (section second) tokenize: '\n'.
  63.  
  64. "
  65. |  Unfortunately, gst cannot handle Regex past a particular length.  Patterns 0 and 11 are
  66. |  too long.  So we'll make do with just 42 and 31.
  67. |
  68. |  Part 1:  0:  8 11, 8: 42,        11: 42 31               =>  0: 42 42 31
  69. |  Part 2:  0:  8 11, 8: 42 | 42 8, 11: 42 31 | 42 11 32    =>  0: 42{n} 31{<n}
  70. |
  71. |  XXX: Not robust... could take a long match of 42s, when a shorter one is what matched 31s.
  72. |
  73. "
  74. part2 := 0.
  75.  
  76. (2 to: 10) do: [ :i |
  77.    patt42_re := ('^', (parser getPattern: 42), '{', i asString, '}') asRegex.
  78.    patt31_re := ('^', (parser getPattern: 31), '{1,', (i - 1) asString, '}$') asRegex.
  79.  
  80.    mats := signals select: [ :sig |
  81.                (sig =~ patt42_re) ifMatched: [ :res |
  82.                    | rest |
  83.                    rest := sig readStream copyFrom: (res matchInterval last) to: (sig size - 1).
  84.                    (rest =~ patt31_re) matched.
  85.                 ] ifNotMatched: [
  86.                     false
  87.                 ]
  88.            ].
  89.  
  90.    part2 := part2 + (mats size).
  91.    (i = 2) ifTrue: [ stdout nextPutAll: ('Part 1: ', part2 asString); nl; flush ]
  92. ].
  93.  
  94. stdout nextPutAll: ('Part 2: ', part2 asString); nl.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement