$idx) { if (str_starts_with($rule_name, "departure")) $accum *= $my_ticket[$idx]; } return $accum; } function get_valid_rules(array $rules, array $my_ticket, array $nearby_tickets, array $invalid_tickets): array { $possible_valid_rules = []; foreach ($rules as $rule) { for ($i = 0; $i < count($my_ticket); $i++) { $rule_valid = true; foreach ($nearby_tickets as $idx => $ticket) { if (in_array($idx, $invalid_tickets) == false) { $field = $ticket[$i]; if ((($field >= $rule[1][0] && $field <= $rule[1][1]) || ($field >= $rule[2][0] && $field <= $rule[2][1])) == false) { $rule_valid = false; break; } } if ($rule_valid == false) break; } if ($rule_valid) { $possible_valid_rules[$i][] = $rule[0]; } } } return get_valid_rules_from_possibilities($possible_valid_rules); } function get_valid_rules_from_possibilities(array $possible_valid_rules): array { $valid_rules = []; uasort($possible_valid_rules, fn ($x, $y) => count($x) > count($y) ? 1 : (count($x) < count($y) ? -1 : 0)); for ($idx = 0; $idx < count($possible_valid_rules); $idx++) { $elem = $possible_valid_rules[array_keys($possible_valid_rules)[$idx]]; if (count($elem) == 1) { $rule_name = $elem[array_keys($elem)[0]]; $valid_rules[$rule_name] = $idx; $possible_valid_rules = array_map(fn ($arr) => array_diff($arr, $elem), $possible_valid_rules); } } return $valid_rules; } function get_invalid_tickets(array $nearby_tickets, array $rules): array { $invalid_tickets = []; foreach ($nearby_tickets as $idx => $ticket) { $ticket_valid = true; foreach ($ticket as $field) { if (field_is_valid($rules, $field) == false) $ticket_valid = false; } if ($ticket_valid == false) $invalid_tickets[] = $idx; } return $invalid_tickets; } function field_is_valid(array $rules, int $field): bool { $valid = false; foreach ($rules as $rule) { if (($field >= $rule[1][0] && $field <= $rule[1][1]) || ($field >= $rule[2][0] && $field <= $rule[2][1])) { $valid = true; break; } } return $valid; } function parse_lines(array $lines): array { $section = 0; $rules = []; $my_ticket = []; $nearby_tickets = []; foreach ($lines as $line) { if ($line === '') { $section += 1; } else { if ($line != 'your ticket:' && $line != 'nearby tickets:') { switch ($section) { case 0: $rules[] = parse_rule($line); break; case 1: $my_ticket = array_map(fn ($x) => (int)$x, explode(',', $line)); break; case 2: $nearby_tickets[] = array_map(fn ($x) => (int)$x, explode(',', $line)); break; } } } } return [$rules, $my_ticket, $nearby_tickets]; } function parse_rule(string $line): array { [$name, $values] = array_map('trim', explode(':', $line)); [$min_range, $max_range] = array_map('trim', explode(' or ', $values)); [$min_min, $min_max] = array_map(fn ($x) => (int)$x, explode('-', $min_range)); [$max_min, $max_max] = array_map(fn ($x) => (int)$x, explode('-', $max_range)); return [$name, [$min_min, $min_max], [$max_min, $max_max]]; }