;;; solver.el --- Day 09 -*- lexical-binding: t; -*- ;; ;; Copyright (C) 2022 Óscar Nájera ;; ;; Author: Óscar Nájera ;; Maintainer: Óscar Nájera ;; 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)))))))