Get closer to finishing day2 part 2

This commit is contained in:
Timothy Warren 2024-12-20 16:13:34 -05:00
parent 25b46bc115
commit da8cfc2f33
2 changed files with 142 additions and 36 deletions

View File

@ -38,3 +38,22 @@ So, in this example, `2` reports are **safe**.
Analyze the unusual data from the engineers. **How many reports are safe?** Analyze the unusual data from the engineers. **How many reports are safe?**
## Part 2 ## Part 2
The engineers are surprised by the low number of safe reports until they realize they forgot to tell you about the Problem Dampener.
The Problem Dampener is a reactor-mounted module that lets the reactor safety systems **tolerate a single bad level** in what would otherwise be a safe report. It's like the bad level never happened!
Now, the same rules apply as before, except if removing a single level from an unsafe report would make it safe, the report instead counts as safe.
More of the above example's reports are now safe:
- `7 6 4 2 1`: **Safe** without removing any level.
- `1 2 7 8 9`: **Unsafe** regardless of which level is removed.
- `9 7 6 2 1`: **Unsafe** regardless of which level is removed.
- `1 3 2 4 5`: **Safe** by removing the second level, `3`.
- `8 6 4 4 1`: **Safe** by removing the third level, `4`.
- `1 3 6 7 9`: **Safe** without removing any level.
Thanks to the Problem Dampener, `4` reports are actually **safe**!
Update your analysis by handling situations where the Problem Dampener can remove a single level from unsafe reports. **How many reports are now safe?**

View File

@ -1,8 +1,8 @@
<?php declare(strict_types=1); <?php declare(strict_types=1);
function parse_reports(): array function parse_reports(string $file = './input.txt'): array
{ {
$raw = file_get_contents('./input.txt'); $raw = file_get_contents($file);
$lines = explode("\n", trim($raw)); $lines = explode("\n", trim($raw));
return array_map(fn (string $line) => explode(' ', $line), $lines); return array_map(fn (string $line) => explode(' ', $line), $lines);
@ -10,45 +10,132 @@ function parse_reports(): array
class Report { class Report {
public function __construct( public function __construct(
public bool $allIncreasing, public array $rawLevels,
public bool $allDecreasing, public array $safeLevels = [],
public bool $safeDifference, private bool $allIncreasing = true,
) {} private bool $allDecreasing = true,
private bool $safeDifference = true,
) {
$this->rawLevels = array_map(fn ($item) => (int)$item, $this->rawLevels);
$this->calculateLevelSafety();
}
public function isSafe(): bool public function isSafe(): bool
{ {
return $this->safeDifference && ($this->allIncreasing || $this->allDecreasing); return $this->safeDifference && ($this->allIncreasing xor $this->allDecreasing);
} }
}
function get_report_safety (array $report): Report { public function isSafeWithDampener(): bool
{
if ($this->isSafe())
{
return true;
}
$unsafe = $this->getUnsafeKeys();
$unsafeCount = count($unsafe);
foreach ($unsafe as $key)
{
$front = array_slice($this->rawLevels, 0, $key);
$back = array_slice($this->rawLevels, $key + 1);
$newRawLevels = array_merge($front, $back);
$newReport = new Report($newRawLevels);
$isNowSafe = $newReport->isSafe();
if ($isNowSafe)
{
// echo json_encode([
// 'old' => $this,
// 'new' => $newReport
// ], JSON_PRETTY_PRINT);
return true;
}
}
return false;
}
private function getUnsafeKeys(): array
{
$out = [];
foreach ($this->safeLevels as $key => $value)
{
if (!$value)
{
$out[] = $key;
}
}
return $out;
}
private function calculateLevelSafety (): void
{
$allIncreasing = true; $allIncreasing = true;
$allDecreasing = true; $allDecreasing = true;
$safeDifference = true; $safeDifference = true;
$safeLevels = [];
$safeDiff = function ($curr, $prev): bool { $safeDiff = function ($curr, $prev): bool {
$diff = abs((int)$curr - (int)$prev); $diff = abs($curr - $prev);
return $diff > 0 && $diff <= 3; return $diff > 0 && $diff < 4;
}; };
$increasing = fn ($curr, $prev): bool => (int)$curr > (int)$prev; $increasing = fn ($curr, $prev): bool => $curr > $prev;
$decreasing = fn ($curr, $prev): bool => (int)$curr < (int)$prev; $decreasing = fn ($curr, $prev): bool => $curr < $prev;
for ($i = 1;$i < count($report); $i++) for ($i = 1; $i < count($this->rawLevels); $i++)
{ {
$curr = $report[$i]; $curr = $this->rawLevels[$i];
$prev = $report[$i - 1]; $prev = $this->rawLevels[$i - 1];
$allIncreasing = $allIncreasing && $increasing($curr, $prev); $isIncreasing = $increasing($curr, $prev);
$allDecreasing = $allDecreasing && $decreasing($curr, $prev); $isDecreasing = $decreasing($curr, $prev);
$safeDifference = $safeDifference && $safeDiff($curr, $prev); $isSafeDiff = $safeDiff($curr, $prev);
$this->allIncreasing = $this->allIncreasing && $isIncreasing;
$this->allDecreasing = $this->allDecreasing && $isDecreasing;
$this->safeDifference = $this->safeDifference && $isSafeDiff;
$safeLevel = $isSafeDiff && (
$this->allIncreasing xor
$this->allDecreasing
);
$this->safeLevels[] = $safeLevel;
}
} }
return new Report($allIncreasing, $allDecreasing, $safeDifference);
} }
$reports = parse_reports(); // ----------------------------------------------------------------------------
$reports = array_map('get_report_safety', $reports);
$safeReports = count(array_filter($reports, fn (Report $r) => $r->isSafe()));
echo "Number of safe reports: $safeReports\n"; $testReports = array_map(fn (array $line) => new Report($line), parse_reports('./test_input.txt'));
$testSafeReports = array_filter($testReports, fn (Report $r) => $r->isSafe());
$testSafeReportsMap = array_map(fn (Report $r) => $r->isSafe(), $testReports);
assert($testSafeReportsMap == [true, false, false, false, false, true]);
assert(count($testSafeReports)==2, 'First example has 2 safe reports');
$testSafeReportsPart2 = array_filter($testReports, fn (Report $r) => $r->isSafeWithDampener());
$testSafeReportsPart2Map = array_map(fn (Report $r) => $r->isSafeWithDampener(), $testReports);
assert($testSafeReportsPart2Map == [true, false, false, true, true, true]);
assert(count($testSafeReportsPart2)==4);
// ----------------------------------------------------------------------------
$reports = array_map(fn (array $line) => new Report($line), parse_reports());
$safeReports = array_filter($reports, fn (Report $r) => $r->isSafe());
$simpleSafeReports = count($safeReports);
$allSafeReports = array_filter($reports, fn (Report $r) => $r->isSafeWithDampener());
$dampenedSafeReports = count($allSafeReports);
$maybeValid = $dampenedSafeReports > 550
&& $dampenedSafeReports != 557
&& $dampenedSafeReports < 572;
echo "(Part 1) Number of safe reports: $simpleSafeReports\n";
echo "(Part 2) Number of safe reports with dampener: $dampenedSafeReports\n";
echo "Part two may be valid: " . $maybeValid . "\n";