aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--2025/03/.gitignore1
-rw-r--r--2025/03/Makefile1
-rw-r--r--2025/03/puzzles.c48
-rw-r--r--2025/04/.gitignore1
-rw-r--r--2025/04/Makefile1
-rw-r--r--2025/04/puzzles.py95
-rwxr-xr-x2025/05/puzzle-1.awk19
-rwxr-xr-x2025/05/puzzle-2.awk31
-rwxr-xr-x2025/06/puzzle-1.awk20
-rwxr-xr-x2025/06/puzzle-2.sh27
-rwxr-xr-x2025/07/puzzle-1.py23
-rwxr-xr-x2025/07/puzzle-2.py31
12 files changed, 298 insertions, 0 deletions
diff --git a/2025/03/.gitignore b/2025/03/.gitignore
new file mode 100644
index 0000000..60d075d
--- /dev/null
+++ b/2025/03/.gitignore
@@ -0,0 +1 @@
+puzzle-[12]
diff --git a/2025/03/Makefile b/2025/03/Makefile
new file mode 100644
index 0000000..de3f940
--- /dev/null
+++ b/2025/03/Makefile
@@ -0,0 +1 @@
+include ../../Makefiles/c.mk
diff --git a/2025/03/puzzles.c b/2025/03/puzzles.c
new file mode 100644
index 0000000..9bd68ee
--- /dev/null
+++ b/2025/03/puzzles.c
@@ -0,0 +1,48 @@
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef PART1
+ #define DIGITS ((size_t)(2))
+#else
+ #define DIGITS ((size_t)(12))
+#endif
+
+int
+main(void)
+{
+ FILE *fp = fopen("input", "r");
+ if (fp == nullptr)
+ err(EXIT_FAILURE, "failed to open input");
+
+ char *buf = nullptr;
+ size_t acc, bufsz;
+ ssize_t n;
+
+ acc = bufsz = 0;
+
+ while ((n = getline(&buf, &bufsz, fp)) != -1) {
+ if (buf[n - 1] == '\n')
+ buf[--n] = 0;
+
+ char digits[DIGITS + 1];
+ memcpy(digits, buf, DIGITS);
+ digits[DIGITS] = 0;
+
+ for (size_t i = 1; i < n - DIGITS + 1; i++) {
+ for (size_t j = 0; j < DIGITS; j++) {
+ if (buf[i + j] > digits[j])
+ memcpy(digits + j, buf + i + j, DIGITS - j);
+ }
+ }
+
+ acc += (size_t)strtol(digits, nullptr, 10);
+ }
+ if (ferror(fp))
+ err(EXIT_FAILURE, "failed to read record");
+
+ fclose(fp);
+ printf("%zu\n", acc);
+ return EXIT_SUCCESS;
+}
diff --git a/2025/04/.gitignore b/2025/04/.gitignore
new file mode 100644
index 0000000..ffc46fe
--- /dev/null
+++ b/2025/04/.gitignore
@@ -0,0 +1 @@
+puzzle-[12].py
diff --git a/2025/04/Makefile b/2025/04/Makefile
new file mode 100644
index 0000000..0a4e980
--- /dev/null
+++ b/2025/04/Makefile
@@ -0,0 +1 @@
+include ../../Makefiles/py.mk
diff --git a/2025/04/puzzles.py b/2025/04/puzzles.py
new file mode 100644
index 0000000..3558269
--- /dev/null
+++ b/2025/04/puzzles.py
@@ -0,0 +1,95 @@
+#!/usr/bin/python3
+
+import itertools
+from typing import Generator, Iterator, Self, TextIO
+
+
+class Grid:
+ @classmethod
+ def from_file(cls, f: TextIO) -> Self:
+ g = Grid()
+ g._grid = mkmap(
+ [[c for c in l if c != '\n'] for l in f.readlines()])
+ return g
+
+ def in_bounds_p(self, z: complex) -> bool:
+ return (
+ 0 <= z.real < len(self._grid[0])
+ and 0 <= z.imag < len(self._grid)
+ )
+
+ def accessablep(self, z: complex) -> bool:
+ return self[z] is not None and self[z] < 4
+
+ def indicies(self) -> Iterator[complex]:
+ return itertools.starmap(complex, itertools.product(
+ range(len(self._grid[0])),
+ range(len(self._grid)),
+ ))
+
+ def neighbors(self, z: complex) -> Generator[complex, None, None]:
+ for Δ in (
+ -1-1j, -1, -1+1j,
+ 0-1j, 0+1j,
+ +1-1j, +1, +1+1j,
+ ):
+ if self.in_bounds_p(z + Δ):
+ yield z + Δ
+
+ def __getitem__(self, z: complex) -> int | None:
+ return self._grid[int(z.real)][int(z.imag)]
+
+ def __setitem__(self, z: complex, n: int | None) -> None:
+ self._grid[int(z.real)][int(z.imag)] = n
+
+
+def mkmap(xs: list[list[str]]) -> list[list[int]]:
+ def get(pos: complex) -> str:
+ r, i = map(int, (pos.real, pos.imag))
+ if 0 <= r < len(xs[0]) and 0 <= i < len(xs):
+ return xs[r][i]
+ return '.'
+
+ return [
+ [
+ sum(get(complex(i, j) + Δ) == '@' for Δ in [
+ -1-1j, -1, -1+1j,
+ 0-1j, 0+1j,
+ +1-1j, +1, +1+1j,
+ ])
+ if get(complex(i, j)) == '@'
+ else None
+ for j in range(len(xs[i]))
+ ]
+ for i in range(len(xs))
+ ]
+
+
+def main() -> None:
+ with open('input', 'r') as f:
+ grid = Grid.from_file(f)
+
+ if PUZZLE_PART == 1:
+ acc = sum(grid.accessablep(z) for z in grid.indicies())
+ else:
+ acc = 0
+ while True:
+ breakp = True
+ for z in grid.indicies():
+ if not grid.accessablep(z):
+ continue
+ breakp = False
+ acc += 1
+ grid[z] = None
+ for p in grid.neighbors(z):
+ if grid[p] is not None:
+ grid[p] -= 1
+
+ if breakp:
+ break
+
+ print(acc)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/2025/05/puzzle-1.awk b/2025/05/puzzle-1.awk
new file mode 100755
index 0000000..acfe21b
--- /dev/null
+++ b/2025/05/puzzle-1.awk
@@ -0,0 +1,19 @@
+#!/usr/bin/awk -f
+
+BEGIN { FS = "-" }
+
+NF == 2 {
+ xs[NR, 1] = $1
+ xs[NR, 2] = $2
+}
+
+NF == 1 {
+ for (i = 1; i <= length(xs) / 2; i++) {
+ if ($1 >= xs[i, 1] && $1 <= xs[i, 2]) {
+ cnt++
+ break
+ }
+ }
+}
+
+END { print cnt }
diff --git a/2025/05/puzzle-2.awk b/2025/05/puzzle-2.awk
new file mode 100755
index 0000000..3dfc661
--- /dev/null
+++ b/2025/05/puzzle-2.awk
@@ -0,0 +1,31 @@
+#!/usr/bin/gawk -f
+
+function rangecmp(i1, v1, i2, v2)
+{
+ return v1[1] - v2[1]
+}
+
+function max(x, y)
+{
+ return x > y ? x : y
+}
+
+BEGIN { FS = "-" }
+
+NF == 2 {
+ xs[NR][1] = $1
+ xs[NR][2] = $2
+}
+
+END {
+ asort(xs, xs, "rangecmp")
+ for (i in xs) {
+ if (xs[i][2] <= m)
+ continue
+ cnt += xs[i][2] - max(xs[i][1], m)
+ if (xs[i][1] > m)
+ cnt++
+ m = xs[i][2]
+ }
+ print cnt
+}
diff --git a/2025/06/puzzle-1.awk b/2025/06/puzzle-1.awk
new file mode 100755
index 0000000..4bb4338
--- /dev/null
+++ b/2025/06/puzzle-1.awk
@@ -0,0 +1,20 @@
+#!/usr/bin/awk -f
+
+NR == 1 {
+ for (i = 1; i <= NF; i++)
+ xs[i, 2] = 1
+}
+
+!/[+*]/ {
+ for (i = 1; i <= NF; i++) {
+ xs[i, 1] += $i
+ xs[i, 2] *= $i
+ }
+}
+
+/[+*]/ {
+ for (i = 1; i <= NF; i++)
+ total += xs[i, $i == "+" ? 1 : 2]
+}
+
+END { print total }
diff --git a/2025/06/puzzle-2.sh b/2025/06/puzzle-2.sh
new file mode 100755
index 0000000..cba270f
--- /dev/null
+++ b/2025/06/puzzle-2.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+{
+ printf '('
+ for i in $(seq "$(head -n1 input | wc -c)")
+ do
+ num="$(cut -c $i input | paste -sd '')"
+ num="${num%${num##*[![:space:]]}}"
+
+ case "$num" in
+ *[+*])
+ test -n "$op" && printf ') + ('
+ op="${num#${num%?}}"
+ num="${num%?}"
+ printf '%d %s ' $num "$op"
+ ;;
+ '')
+ test "$op" = +
+ printf '%d' $?
+ ;;
+ *)
+ printf '%d %s ' $num "$op"
+ ;;
+ esac
+ done
+ printf ')\n'
+} | bc
diff --git a/2025/07/puzzle-1.py b/2025/07/puzzle-1.py
new file mode 100755
index 0000000..0c30dfa
--- /dev/null
+++ b/2025/07/puzzle-1.py
@@ -0,0 +1,23 @@
+#!/usr/bin/python3
+
+
+def main() -> None:
+ with open('input', 'r') as f:
+ grid = tuple(tuple(x.strip()) for x in f.readlines())
+
+ xs = set()
+ xs.add(grid[0].index('S'))
+ cnt = 0
+
+ for row in grid[1:]:
+ for i, ch in enumerate(row):
+ if ch == '^' and i in xs:
+ cnt += 1
+ xs.remove(i)
+ xs.add(i - 1)
+ xs.add(i + 1)
+
+ print(cnt)
+
+if __name__ == '__main__':
+ main()
diff --git a/2025/07/puzzle-2.py b/2025/07/puzzle-2.py
new file mode 100755
index 0000000..3695889
--- /dev/null
+++ b/2025/07/puzzle-2.py
@@ -0,0 +1,31 @@
+#!/usr/bin/python3
+
+import collections
+import functools
+
+
+Pos = collections.namedtuple('Pos', ['x', 'y'])
+
+
+def main() -> None:
+ with open('input', 'r') as f:
+ grid = tuple(tuple(x.strip()) for x in f.readlines())
+
+ pos = Pos(grid[0].index('S'), 0)
+ print(npaths(grid, pos))
+
+
+@functools.cache
+def npaths(grid: list[list[str]], pos: Pos) -> int:
+ if pos.y == len(grid):
+ return 1
+ if grid[pos.y][pos.x] == '^':
+ return (
+ npaths(grid, Pos(pos.x - 1, pos.y))
+ + npaths(grid, Pos(pos.x + 1, pos.y))
+ )
+ return npaths(grid, Pos(pos.x, pos.y + 1))
+
+
+if __name__ == '__main__':
+ main()