function q2(input) {
const t0 = performance.now();
const { rules, yourTicket, tickets } = input;
let sieve = rules.map(rule => {
const possibleColumns = new Set();
return { name: rule.name, possibleColumns };
});
const columns = rules.length;
for (let i = 0; i < rules.length; i++) {
const { possibleColumns } = sieve[i];
const rule = rules[i];
for (let j = 0; j < columns; j++) {
let always_valid = true;
for (const ticket of tickets) {
const col_val = ticket[j];
let valid = false;
for (const range of rule.ranges) {
valid = valid || (col_val >= range[0] && col_val <= range[1]);
}
always_valid = always_valid && valid;
if (!always_valid) break;
}
if (always_valid) possibleColumns.add(j);
}
}
let identified = [];
for (let i = 0; i < rules.length; i++) {
sieve.sort((a, b) => b.possibleColumns.size - a.possibleColumns.size);
const lastRule = sieve.pop();
if (lastRule.possibleColumns.size === 1) {
identified.push(lastRule);
for (const column of lastRule.possibleColumns.values()) {
for (const rule of sieve) {
rule.possibleColumns.delete(column);
}
}
} else {
return "gotta think of a different strategy, chief";
}
}
sieve = identified;
for (const { name, possibleColumns } of sieve) {
for (const column of possibleColumns.values()) {
for (const rule of rules) {
if (rule.name === name) {
rule.column = column;
break;
}
}
}
}
let answer = 1;
for (const rule of rules) {
if (!rule.name.startsWith("departure")) continue;
answer *= yourTicket[rule.column];
}
return { rules, yourTicket, sieve, answer, time: performance.now() - t0 };
}