day-10.lisp (1947B)
1 (defpackage #:aoc/day-10 2 (:use #:cl #:aoc/utils) 3 (:export #:day-10)) 4 (in-package #:aoc/day-10) 5 6 (defun find-trailheads (map) 7 (loop for y from 0 below (input-map-height map) 8 nconc (loop for x from 0 below (input-map-width map) 9 for point = (cons x y) 10 for cell = (map-cell map point) 11 when (char= cell #\0) 12 collect point))) 13 14 (defparameter *trail-neighbours* 15 (list (cons 0 -1) 16 (cons -1 0) 17 (cons 1 0) 18 (cons 0 1))) 19 20 (defun score (map trailhead) 21 (let ((map-width (input-map-width map)) 22 (map-height (input-map-height map)) 23 (points (make-hash-table :test #'equal)) 24 (rating 0)) 25 (labels ((%walk (pos) 26 (when (char= (map-cell map pos) #\9) 27 (setf (gethash pos points) t) 28 (incf rating) 29 (return-from %walk nil)) 30 (loop with height = (char-number (map-cell map pos)) 31 for np in (loop for nd in *trail-neighbours* 32 for np = (point+ pos nd) 33 when (point-in-bounds-p np map-width map-height) 34 collect np) 35 for nc = (map-cell map np) 36 when (and (not (char= nc #\.)) 37 (= (- (char-number nc) 38 height) 39 1)) 40 do (%walk np)))) 41 (%walk trailhead) 42 (values (length (hash-table-keys points)) 43 rating)))) 44 45 (defun day-10 (input) 46 (loop with map = (make-map input) 47 with trailheads = (find-trailheads map) 48 for trailhead in trailheads 49 for (score rating) = (multiple-value-list (score map trailhead)) 50 sum score into task-1 51 sum rating into task-2 52 finally (return (values task-1 task-2))))