mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Implement 2024 day 4
This commit is contained in:
69
2024/src/aoc/days/day4.py
Normal file
69
2024/src/aoc/days/day4.py
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import numpy
|
||||||
|
|
||||||
|
from . import SeparateRunner
|
||||||
|
|
||||||
|
|
||||||
|
class DayRunner(SeparateRunner):
|
||||||
|
@classmethod
|
||||||
|
def part1(cls, input: str) -> int:
|
||||||
|
grid = numpy.array(list(map(list, input.strip().split("\n"))))
|
||||||
|
|
||||||
|
found = 0
|
||||||
|
|
||||||
|
directions = [
|
||||||
|
(-1, -1),
|
||||||
|
(-1, 0),
|
||||||
|
(-1, 1),
|
||||||
|
(0, -1),
|
||||||
|
(0, 1),
|
||||||
|
(1, -1),
|
||||||
|
(1, 0),
|
||||||
|
(1, 1),
|
||||||
|
]
|
||||||
|
|
||||||
|
word = "XMAS"
|
||||||
|
|
||||||
|
for y in range(grid.shape[0]):
|
||||||
|
for x in range(grid.shape[1]):
|
||||||
|
if grid[y, x] != "X":
|
||||||
|
continue
|
||||||
|
|
||||||
|
for dx, dy in directions:
|
||||||
|
end_x = x + 3 * dx
|
||||||
|
end_y = y + 3 * dy
|
||||||
|
|
||||||
|
if (
|
||||||
|
end_x < 0
|
||||||
|
or end_x >= grid.shape[1]
|
||||||
|
or end_y < 0
|
||||||
|
or end_y >= grid.shape[0]
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if all(
|
||||||
|
grid[y + i * dy, x + i * dx] == c for i, c in enumerate(word)
|
||||||
|
):
|
||||||
|
found += 1
|
||||||
|
|
||||||
|
return found
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def part2(cls, input: str) -> int:
|
||||||
|
grid = numpy.array(list(map(list, input.strip().split("\n"))))
|
||||||
|
|
||||||
|
found = 0
|
||||||
|
|
||||||
|
magic = ord("M") ^ ord("S")
|
||||||
|
|
||||||
|
for y in range(1, grid.shape[0] - 1):
|
||||||
|
for x in range(1, grid.shape[1] - 1):
|
||||||
|
if grid[y, x] != "A":
|
||||||
|
continue
|
||||||
|
|
||||||
|
first_diag = ord(grid[y - 1, x - 1]) ^ ord(grid[y + 1, x + 1])
|
||||||
|
secnd_diag = ord(grid[y - 1, x + 1]) ^ ord(grid[y + 1, x - 1])
|
||||||
|
|
||||||
|
if first_diag == magic and secnd_diag == magic:
|
||||||
|
found += 1
|
||||||
|
|
||||||
|
return found
|
||||||
0
2024/tests/__init__.py
Normal file
0
2024/tests/__init__.py
Normal file
5
2024/tests/samples/04.1.txt
Normal file
5
2024/tests/samples/04.1.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
..X...
|
||||||
|
.SAMX.
|
||||||
|
.A..A.
|
||||||
|
XMAS.S
|
||||||
|
.X....
|
||||||
10
2024/tests/samples/04.2.txt
Normal file
10
2024/tests/samples/04.2.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
MMMSXXMASM
|
||||||
|
MSAMXMSMSA
|
||||||
|
AMXSXMAAMM
|
||||||
|
MSAMASMSMX
|
||||||
|
XMASAMXAMM
|
||||||
|
XXAMMXXAMA
|
||||||
|
SMSMSASXSS
|
||||||
|
SAXAMASAAA
|
||||||
|
MAMMMXMMMM
|
||||||
|
MXMXAXMASX
|
||||||
26
2024/tests/test_day4.py
Normal file
26
2024/tests/test_day4.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from aoc.days.day4 import DayRunner
|
||||||
|
|
||||||
|
|
||||||
|
def get_data(which: int) -> str:
|
||||||
|
sample = os.path.dirname(__file__) + f"/samples/04.{which}.txt"
|
||||||
|
with open(sample, mode="rt", encoding="utf-8") as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"input,answer",
|
||||||
|
[
|
||||||
|
(get_data(1), 4),
|
||||||
|
(get_data(2), 18),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_sample_part1(input: str, answer: int) -> None:
|
||||||
|
assert DayRunner.part1(input) == answer
|
||||||
|
|
||||||
|
|
||||||
|
def test_sample_part2() -> None:
|
||||||
|
assert DayRunner.part2(get_data(2)) == 9
|
||||||
Reference in New Issue
Block a user