;;; solver.el --- Day 10 -*- lexical-binding: t; -*- ;; ;; Copyright (C) 2022 Óscar Nájera ;; ;; Author: Óscar Nájera ;; Maintainer: Óscar Nájera ;; Created: December 10, 2022 ;; Modified: December 10, 2022 ;; ;; This file is not part of GNU Emacs. ;; ;;; Commentary: ;; ;; Day 10 ;; ;;; Code: (require 'subr-x) (require 'cl-lib) (require 'ert) (defsubst solver-probe (cycle register) (when (memq cycle '(20 60 100 140 180 220)) (* cycle register))) (defsubst solver-draw-pixel (pixel register) (when (= 0 pixel) (insert "\n")) (insert (if (<= (1- register) pixel (1+ register)) "#" "."))) (defun solver-instructions (filename) (with-temp-buffer (insert-file-contents filename) (split-string (buffer-string) "\n"))) (defun solver (data-file) (let ((register 1) (cycle 1) measures) (with-temp-buffer (dolist (instruction (solver-instructions data-file)) (solver-draw-pixel (mod (1- cycle) 40) register) (cl-incf cycle) (let ((step1 (solver-probe cycle register)) ;; the noop default (step2 ;; addx takes 2 cycles (when (string-prefix-p "addx" instruction) (solver-draw-pixel (mod (1- cycle) 40) register) (cl-incf cycle) (cl-incf register (string-to-number (cadr (split-string instruction)))) (solver-probe cycle register)))) (when-let ((probe (or step1 step2))) (push probe measures)))) (list (apply #'+ measures) (buffer-string))))) (ert-deftest test-solver () (should (equal (solver "eg-in") (list 13140 " ##..##..##..##..##..##..##..##..##..##.. ###...###...###...###...###...###...###. ####....####....####....####....####.... #####.....#####.....#####.....#####..... ######......######......######......#### #######.......#######.......#######..... ."))) (should (equal (solver "input") (list 12540 " ####.####..##..####.####.#....#..#.####. #....#....#..#....#.#....#....#..#.#.... ###..###..#......#..###..#....####.###.. #....#....#.....#...#....#....#..#.#.... #....#....#..#.#....#....#....#..#.#.... #....####..##..####.####.####.#..#.####. .")))) (provide 'solver) ;;; solver.el ends here e
blob: 76001f181a0490004331a33fd284bb01536d862f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
(ql:quickload '(fiveam str arrows))

(defparameter eg-input "LLR

AAA = (BBB, BBB)
BBB = (AAA, ZZZ)
ZZZ = (ZZZ, ZZZ)")

(defun parse-input (lines)
  (let ((graph (make-hash-table :test #'equal)))
    (destructuring-bind (instructions blank . nodes) lines
      (declare (ignorable blank))
      (dolist (line nodes)
        (destructuring-bind (node . leaves)
            (remove-if #'str:emptyp
                       (cl-ppcre:split "[=,() ]" line))
          (setf (gethash node graph) leaves)))
      (values instructions graph))))

(defun traverse (instructions graph location terminatep)
  (loop
    for i from 0
    do (arrows:-<>
        (ecase (aref instructions (mod i (length instructions)))
          (#\L #'first)
          (#\R #'second))
        (funcall <> (gethash location graph))
        (setf location <>))
    count i until (funcall terminatep location)))

(defun solver1 (lines)
  (multiple-value-bind (instructions graph)
      (parse-input lines)
    (traverse instructions graph "AAA" (lambda (p) (equal "ZZZ" p)))))

(defparameter eg-input2 "LR

11A = (11B, XXX)
11B = (XXX, 11Z)
11Z = (11B, XXX)
22A = (22B, XXX)
22B = (22C, 22C)
22C = (22Z, 22Z)
22Z = (22B, 22B)
XXX = (XXX, XXX)")

(defun solver2 (lines)
  (multiple-value-bind (instructions graph)
      (parse-input lines)
    (arrows:->>
     (remove-if-not (lambda (s) (str:ends-with-p "A" s))
                    (alexandria:hash-table-keys graph))
     (mapcar (lambda (start)
               (traverse instructions graph start (lambda (p) (str:ends-with-p "Z" p)))))
     (apply #'lcm))))

(fiveam:test solutions
  (fiveam:is (= 6 (solver1 (uiop:split-string eg-input :separator '(#\Newline)))))
  (fiveam:is (= 6 (solver2 (uiop:split-string eg-input2 :separator '(#\Newline)))))
  (fiveam:is (= 19199 (solver1 (uiop:read-file-lines "input"))))
  (fiveam:is (= 13663968099527(solver2 (uiop:read-file-lines "input")))))