Skip to content

Instantly share code, notes, and snippets.

@maartenpaauw
Created December 4, 2023 18:38
Show Gist options
  • Save maartenpaauw/51cc23c429488bf4145defa80f2ee64f to your computer and use it in GitHub Desktop.
Save maartenpaauw/51cc23c429488bf4145defa80f2ee64f to your computer and use it in GitHub Desktop.
Advent of Code 2023 - Day 4
<?php
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
final class ScratchCard
{
/**
* @var Collection<array-key, int>
*/
private Collection $matchingNumbers;
/**
* @var Collection<array-key, int>
*/
private Collection $copies;
/**
* @param array<array-key, int> $numbers
* @param array<array-key, int> $winningNumbers
*/
public function __construct(
private readonly int $number,
private readonly array $numbers,
private readonly array $winningNumbers,
public int $instances = 1,
)
{
$this->initializeMatchingNumbers();
$this->initializeCopies();
}
private function initializeMatchingNumbers(): void
{
$this->matchingNumbers = Collection::make($this->numbers)->intersect($this->winningNumbers);
}
private function initializeCopies(): void
{
if ($this->matchingNumbers->isEmpty()) {
$this->copies = Collection::make();
return;
}
$this->copies = Collection::range(
$this->number + 1,
$this->number + $this->matchingNumbers->count(),
);
}
public function number(): int
{
return $this->number;
}
public function points(): int
{
return $this->matchingNumbers->reduce(static fn (int $score): int => $score === 0 ? 1 : $score * 2, 0);
}
/**
* @param Collection<int, ScratchCard> $scratchCards
*/
public function copy(Collection $scratchCards): void
{
$this->copies->each(function (int $number) use ($scratchCards): void {
$copy = $scratchCards->get($number);
if ($copy) {
$copy->copied();
$copy->copy($scratchCards);
}
});
}
public function copied(): void
{
$this->instances += 1;
}
public static function fromString(string $notation): self
{
preg_match_all(
'/^(Card\s*(?<card>\d+):\s*?)(?<winning>(\d\s*?)+)(\s*\|\s*)(?<numbers>(\s*?\d+\s*?)+)/',
$notation,
$matches,
);
preg_match_all('/\d+/', $matches['winning'][0], $winningNumbers);
preg_match_all('/\d+/', $matches['numbers'][0], $numbers);
$winningNumbers = array_map('intval', $winningNumbers[0]);
$numbers = array_map('intval', $numbers[0]);
return new self(
number: intval($matches['card'][0]),
numbers: $numbers,
winningNumbers: $winningNumbers,
);
}
}
$input = "Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53
Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1
Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83
Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11";
$scratchCards = Str::of($input)
->explode("\n")
->map(static fn (string $notation): ScratchCard => ScratchCard::fromString($notation))
->keyBy(static fn (ScratchCard $scratchCard): int => $scratchCard->number());
$part1 = $scratchCards
->map(static fn (ScratchCard $scratchCard): int => $scratchCard->points())
->sum();
$part2 = $scratchCards
->each(static fn (ScratchCard $scratchCard) => $scratchCard->copy($scratchCards))
->map(static fn (ScratchCard $scratchCard) => $scratchCard->instances)
->sum();
$result = [$part1, $part2];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment