Advent of Code '23 - day 3

Table of Contents

This might be one of the last days I'll be using elisp. The puzzles are taking longer to solve and I don't really forsee lots of free time in the coming week. The first part went pretty quickly. The second deserved a completely new approach, where I'd search for all stars first, and (rather ugly) look for neighboring numbers.

Input

Example

467..114..
...*......
..35..633.
......#...
617*......
.....+.58.
..592.....
......755.
...$.*....
.664.598..

Part 1

This solution scans the input row by row, character by character. If the current character is a number, it looks around for a special symbol. When done parsing, and it did see a special symbol, the number gets added to a list.

(defun string-numberp(s)
  (condition-case invalid-read-syntax
      (numberp(read s))
    (error nil)))

(defun aoc23/scan-point (point field)
  (let ((offsets '((-1 -1) (0 -1) (1 -1) (-1 0) (1 0) (-1 1) (0 1) (1 1)))
        (found nil))
    (dolist (o offsets)
      (let ((point (list (+ (car point) (car o))
                         (+ (cadr point) (cadr o)))))
        (unless (or (< (car point) 0)
                    (>= (car point) (length (car field)))
                    (< (cadr point) 0)
                    (>= (cadr point) (length field)))
          (let ((char (substring (nth (cadr point) field)
                                 (car point)
                                 (+ 1 (car point)))))
            (message "%s" char)
            (when (not (or (string= "." char)
                           (string-numberp char)))
              (setq found t))))))
    found))

(let ((field (string-split input))
      (numbers '())
      (current "")
      (eligable nil))
  (dotimes (y (length field))
    (let ((row (nth y field)))
      (dotimes (i (length row))
        (let ((c (substring row i (+ 1 i))))
          (if (string-numberp c)
              (progn
                (setq current (concat current c))
                (when (aoc23/scan-point (list i y) field)
                  (setq eligable t)))
            (unless (string= "" current)
              (when (eq eligable t)
                (setq numbers (append numbers (list (string-to-number current)))))
              (setq current "")
              (setq eligable nil)))))
      (unless (string= "" current)
        (when (eq eligable t)
          (setq numbers (append numbers (list (string-to-number current)))))
        (setq current "")
        (setq eligable nil))))
  (apply '+ numbers))

Part 2

This

(defun string-numberp(s)
  (condition-case invalid-read-syntax
      (numberp(read s))
    (error nil)))

(defun aoc23/parse (i field)
  (when (and (>= i 0)
             (< i (length field)))
    (when (string-numberp (substring field i (1+ i)))
      (let ((start i)
            (end i))
        (while (and (>= (1- start) 0)
                    (string-numberp (substring field (1- start) start)))
          (setq start (1- start)))
        (while (and (< (1+ end) (length field))
                    (string-numberp (substring field end (1+ end))))
          (setq end (1+ end)))

        (string-to-number (substring field start end))
        ))))

(defun aoc23/scan-pairs (offset input length)
  (let ((numbers '()))
    (when (aoc23/parse (1- offset) input)
      (setq numbers (append numbers (list (aoc23/parse (1- offset) input)))))
    (when (aoc23/parse (1+ offset) input)
      (setq numbers (append numbers (list (aoc23/parse (1+ offset) input)))))
    (let ((up (- offset (1+ length)))
          (down (+ offset (1+ length))))
      (if (aoc23/parse up input)
          (setq numbers (append numbers (list (aoc23/parse up input))))
        (progn
          (when (aoc23/parse (1- up) input)
            (setq numbers (append numbers (list (aoc23/parse (1- up) input)))))
          (when (aoc23/parse (1+ up) input)
            (setq numbers (append numbers (list (aoc23/parse (1+ up) input)))))))
      (if (aoc23/parse down input)
          (setq numbers (append numbers (list (aoc23/parse down input))))
        (progn
          (when (aoc23/parse (1- down) input)
            (setq numbers (append numbers (list (aoc23/parse (1- down) input)))))
          (when (aoc23/parse (1+ down) input)
            (setq numbers (append numbers (list (aoc23/parse (1+ down) input))))))))
    (when (eq 2 (length numbers))
      (message "pair %S @ %d" numbers offset)
      (apply '* numbers))))




(let ((i 0)
      (l (length (car (string-split input))))
      (ratios '()))
  (while (setq i (string-search "*" input i))
    (let ((r (aoc23/scan-pairs i input l)))
      (when r
        (setq ratios (append ratios (list r)))))
    (setq i (1+ i)))
  (apply '+ ratios))

;; (let* ((input "467..114..
;; ...*......
;; ..35..633.")
;;        (s (string-search "*" input))
;;        (l (string-search "\n" input)))
;;   (aoc23/scan-pairs s input (1+ l)))