#!/usr/bin/env luajit require("utils") require("set") local entries = {} for line in io.lines(arg[3]) do local entry = split(line, " ") table.remove(entry, 11) table.insert(entries, entry) end function uniques(segment) if #segment == 2 then return "cf" end if #segment == 3 then return "acf" end if #segment == 4 then return "bcdf" end end function reduceoptions(options, segment) local included = uniques(segment) if included then for part in chars("abcdgef") do if string.find(segment, part) then options[part]:keeponly(chars(included)) else options[part]:removeall(chars(included)) end end end end function printoptions(options) for from, s in pairs(options) do io.write(from..":") for to in s:iter() do io.write(to) end io.write(" ") end io.write("\n") end function asdigit(segment, sel) local lit = set() for c in chars(segment) do lit:add(sel[c]) end if lit:equal(set(chars("acbefg"))) then return 0 end if lit:equal(set(chars("cf"))) then return 1 end if lit:equal(set(chars("acdeg"))) then return 2 end if lit:equal(set(chars("acdfg"))) then return 3 end if lit:equal(set(chars("bcdf"))) then return 4 end if lit:equal(set(chars("abdfg"))) then return 5 end if lit:equal(set(chars("abdefg"))) then return 6 end if lit:equal(set(chars("acf"))) then return 7 end if lit:equal(set(chars("abcdefg"))) then return 8 end if lit:equal(set(chars("abcdfg"))) then return 9 end end function backtrack(options, displays, display, segment, acc, sel, rev) if display > #displays then return set({acc}) elseif segment <= #displays[display] then local pickfor = char(displays[display], segment) local picked = sel[pickfor] if picked then return backtrack(options, displays, display, segment+1, acc, sel, rev) else local accs = set() for picked in options[char(displays[display], segment)]:iter() do sel[pickfor] = picked if not rev:has(picked) then rev:add(picked) accs:addall(backtrack(options, displays, display, segment+1, acc, sel, rev):iter()) rev:remove(picked) end end sel[pickfor] = nil return accs end else local digit = asdigit(displays[display], sel) if digit then return backtrack(options, displays, display + 1, 1, (acc * 10 + digit) % 10000, sel, rev) else return set() end end end function outputvalue(entry) local options = { a = set(chars('abcdefg')), b = set(chars('abcdefg')), c = set(chars('abcdefg')), d = set(chars('abcdefg')), e = set(chars('abcdefg')), f = set(chars('abcdefg')), g = set(chars('abcdefg')) } for k, v in pairs(entry) do reduceoptions(options, v) end local solutions = backtrack(options, entry, 1, 1, 0, {}, set()) if solutions.size == 1 then return solutions:iter()() else error("meh") end end foreach(entries, outputvalue) print(sum(entries))