blob: cd0402f5b42d2d0bd6937f0fcbd387992d5d12d4 (
plain) (
tree)
|
|
(defstruct grid data dim0 dim1)
(defstruct point i j)
(defstruct pdir point dir)
(defun parse-grid (filespec)
(with-open-file (stream filespec)
(let ((lines (loop for line = (read-line stream nil)
while line
collect line)))
(make-grid :data (apply #'concatenate 'string lines)
:dim0 (length lines)
:dim1 (length (first lines))))))
(defun grid-character (grid i j)
(aref (grid-data grid) (+ (* i (grid-dim1 grid)) j)))
(defun grid-character-update (grid i j item)
(setf (aref (grid-data grid) (+ (* i (grid-dim1 grid)) j)) item))
(defun grid-point (grid item)
(let ((pos (position item (grid-data grid))))
(when pos
(multiple-value-bind (i j) (truncate pos (grid-dim1 grid))
(make-point :i i :j j)))))
(defun point-in-grid (point grid)
(and (and (>= (point-i point) 0) (< (point-i point) (grid-dim0 grid)))
(and (>= (point-j point) 0) (< (point-j point) (grid-dim1 grid)))))
(defun next-pdir (grid pdir)
(let* ((i (point-i (pdir-point pdir)))
(j (point-j (pdir-point pdir)))
(dir (pdir-dir pdir))
(next-point (cond ((= dir 0) (make-point :i (1- i) :j j)) ; up
((= dir 1) (make-point :i i :j (1+ j))) ; right
((= dir 2) (make-point :i (1+ i) :j j)) ; down
((= dir 3) (make-point :i i :j (1- j))))) ; left
(i (point-i next-point))
(j (point-j next-point)))
(when (point-in-grid next-point grid)
(let* ((next-char (grid-character grid i j))
(next-dir (cond ((equal next-char #\S) dir)
((= dir 0) (cond ((equal next-char #\7) 3)
((equal next-char #\F) 1)
((equal next-char #\|) dir)))
((= dir 1) (cond ((equal next-char #\7) 2)
((equal next-char #\J) 0)
((equal next-char #\-) dir)))
((= dir 2) (cond ((equal next-char #\L) 1)
((equal next-char #\J) 3)
((equal next-char #\|) dir)))
((= dir 3) (cond ((equal next-char #\L) 0)
((equal next-char #\F) 2)
((equal next-char #\-) dir))))))
(when next-dir
(make-pdir :point next-point :dir next-dir))))))
(defun grid-loop (grid start pdir &optional (count 0) visited)
(if (and (equalp start (pdir-point pdir)) (/= count 0))
visited
(let* ((visited (cons pdir visited))
(pdir (next-pdir grid pdir)))
(when pdir
;; Updating the grid for a quick visited check
(let* ((i (point-i (pdir-point pdir)))
(j (point-j (pdir-point pdir)))
(c (grid-character grid i j)))
(unless (equal c #\S)
(grid-character-update grid i j #\.)))
(grid-loop grid start pdir (1+ count) visited)))))
(defun solve1 (filespec)
(let* ((grid (parse-grid filespec))
(start (grid-point grid #\S))
(positions (or (grid-loop grid start (make-pdir :point start :dir 0))
(grid-loop grid start (make-pdir :point start :dir 1))
(grid-loop grid start (make-pdir :point start :dir 2))
(grid-loop grid start (make-pdir :point start :dir 3)))))
(ash (length positions) -1)))
(defun solve2 (filespec)
(let* ((grid (parse-grid filespec))
(start (grid-point grid #\S))
(positions (or (grid-loop grid start (make-pdir :point start :dir 0))
(grid-loop grid start (make-pdir :point start :dir 1))
(grid-loop grid start (make-pdir :point start :dir 2))
(grid-loop grid start (make-pdir :point start :dir 3)))))
(let* ((area (loop for cur in (append (cdr positions) (list (car positions)))
for prv in positions
as curi = (point-i (pdir-point cur))
as curj = (point-j (pdir-point cur))
as prvi = (point-i (pdir-point prv))
as prvj = (point-j (pdir-point prv))
sum (- (* prvi curj) (* prvj curi))))
(iarea (- (abs area) (length positions))))
(1+ (ash iarea -1)))))
(print (solve1 "data/10/example1.txt")) ;; 4
(print (solve1 "data/10/example2.txt")) ;; 8
(print (solve1 "data/10/input.txt")) ;; 6690
(print (solve2 "data/10/example3.txt")) ;; 4
(print (solve2 "data/10/example4.txt")) ;; 8
(print (solve2 "data/10/example5.txt")) ;; 10
(print (solve2 "data/10/input.txt")) ;; 525
|