You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
74 lines
2.1 KiB
JavaScript
74 lines
2.1 KiB
JavaScript
4 years ago
|
const fs = require("fs");
|
||
|
|
||
|
let [rules, messages] = fs
|
||
|
.readFileSync("input", "utf-8")
|
||
|
.trim()
|
||
|
.split("\n\n")
|
||
|
.map((part) => part.split("\n"));
|
||
|
|
||
|
rules = Object.fromEntries(rules.map((line) => line.split(": ")));
|
||
|
|
||
|
// unecessary, but might reveal an overlooked loop
|
||
|
rules["8"] = "42 | 42 8";
|
||
|
rules["11"] = "42 31 | 42 11 31";
|
||
|
|
||
|
// console.log(rules);
|
||
|
// console.log(messages);
|
||
|
|
||
|
function getRegex(idx, visited = []) {
|
||
|
const rule = rules[idx];
|
||
|
if (rule.startsWith('"')) {
|
||
|
return rule.slice(1, rule.length - 1);
|
||
|
}
|
||
|
let regex = "";
|
||
|
let multiple = false;
|
||
|
for (const symbol of rule.split(" ")) {
|
||
|
if (symbol === "|") {
|
||
|
regex = "(" + regex + "|";
|
||
|
multiple = true;
|
||
|
} else {
|
||
|
regex = regex + getRegex(parseInt(symbol), visited.concat(idx));
|
||
|
}
|
||
|
}
|
||
|
regex = multiple ? regex + ")" : regex;
|
||
|
rules[idx] = '"' + regex + '"';
|
||
|
return regex;
|
||
|
}
|
||
|
|
||
|
// Rule 0 is "8 11"
|
||
|
// These rules are the only looping rules through self referencing
|
||
|
// rule 8: 42 | 42 8
|
||
|
// expects rule 42 one or more times
|
||
|
// rule 11: 42 31 | 42 11 31
|
||
|
// recursively expects R42 R11 R31
|
||
|
// translated:
|
||
|
// expects rule 42 one or more times followed by 31 by the same quantity
|
||
|
// combined:
|
||
|
// rule 0: 8 11
|
||
|
// start of string matches 42 (one or more)
|
||
|
// end of string matches 31 (one or more)
|
||
|
// the quantity of R42 matches has to be more than the quantity of R31
|
||
|
|
||
|
const rule42 = getRegex(42);
|
||
|
const rule31 = getRegex(31);
|
||
|
const possibleEndings = [];
|
||
|
|
||
|
// 10 is a guessed maximum repetition based message length
|
||
|
// if this value is too high the regex wont compile
|
||
|
// for larger messages a recursive approach is necessary
|
||
|
for (let reps = 1; reps <= 10; reps++) {
|
||
|
possibleEndings.push(`((${rule42.repeat(reps)})(${rule31.repeat(reps)}))`);
|
||
|
}
|
||
|
const patternRaw = `^(${rule42})+(${possibleEndings.join("|")})$`;
|
||
|
// console.log("Pattern:", patternRaw);
|
||
|
console.log("Compiling RegExp...");
|
||
|
const pattern = new RegExp(patternRaw);
|
||
|
console.log("done.");
|
||
|
|
||
|
console.log("Checking messages...");
|
||
|
let sum = 0;
|
||
|
for (let message of messages) {
|
||
|
if (pattern.test(message)) sum++;
|
||
|
}
|
||
|
console.log(sum);
|