aboutsummaryrefslogtreecommitdiffstats
path: root/AoC2022/09/solver.el
blob: 778c508dad765635e6587a039964f6328c15351c (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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
;;; solver.el --- Day 09 -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2022 Óscar Nájera
;;
;; Author: Óscar Nájera <hi@oscarnajera.com>
;; Maintainer: Óscar Nájera <hi@oscarnajera.com>
;; Created: December 09, 2022
;; Modified: December 09, 2022
;;
;; This file is not part of GNU Emacs.
;;
;;; Commentary:
;;
;;  Day 09
;;
;;; Code:
(require 'subr-x)

(defsubst solver-diff (head tail)
  (cons (- (car head) (car tail)) (- (cdr head) (cdr tail))))

(defsubst solver-distance-1 (vec)
  "Norm 1 distance."
  (+ (abs (car vec)) (abs (cdr vec))))

(defsubst solver-diagonal (vec)
  (and (= 1 (abs (car vec))) (= 1 (abs (cdr vec)))))

(defun solver-move (direction)
  (cl-ecase direction
    ('R (lambda (x) (cl-incf (car x))))
    ('L (lambda (x) (cl-decf (car x))))
    ('U (lambda (x) (cl-incf (cdr x))))
    ('D (lambda (x) (cl-decf (cdr x))))))

(defun solver-puller (diff-v)
  (let ((distance (solver-distance-1 diff-v)))
    (cond
     ((or (<= distance 1)
          (solver-diagonal diff-v)) #'identity)
     ((= distance 2)
      (pcase diff-v
        (`(0 . ,d) (solver-move (if (= d 2) 'U 'D)))
        (`(,d . 0) (solver-move (if (= d 2) 'R 'L)))))
     ((<= 3 distance 4)
      (lambda (x)
        (funcall (solver-move (if (< 0 (car diff-v)) 'R 'L)) x)
        (funcall (solver-move (if (< 0 (cdr diff-v)) 'U 'D)) x)))
     (t (error "Leader moved too far")))))

(defun solver-input (data-string)
  (thread-last
    (split-string data-string "\n" t)
    (mapcar (lambda (inst) (let ((move (split-string inst)))
                             (cons (intern (car move))
                                   (string-to-number (cadr move))))))))

(defun solver (moves rope)
  (let (path
        (head (car rope))
        (end (car (last rope))))
    (dolist (move moves)
      (dotimes (_ (cdr move))
        (funcall (solver-move (car move)) head)
        (cl-loop for (leader follower) on rope  while follower
                 do (funcall (solver-puller (solver-diff leader follower)) follower))
        ;; (message "%S" rope)
        (push (cons (car end) (cdr end)) path)))
    (cl-remove-duplicates path :test #'equal)))

(defconst solver-eg-1 (solver-input  "R 4
    U 4
    L 3
    D 1
    R 4
    D 1
    L 5
    R 2"))

(defconst solver-eg-2 (solver-input  "R 5
U 8
L 8
D 3
R 17
D 10
L 25
U 20"))

(defconst solver-problem (solver-input (with-temp-buffer (insert-file-contents "input") (buffer-string))))
(ert-deftest test-solver ()
  ;; part 1
  (should (= 13 (length (solver solver-eg-1 (list (cons 0 0) (cons 0 0))))))
  (should (= 6384 (length (solver solver-problem (list (cons 0 0) (cons 0 0))))))
  ;; part 2
  (should (= 1 (length (solver solver-eg-1 (cl-loop repeat 10 collect (cons 0 0))))))
  (should (= 36 (length (solver solver-eg-2 (cl-loop repeat 10 collect (cons 0 0))))))
  (should (= 2734 (length (solver solver-problem (cl-loop repeat 10 collect (cons 0 0)))))))