aboutsummaryrefslogtreecommitdiffstats
path: root/AoC2022/09/solver.el
blob: d1eac37f0283b0502235c53bd2df0dd71c36d404 (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
;;; 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:

(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))))))
;; WARN This need to be bytecompiled otherwise the lambda is not capturing diff-v in the closure
(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)))))
     ((= distance 3)
      (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 "Head moved too far")))))

(with-temp-buffer
  (insert-file-contents "input")
;;   (insert "R 4
;; U 4
;; L 3
;; D 1
;; R 4
;; D 1
;; L 5
;; R 2")
  (let (path
        (head (cons 0 0))
        (tail (cons 0 0))
        (moves
         (thread-last
           (split-string (buffer-string) "\n" t)
           (mapcar (lambda (inst) (let ((move (split-string inst)))
                                    (cons (intern (car move))
                                          (string-to-number (cadr move))))))
           )))
    (dolist (move moves)
      (dotimes (_ (cdr move))
        (funcall (solver-move (car move)) head)
        (funcall (solver-puller (solver-diff head tail)) tail)
        (push (cons (car tail) (cdr tail)) path)))
    (= 6384 (length (cl-remove-duplicates path :test #'equal))))