uses prng; fn c2d(b : byte) [ if b >= 'a', b <= 'z' then return b - 'a'; else if b >= '0', b <= '9' then return b - '0' + 26; else abort; ] fn g2n(b : bytes) : int := (36 * 36) * c2d(b[0]) + 36 * c2d(b[1]) + c2d(b[2]); fn n2g(n : int) : bytes [ var result := ""; for i := 0 to 3 do [ var d := n div ipower(36, 2 - i) mod 36; result +<= select(d >= 26, d + 'a', d - 26 + '0'); ] return result; ] option op [ op_nothing; op_and; op_or; op_xor; ] fn simulate(op_list : list(tuple3(op, int, int)), bits a b : int) : int [ var state := fill(sint8, -1, len(op_list)); for i := 0 to bits do state[i] := select(a bt i, 0, 1); for i := 0 to bits do state[bits + i] := select(b bt i, 0, 1); var todo := len(op_list) - bits * 2; while true do [ var did_something := false; for i := bits * 2 to len(op_list) do [ if state[i] >= 0 then continue; if state[op_list[i].v2] < 0 then continue; if state[op_list[i].v3] < 0 then continue; var new_state : sint8; if op_list[i].v1 is op_and then new_state := state[op_list[i].v2] and state[op_list[i].v3]; else if op_list[i].v1 is op_or then new_state := state[op_list[i].v2] or state[op_list[i].v3]; else if op_list[i].v1 is op_xor then new_state := state[op_list[i].v2] xor state[op_list[i].v3]; else abort; state[i] := new_state; todo -= 1; if todo = 0 then goto done; did_something := true; ] if not did_something then return bits + 2; ] done: var result := 0; var bit := 0; for i := len(op_list) - (bits + 1) to len(op_list) do [ if state[i] = 1 then result bts= bit; bit += 1; ] return result; ] fn difference(ops : list(tuple3(op, int, int)), bits a b : int) : int [ var s := simulate(ops, bits, a, b); return popcnt(s xor a + b); ] fn cummulative_difference(ops : list(tuple3(op, int, int)), bits : int, n : int) : int [ implicit var st := prng_init(1); var sum := 0; for i := 0 to n do [ var p1 := prng_get_int(bits); var p2 := prng_get_int(bits); var d := difference~spark(ops, bits, p1, p2); sum += d; ] return sum; ] fn main [ var sections := list_break(list_break_to_lines(read_lazy(h[0])), ""); var bits := len(sections[0]) shr 1; var op_map := array_fill(-1, [ ipower(36, 3) ]); var op_list := empty(tuple3(op, int, int)); var op_names := empty(bytes); for l in sections[0] do [ var g := g2n(l[ .. 3]); op_map[g] := len(op_list); op_list +<= mktuple3(op.op_nothing, -1, -1); op_names +<= l[ .. 3]; ] var ops := array_fill(mktuple3(op.op_nothing, -1, -1), [ ipower(36, 3) ]); for l in sections[1] do [ var b := list_break_whitespace(l); var i1 := g2n(b[0]); var i2 := g2n(b[2]); var ir := g2n(b[4]); var o : op; if b[1] = "AND" then o := op.op_and; else if b[1] = "OR" then o := op.op_or; else if b[1] = "XOR" then o := op.op_xor; else abort; ops[ir] := mktuple3(o, i1, i2); ] while true do [ var did_something := false; for i := 0 to ipower(36, 3) do [ if i div (36 * 36) = 25 then continue; if ops[i].v1 is op_nothing then continue; if op_map[i] >= 0 then continue; if op_map[ops[i].v2] < 0 then continue; if op_map[ops[i].v3] < 0 then continue; op_map[i] := len(op_list); op_list +<= mktuple3(ops[i].v1, op_map[ops[i].v2], op_map[ops[i].v3]); op_names +<= n2g(i); did_something := true; ] if not did_something then break; ] for i := 0 to ipower(36, 3) do [ if i div (36 * 36) <> 25 then continue; if ops[i].v1 is op_nothing then continue; op_map[i] := len(op_list); op_names +<= n2g(i); op_list +<= mktuple3(ops[i].v1, op_map[ops[i].v2], op_map[ops[i].v3]); ] var swapped := fill(false, len(op_list)); var swapped_names := empty(bytes); const diff_n := 100; for p := 0 to 4 do [ var best_i, best_j, best_diff := -1, -1, cummulative_difference(op_list, bits, diff_n); for i := bits * 2 to len(op_list) do [ if swapped[i] then continue; for j := i + 1 to len(op_list) do [ if swapped[j] then continue; var n_list := op_list; n_list[i], n_list[j] := n_list[j], n_list[i]; var c := cummulative_difference(n_list, bits, diff_n); if c < best_diff then [ best_i, best_j, best_diff := i, j, c; ] ] ] if best_i = -1 then abort; swapped[best_i] := true; swapped[best_j] := true; op_list[best_i], op_list[best_j] := op_list[best_j], op_list[best_i]; swapped_names +<= op_names[best_i]; swapped_names +<= op_names[best_j]; ] if cummulative_difference(op_list, bits, diff_n) <> 0 then abort; swapped_names := list_sort(swapped_names); var result := ""; for i := 0 to len(swapped_names) do [ if i > 0 then result +<= ','; result += swapped_names[i]; ] write(h[1], result + nl); ]