Published
Edited
Dec 17, 2020
Insert cell
Insert cell
Insert cell
Insert cell
function parseInput(input) {
let [rules, tickets] = input.split("\n\nnearby tickets:\n");
let yourTicket;
[rules, yourTicket] = rules.split("\n\nyour ticket:\n");

rules = rules.split('\n').map(rule => {
let [name, ranges] = rule.split(": ");
ranges = ranges.split(" or ").map(range => range.split("-").map(nr => +nr));
return { name, ranges };
});

yourTicket = yourTicket.split(",").map(v => +v);
tickets = tickets.split("\n").map(ticket => ticket.split(",").map(v => +v));
return { rules, yourTicket, tickets };
}
Insert cell
testInput = parseInput(testInput_text)
Insert cell
input = parseInput(input_text)
Insert cell
function q1(input) {
const invalid_vals = [];
const valid_tickets = [];
const { rules, tickets } = input;
for (const ticket of tickets) {
let valid_ticket = true;
for (const val of ticket) {
let valid_rule = false;
for (const rule of rules) {
let valid_range = false;
for (const range of rule.ranges) {
if (val >= range[0] && val <= range[1]) {
valid_range = true;
break;
}
}
if (valid_range) {
valid_rule = true;
break;
}
}
if (!valid_rule) {
invalid_vals.push(val);
valid_ticket = false;
}
}
if (valid_ticket) valid_tickets.push(ticket);
}
let sum = 0;
for (const val of invalid_vals) sum += val;
return { valid_tickets, invalid_vals, sum };
}
Insert cell
testAnswer1 = q1(testInput)
Insert cell
answer1 = q1(input)
Insert cell
Insert cell
q2(testInput2)
Insert cell
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 };
});

// to clarify which loop is which
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++) {
// put rule with fewest possible columns at the end
sieve.sort((a, b) => b.possibleColumns.size - a.possibleColumns.size);

// let's hope that there's always at least one rule with
// only one possible column after every loop
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 };
}
Insert cell
q2(input2)
Insert cell
Insert cell
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more