The Right Lang for the Job

Exploring the abbyss of non-mainstream programming languages

Advent of Code 2023 - Day 3, Part 1

A classic, buffer-based implementation this time


I made it! I woke up early, drank 3 coffees, but in the end, I managed to solve the puzzle and post the solution before the others! 🙂

The puzzle this time is about extracting numbers from a 2D array of characters and checking whether the number neighbours any character other than a dot (".").

In Emacs, all text is in a 2D array by default - that's (conceptually) what a buffer is, after all. So there's really not much to the solution this time, other than handling some corner cases (first and last lines, and treating newlines as dots - for numbers that are at the end of the line).

Here's the solution:

 1: ;; NOTE: lines are 140 characters wide (maybe verify this instead of assuming?)
 2: (with-current-buffer (get-buffer "input3.txt")
 3:   (goto-char (point-min))
 4:   (let (numbers (lines (count-lines (point-min) (point-max))))
 5:     (while (re-search-forward (rx (1+ num)) nil t)
 6:       (let* ((beg (match-beginning 0))
 7:              (end (match-end 0))
 8:              (surrounding (concat 
 9:                            (string (char-after (1- beg))) ; preceding char
10:                            (string (char-after end))      ; following char
11:                            ;; previous line
12:                            (if (not (= 1 (line-number-at-pos)))
13:                                (buffer-substring-no-properties (- beg 142) (- end 140))
14:                              ".")
15:                            ;; next line
16:                            (if (not (= lines (line-number-at-pos)))
17:                                (buffer-substring-no-properties (+ beg 140) (+ end 142))
18:                              "."))))
19:         (unless (cl-every (lambda (c) (or (eq c ?\n) (eq c ?.))) surrounding)
20:           (push (string-to-number (match-string 0)) numbers))))
21:     (apply #'+ numbers)))

We just loop through the numbers in the buffer, fetch the characters that surround the number, and verify there are only dots (and newlines, as a special case) in these characters.

I thought about using save-excursion and forward-line to get the preceding and following lines, then using looking-at-p to check for symbols - I think it would work and I wouldn't need to check line width in that case. By the time I thought of it, though, buffer-substring-based solution worked already, so I just left it as is.

Unfortunately, I don't have the time to solve Part 2 of the puzzle. In part 2, you need to find all * symbols that have more than one number in its surroundings. It's more interesting than Part 1 because there are more ways of solving it. I'll see if I have the time to code the solution in the evening.