Advent of Code solutions
at main 150 lines 3.9 kB view raw
1module io at "trilogy:io" use readlines, println 2module str at "trilogy:str" use chomp, split, fmt 3module array at "trilogy:array" use is_empty, push, all, fold 4module num at "trilogy:num" use lcm 5module iter at "trilogy:iter" use range 6module tuple at "trilogy:tuple" use mapsnd 7module record at "trilogy:record" use contains 8 9module broadcaster destinations { 10 proc add_input!(_) {} 11 12 proc init!() { 13 for dest in destinations { 14 yield 'init(dest) 15 } 16 } 17 18 proc signal!(_) { 19 for dest in destinations { 20 yield 'low(dest) 21 } 22 } 23 24 export add_input, init, signal 25} 26 27module flipflop destinations { 28 slot state = {| 'on => false |} 29 30 proc add_input!(_) {} 31 32 proc init!() { 33 for dest in destinations { 34 yield 'init(dest) 35 } 36 } 37 38 proc signal!(signal) { 39 match signal 40 case 'low(_) { 41 if state.'on { 42 state.'on = false 43 for dest in destinations { 44 yield 'low(dest) 45 } 46 } else { 47 state.'on = true 48 for dest in destinations { 49 yield 'high(dest) 50 } 51 } 52 } 53 case 'high {} 54 } 55 56 export add_input, init, signal 57} 58 59module conjunction destinations { 60 slot state = {||} 61 62 proc add_input!(input) { 63 state.input = 'low 64 } 65 66 proc init!() { 67 for dest in destinations { 68 yield 'init(dest) 69 } 70 } 71 72 proc signal!(signal) { 73 match signal 74 case 'low(input) { 75 state.input = 'low 76 } 77 case 'high(input) { 78 state.input = 'high 79 } 80 for _:value in state { 81 if value == 'low { 82 for dest in destinations { 83 yield 'high(dest) 84 } 85 return 86 } 87 } 88 for dest in destinations { 89 yield 'low(dest) 90 } 91 } 92 93 export add_input, init, signal 94} 95 96slot important = ["mp", "qt", "qb", "ng"] 97 98func parse_node srcdest = let [name, dests] = split " -> " srcdest, name : split ", " dests 99 100func parse "%" <> srcdest = parse_node srcdest |> (fn n:x.n:flipflop x) 101func parse "&" <> srcdest = parse_node srcdest |> (fn n:x.n:conjunction x) 102func parse "broadcaster -> " <> dests = "broadcaster" : broadcaster (split ", " dests) 103 104proc main!() { 105 let nodes = {| |} 106 for line in readlines!() { 107 let name:node = parse <| chomp line 108 nodes.name = node 109 } 110 111 for name:node in nodes { 112 with { node::init!() } 113 when 'init(dest) resume (with (nodes.dest)::add_input!(name) else cancel unit) 114 else yield 115 } 116 117 let keys = {| |} 118 119 let mut presses = 0 120 while !(all (fn x. contains x keys) important) { 121 presses += 1 122 let mut queue = ["button":'low("broadcaster")] 123 while !(is_empty queue) { 124 let [src:msg, ..rest] = queue 125 let 'low(dest) or 'high(dest) = msg 126 queue = rest 127 with { 128 match msg 129 case 'low(_) { 130 (nodes.dest)::signal!('low(src)) 131 } 132 case 'high(_) { 133 if is ^src in important { 134 keys.src = presses 135 } 136 (nodes.dest)::signal!('high(src)) 137 } 138 } when 'low(tgt) invert { 139 push!(queue, dest:'low(tgt)) 140 cancel resume unit 141 } when 'high(tgt) invert { 142 push!(queue, dest:'high(tgt)) 143 cancel resume unit 144 } when 'MIA cancel unit 145 else yield 146 } 147 } 148 149 println!(fold lcm 1 [val for _:val in keys]) 150}