Skip to content

Commit cc4dd39

Browse files
committed
Tooling and more day 1 cleanup
1 parent b1134ce commit cc4dd39

8 files changed

Lines changed: 192 additions & 9 deletions

File tree

.dir-locals.el

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
((lean4-mode
2+
(eval . (unless (featurep 'aoc2025-eutro)
3+
(let ((load-path (cons (locate-dominating-file
4+
(or load-file-name (buffer-file-name))
5+
"aoc2025-eutro.el")
6+
load-path)))
7+
(require 'aoc2025-eutro))))
8+
(eval . (aoc2025-eutro-mode))))

Aoc2025.lean

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
import Aoc2025.Basic

Aoc2025/Basic.lean

Lines changed: 0 additions & 1 deletion
This file was deleted.

Aoc2025/Day01.lean

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,41 @@
1-
def dialInit : Int := 50
2-
def dialSize : Int := 100
1+
abbrev Dial := Int
2+
def dialSize : Nat := 100
3+
def dialInit : Dial := 50
34

4-
abbrev DialState α := StateM Int α
5+
abbrev DialState α := StateM Dial α
56

67
-- Rotate the dial by the given command.
78
def stepDial (command : Int) : DialState Unit := do
89
let dial <- get
910
set $ (dial + command) % dialSize
1011

12+
theorem step_dial_homomorphism
13+
: ∀ c0 c1, stepDial (c0 + c1) = (do stepDial c0; stepDial c1) := by
14+
intros
15+
apply StateT.ext
16+
intros
17+
simp [stepDial]
18+
grind
19+
1120
-- Rotate the dial at once, only counting 0 at the end.
1221
def stepAtomic (command : Int) : DialState Int := do
1322
stepDial command
1423
let dial' <- get
1524
return if dial' = 0 then 1 else 0
1625

1726
-- Rotate the dial one step at a time, counting every 0.
18-
def stepIncremental (command : Int) : DialState Int :=
19-
0 |> command.natAbs.foldM fun _ _ a ↦ do
20-
let a' <- stepAtomic command.sign
21-
return a + a'
27+
def stepIncrementalSlow (command : Int) : DialState Int := do
28+
let substates <- (List.replicate command.natAbs command.sign).mapM stepAtomic
29+
return substates.sum
30+
31+
def stepIncremental (command : Int) : DialState Int := do
32+
let dial <- get
33+
stepDial command
34+
let rawDial' := dial + command
35+
let mut fullRotations := rawDial'.natAbs / dialSize
36+
if rawDial' <= 0 ∧ dial % dialSize != 0 then
37+
fullRotations := fullRotations + 1
38+
return fullRotations
2239

2340
-- Run the stepping function over the commands.
2441
def runPart (step : Int -> DialState Int) (commands : Array Int) : Int :=

aoc2025-eutro.el

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
;;; aoc2025-eutro.el --- Advent of Code utilities -*- lexical-binding: t -*-
2+
3+
;;; Code:
4+
5+
(defgroup aoc2025-eutro nil
6+
"Group for Eutro's Advent of Code 2025"
7+
:prefix 'aoc2025-eutro-
8+
:group 'misc)
9+
10+
(defconst aoc-root
11+
(locate-dominating-file
12+
(or load-file-name (buffer-file-name))
13+
"README.md"))
14+
15+
(defconst aoc-dayfile-pattern "Day\\([0-9]\\{2\\}\\)")
16+
17+
(defvar-local aoc-pinned-day-number nil)
18+
19+
(defun aoc-day-number ()
20+
"Determine the day number of the current file, or the current day."
21+
(or
22+
aoc-pinned-day-number
23+
(when-let ((file-name (buffer-file-name)))
24+
(and (string-match aoc-dayfile-pattern file-name)
25+
(string-to-number (match-string 1 file-name))))
26+
(progn
27+
(require 'calendar)
28+
(cadr (calendar-current-date)))))
29+
30+
(defun aoc-get-out-buffer (&optional clear day)
31+
"Get the *aoc-output* buffer."
32+
(let ((buf (get-buffer-create "*aoc-output*")))
33+
(when (or clear
34+
(not (eq 'aoc-run-mode
35+
(buffer-local-value 'major-mode buf))))
36+
(with-current-buffer buf
37+
(erase-buffer)
38+
(when day (setq aoc-pinned-day-number day))
39+
(aoc-run-mode)))
40+
buf))
41+
42+
(defconst aoc--run-script (expand-file-name "run.sh" aoc-root))
43+
44+
(defconst aoc--display-buffer-action nil
45+
;;'display-buffer-use-least-recent-window
46+
)
47+
48+
(defun aoc-run (&optional prefix)
49+
"Run the current day.
50+
51+
With PREFIX, read input from the buffer."
52+
(interactive "P")
53+
(let* ((day (aoc-day-number))
54+
(inp-args (when prefix '("--")))
55+
(buf (aoc-get-out-buffer t day))
56+
(args (cons (number-to-string day) inp-args))
57+
(proc (apply #'start-process "aoc-run" buf aoc--run-script args))
58+
(win (selected-window)))
59+
(set-process-sentinel
60+
proc
61+
(lambda (_proc msg)
62+
(when-let ((win (get-buffer-window buf)))
63+
(with-selected-window win
64+
(recenter -1)))))
65+
(unless (eq (window-buffer win) buf)
66+
(if prefix
67+
(pop-to-buffer buf aoc--display-buffer-action)
68+
(display-buffer buf aoc--display-buffer-action)))
69+
(message "./run.sh %s" (string-join (mapcar #'shell-quote-argument args) " "))))
70+
71+
(defun aoc-copy-part-answer (part)
72+
"Copy the answer for the given PART from *aoc-output*."
73+
(with-current-buffer (aoc-get-out-buffer)
74+
(goto-char (point-max))
75+
(unless (re-search-backward (format "Part %d: " part) nil t)
76+
(user-error "Part %d not found in buffer" part))
77+
(goto-char (match-end 0))
78+
(let ((start (point)))
79+
(end-of-line)
80+
(copy-region-as-kill start (point))
81+
(message "Copied: %s" (current-kill 0 t)))))
82+
83+
(defmacro aoc-copy-n (part)
84+
`(defun ,(intern (format "aoc-copy-%d" part)) ()
85+
,(format "Copy the answer for part %d in *aoc-output*." part)
86+
(interactive)
87+
(aoc-copy-part-answer ,part)))
88+
89+
(aoc-copy-n 1)
90+
(aoc-copy-n 2)
91+
92+
(defconst aoc-mode-map
93+
(let ((keys (make-sparse-keymap)))
94+
(define-key keys (kbd "C-c C-c") #'aoc-run)
95+
(define-key keys (kbd "C-c 1") #'aoc-copy-1)
96+
(define-key keys (kbd "C-c 2") #'aoc-copy-2)
97+
keys))
98+
99+
(define-minor-mode aoc-mode
100+
"Minor mode for Advent of Code utilities"
101+
:lighter " AoC24")
102+
103+
(defconst aoc-run-mode-map
104+
(let ((keys (copy-keymap aoc-mode-map)))
105+
keys))
106+
107+
(define-derived-mode aoc-run-mode comint-mode "AoC-Run"
108+
"Major mode for the *aoc-run* buffer.")
109+
110+
;; Local Variables:
111+
;; read-symbol-shorthands: (("aoc-" . "aoc2025-eutro-"))
112+
;; End:
113+
114+
(provide 'aoc2025-eutro)
115+
;;; aoc2025-eutro.el ends here

build.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/env sh
2+
3+
DIR="$(readlink -f "$(dirname "$0")")"
4+
cd "$DIR" || exit 1
5+
6+
case "$1" in
7+
''|*[!0-9]*) DAYN="$(date +%d)" ;;
8+
*) DAYN="$1"; shift ;;
9+
esac
10+
DAY="$(echo "$DAYN" | sed 's/^0*//')"
11+
DAYP="$(printf "%02d" "$DAY")"
12+
13+
lake build --no-ansi "Day$DAYP:exe" "$@"

lakefile.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,7 @@ scope = "leanprover-community"
1616

1717
[[lean_lib]]
1818
name = "Aoc2025"
19+
20+
[[lean_exe]]
21+
name = "Day01"
22+
root = "Aoc2025.Day01"

run.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env sh
2+
3+
DIR="$(readlink -f "$(dirname "$0")")"
4+
cd "$DIR" || exit 1
5+
6+
case "$1" in
7+
''|*[!0-9]*) DAYN="$(date +%d)" ;;
8+
*) DAYN="$1"; shift ;;
9+
esac
10+
DAY="$(echo "$DAYN" | sed 's/^0*//')"
11+
DAYP="$(printf "%02d" "$DAY")"
12+
13+
export AOC_INPUT
14+
if [ "$1" = "--" ]
15+
then AOC_INPUT="/dev/stdin"; shift
16+
elif [ "$1" = "-e" -o "$1" = "--example" ]
17+
then AOC_INPUT="$DIR/inputs/example$DAYP.txt"; shift
18+
elif [ "$1" = "-i" -o "$1" = "--input" ]
19+
then AOC_INPUT="$2"; shift; shift
20+
else
21+
AOC_INPUT="$DIR/inputs/day$DAYP.txt"
22+
if ! [ -f "$AOC_INPUT" ]
23+
then raco aoc -y 2025 -d "$DAY" > "$AOC_INPUT" || exit 1
24+
fi
25+
fi
26+
27+
./build.sh "$DAY"
28+
time ".lake/build/bin/Day$DAYP" "$@" < "$AOC_INPUT"

0 commit comments

Comments
 (0)