const array_size := ipower(27, 2); fn array_index(s : bytes) : int [ if s = "broadcaster" then return 0; var idx := 0; for q in s do idx := idx * 27 + (q - 'a' + 1); return idx; ] fn gcd(u w : int) : int [ while w <> 0 do u, w := w, u mod w; return u; ] fn lcm(u w : int) := u div gcd(u, w) * w; option typ [ nothing; bcst; ff : bool; conj : list(tuple2(int, bool)); ] record module [ t : typ; result : list(int); ] fn main [ var lines := list_break_to_lines(read_lazy(h[0])); var modules := array_fill(module.[ t : typ.nothing, result : empty(int) ], [array_size]); var kcidx := -1; var rxidx := array_index("rx"); for line in lines do [ line := list_replace_substring(line, " ", ""); line := list_replace_substring(line, "->", "-"); var l := list_break(line, '-'); var rl := list_break(l[1], ','); var result := map(rl, array_index); var nm := l[0]; var t : typ; if nm[0] = '%' then [ t := typ.ff.(false); nm := nm[1 .. ]; ] else if nm[0] = '&' then [ t := typ.conj.(empty(tuple2(int, bool))); nm := nm[1 .. ]; ] else [ t := typ.bcst; ] if len(result) = 1, result[0] = rxidx then kcidx := array_index(nm); var mod := module.[ t : t, result : result ]; modules[array_index(nm)] := mod; ] var num_clusters := 0; for i := 0 to array_size do [ for j in modules[i].result do [ if modules[j].t is conj then [ modules[j].t.conj +<= mktuple2(i, false); if j = kcidx then num_clusters += 1; ] ] ] var pulse_period := fill(-1, num_clusters); var i := 0; while true do [ i += 1; var pulse_queue := [ mktuple3(false, 0, array_index("broadcaster")) ]; while len_greater_than(pulse_queue, 0) do [ var p := pulse_queue[0]; pulse_queue := pulse_queue[1 .. ]; var midx := p.v3; if midx = rxidx and not p.v1 then goto have_rx; var m := modules[p.v3]; var target_pulse : bool; if m.t is bcst then [ target_pulse := p.v1; goto send; ] if m.t is ff then [ if p.v1 then continue; modules[midx].t.ff := not modules[midx].t.ff; target_pulse := modules[midx].t.ff; goto send; ] if m.t is conj then [ var jj : int; for j := 0 to len(m.t.conj) do [ if m.t.conj[j].v1 = p.v2 then [ modules[midx].t.conj[j].v2 := p.v1; jj := j; goto found; ] ] abort; found: if midx = kcidx, p.v1 then [ if pulse_period[jj] = -1 then pulse_period[jj] := i; if list_search(pulse_period, -1) = -1 then [ i := list_fold(1, pulse_period, lcm); goto have_rx; ] ] target_pulse := false; for j := 0 to len(m.t.conj) do [ if not modules[midx].t.conj[j].v2 then [ target_pulse := true; break; ] ] goto send; ] continue; send: for j := 0 to len(m.result) do [ pulse_queue +<= mktuple3(target_pulse, midx, m.result[j]); ] ] ] have_rx: write(h[1], ntos(i) + nl); ]