import { parseInput, Workflow } from "./parser.ts";
import { partition, MaterialRange } from "./range.ts";

const input = await Deno.readTextFile("input.txt");
const parsed = parseInput(input);


class Executor {
    workflowTable: Map<string, Workflow>
    constructor(rules: Workflow[]) {
        this.workflowTable = new Map();
        for (const rule of rules) {
            this.workflowTable.set(rule.name, rule);
        }
    }

    caculRange(start: string, material: MaterialRange) {
        if (start === "A") {
            return [material];
        }
        if (start === "R") {
            return [];
        }
        const gotoRules = this.workflowTable.get(start)!;

        const ret = [] as MaterialRange[];
        let dest = gotoRules.always;
        for (const rule of gotoRules.rules) {
            const cond = partition(rule.condition, material)
            if (cond === null) {
                // skip
                continue;
            }
            else if (cond instanceof Array) {
                const [falseRange, trueRange] = cond;
                ret.push(...this.caculRange(rule.dest, trueRange));
                material = falseRange;
            }
            else {
                dest = rule.dest;
                break;
            }
        }
        ret.push(...this.caculRange(dest, material));
        return ret;
    }
}

const executor = new Executor(parsed.rules);
const ranges = executor.caculRange("in", {
    x: [1, 4000],
    m: [1, 4000], 
    a: [1, 4000], 
    s: [1, 4000]
});
const countRange = (x: [number, number])=> x[1] - x[0] + 1;
console.log(ranges.map(r=> {
    return countRange(r.x) * countRange(r.m) * countRange(r.a) * countRange(r.s);
}).reduce((a, b) => a + b, 0))