adventofcode2022

My solutions for Advent of Code 2022
Log | Files | Refs

day22.lisp (5527B)


      1 (defpackage #:adventofcode2022/day22
      2   (:use #:cl #:adventofcode2022))
      3 (in-package #:adventofcode2022/day22)
      4 
      5 (defun turn (facing direction)
      6   (mod
      7    (+ facing
      8       (case direction
      9         (:left -1)
     10         (:right 1)
     11         (otherwise 0)))
     12    4))
     13 
     14 (defun walk (coords facing)
     15   (let ((x (car coords))
     16         (y (cadr coords)))
     17     (case facing
     18       (0 (list (1+ x) y))
     19       (1 (list x (1+ y)))
     20       (2 (list (1- x) y))
     21       (3 (list x (1- y))))))
     22 
     23 (defun parse-input (inputs)
     24   (loop with map = (make-hash-table :test 'equal)
     25         with last-line? = nil
     26         with min-x = nil
     27         for line in inputs
     28         for length = (length line)
     29         for y from 0
     30         when last-line?
     31           return (values
     32                   map
     33                   (loop with start = 0
     34                         with results = nil
     35                         for i from 0
     36                         while (< i length)
     37                         for char = (aref line i)
     38                         if (not (digit-char-p char))
     39                           do (push (parse-integer (subseq line start i)) results)
     40                           and do (push (case char (#\R :right) (#\L :left)) results)
     41                           and do (setf start (1+ i))
     42                         finally (push (parse-integer (subseq line start i)) results)
     43                         finally (return (nreverse results)))
     44                   (list min-x 0))
     45         when (= length 0)
     46           do (setf last-line? t)
     47         do (loop for x from 0 below length
     48                  for char = (aref line x)
     49                  for type = (case (aref line x)
     50                               (#\# :wall)
     51                               (#\. :empty)
     52                               (otherwise nil))
     53                  when (and (= y 0)
     54                            (eq type :empty)
     55                            (or (null min-x)
     56                                (< x min-x)))
     57                    do (setf min-x x)
     58                  when type
     59                    do (setf (gethash (list x y) map) type))))
     60 
     61 (defun wrap-around (map pos last-pos dir)
     62   (declare (ignore dir))
     63   (let ((x (car pos))
     64         (y (cadr pos)))
     65     (if (= y (cadr last-pos))
     66         (list
     67          (if (> x (car last-pos))
     68              (loop for i from 0
     69                    for tile = (gethash (list i y) map)
     70                    when tile
     71                      return i)
     72              (loop for i from (car last-pos)
     73                    for (tile exists) = (multiple-value-list (gethash (list i y) map))
     74                    while exists
     75                    maximize i))
     76          y)
     77         (list
     78          x
     79          (if (> y (cadr last-pos))
     80              (loop for i from 0
     81                    for tile = (gethash (list x i) map)
     82                    when tile
     83                      return i)
     84              (loop for i from (1+ y)
     85                    for tile = (gethash (list x i) map)
     86                    while tile
     87                    maximize i))))))
     88 
     89 (defparameter *wrap-map* (make-hash-table :test 'equal))
     90 
     91 (loop for i below 50
     92       do (flet ((m (x y dir nx ny ndir)
     93                   (setf (gethash (list x y dir) *wrap-map*) (list nx ny ndir))))
     94            (m 50 i 2 0 (- 149 i) 0)
     95            (m (+ 50 i) 0 3 0 (+ 150 i) 0)
     96 
     97            (m (+ 100 i) 0 3 i 199 3)
     98            (m 149 i 0 99 (- 149 i) 2)
     99            (m (+ 100 i) 49 1 99 (+ 50 i) 2)
    100 
    101            (m 50 (+ 50 i) 2 i 100 1)
    102            (m 99 (+ 50 i) 0 (+ 100 i) 49 3)
    103 
    104            (m 99 (+ 100 i) 0 149 (- 49 i) 2)
    105            (m (+ 50 i) 149 1 49 (+ 150 i) 2)
    106 
    107            (m 0 (+ 100 i) 2 50 (- 49 i) 0)
    108            (m i 100 3 50 (+ 50 i) 0)
    109 
    110            (m 0 (+ 150 i) 2 (+ 50 i) 0 1)
    111            (m 49 (+ 150 i) 0 (+ 50 i) 149 3)
    112            (m i 199 1 (+ 100 i) 0 1)))
    113 
    114 (defun wrap-cube (map pos last-pos dir)
    115   (declare (ignore map pos))
    116   (or (gethash (append last-pos (list dir))
    117                *wrap-map*)
    118       (error "Wrap result is null!")))
    119 
    120 (defun walk-map (map directions start-pos wrap-function)
    121   (loop with facing = 0
    122         with current-pos = start-pos
    123         for direction in directions
    124         if (numberp direction)
    125           do (loop repeat direction
    126                    for next-coord = (walk current-pos facing)
    127                    for next-facing = facing
    128                    for next-tile = (gethash next-coord map)
    129                    when (null next-tile)
    130                      do (let ((wrap (funcall wrap-function map next-coord current-pos facing)))
    131                           (setf next-coord (subseq wrap 0 2))
    132                           (when (> (length wrap) 2)
    133                             (setf next-facing (caddr wrap))))
    134                      and do (setf next-tile (gethash next-coord map))
    135                    never (eq next-tile :wall)
    136                    do (setf current-pos next-coord
    137                             facing next-facing))
    138         else
    139           do (setf facing (turn facing direction))
    140         finally (return (progn
    141                           (list (* 4 (1+ (car current-pos))) (* 1000 (1+ (cadr current-pos))) facing)
    142                           (+ (* 1000 (1+ (cadr current-pos)))
    143                              (* 4 (1+ (car current-pos)))
    144                              facing)))))
    145 
    146 (defun task1 (inputs)
    147   (multiple-value-bind (map directions start-pos)
    148       (parse-input inputs)
    149     (walk-map map directions start-pos #'wrap-around)))
    150 
    151 (defun task2 (inputs)
    152   (multiple-value-bind (map directions start-pos)
    153       (parse-input inputs)
    154     (walk-map map directions start-pos #'wrap-cube)))
    155 
    156 (define-day 22
    157     ()
    158   #'task1
    159   #'task2)