function get_regex($num, $rules) {
if ($rules[$num][0] == "\"") {
$regex[$num] = str_replace("\"", "", $rules[$num]);
return $regex[$num];
}
$rule = str_replace(" ", "", preg_replace_callback("/[0-9]+/", function ($m) use ($num, $rules) {
if ($m[0] == $num) return "@"; // Self
return get_regex($m[0], $rules);
}, $rules[$num]));
// If contains self...
if (strpos($rule, "@") !== false) {
// Get rid of the non-recursive part, as it is redundant
$rule = substr($rule, strlen($rule) / 2);
// Update using uniquely named recursive backreference
$name = "br".uniqid();
$rule = "(?<".$name.">" . str_replace("@", "(?&".$name.")?", $rule) . ")";
}
return "(" . $rule . ")";
}
function solve($messages, $rules) {
$regex = get_regex(0, $rules);
return $messages
->filter(fn ($m) => preg_match("/^".$regex."$/", $m))
->count();
}
// ==================================================
// > SOLUTION
// ==================================================
// Parsing
[$rules, $messages] = $input->split("\n\n");
$rules = $rules->lines->map(fn ($l) => $l->split(": "))->mapAssoc(fn ($i, $r) => [(string) $r[0] => (string) $r[1]]);
$messages = set(explode("\n", (string) $messages));
// Part 1
$solution_1 = solve($messages, $rules);
// Part 2
$rules[8] = "42 | 42 8";
$rules[11] = "42 31 | 42 11 31";
$solution_2 = solve($messages, $rules);