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