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)))))))
|