135 lines
5 KiB
Common Lisp
135 lines
5 KiB
Common Lisp
|
#!/usr/bin/env -S sbcl --script
|
||
|
|
||
|
;; Copyright (C) 2022
|
||
|
;; This program is free software: you can redistribute it and/or modify
|
||
|
;; it under the terms of the GNU General Public License as published by
|
||
|
;; the Free Software Foundation, either version 3 of the License, or
|
||
|
;; (at your option) any later version.
|
||
|
|
||
|
;; This program is distributed in the hope that it will be useful,
|
||
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
;; GNU General Public License for more details.
|
||
|
|
||
|
;; You should have received a copy of the GNU General Public License
|
||
|
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
|
|
||
|
(require 'asdf)
|
||
|
(require 'uiop)
|
||
|
(require 'str)
|
||
|
(require 'iterate)
|
||
|
|
||
|
(defpackage :advent-of-code-day-8
|
||
|
(:use :cl :iterate))
|
||
|
|
||
|
(in-package :advent-of-code-day-8)
|
||
|
|
||
|
(defclass tree ()
|
||
|
((x
|
||
|
:initarg :x
|
||
|
:reader x)
|
||
|
(y
|
||
|
:initarg :y
|
||
|
:reader y)))
|
||
|
|
||
|
(defmacro make-tree (x y)
|
||
|
`(make-instance 'tree :x ,x :y ,y))
|
||
|
|
||
|
(defun scan-right? (trees position)
|
||
|
(iter (with width = (- (array-dimension trees 1) 1))
|
||
|
(with tree-height = (aref trees (y position) (x position)))
|
||
|
(for i from (+ (x position) 1) to width)
|
||
|
(for tree = (aref trees (y position) i))
|
||
|
(counting t into view-count)
|
||
|
(unless (< tree tree-height)
|
||
|
(return (cons :not-visible view-count)))
|
||
|
(finally (return (cons :visible view-count)))))
|
||
|
|
||
|
(defun scan-left? (trees position)
|
||
|
(iter (with tree-height = (aref trees (y position) (x position)))
|
||
|
(for i from (- (x position) 1) downto 0)
|
||
|
(for tree = (aref trees (y position) i))
|
||
|
(counting t into view-count)
|
||
|
(unless (< tree tree-height)
|
||
|
(return (cons :not-visible view-count)))
|
||
|
(finally (return (cons :visible view-count)))))
|
||
|
|
||
|
(defun scan-down? (trees position)
|
||
|
(iter (with height = (- (array-dimension trees 0) 1))
|
||
|
(with tree-height = (aref trees (y position) (x position)))
|
||
|
(for i from (+ (y position) 1) to height)
|
||
|
(for tree = (aref trees i (x position)))
|
||
|
(counting t into view-count)
|
||
|
(unless (< tree tree-height)
|
||
|
(return (cons :not-visible view-count)))
|
||
|
(finally (return (cons :visible view-count)))))
|
||
|
|
||
|
(defun scan-up? (trees position)
|
||
|
(iter (with tree-height = (aref trees (y position) (x position)))
|
||
|
(for i from (- (y position) 1) downto 0)
|
||
|
(for tree = (aref trees i (x position)))
|
||
|
(counting t into view-count)
|
||
|
(unless (< tree tree-height)
|
||
|
(return (cons :not-visible view-count)))
|
||
|
(finally (return (cons :visible view-count)))))
|
||
|
|
||
|
(defun tree-visible? (trees position)
|
||
|
(or (equal (car (scan-right? trees position)) :visible)
|
||
|
(equal (car (scan-left? trees position)) :visible)
|
||
|
(equal (car (scan-down? trees position)) :visible)
|
||
|
(equal (car (scan-up? trees position)) :visible)))
|
||
|
|
||
|
(defun scenic-score (trees tree)
|
||
|
(* (cdr (scan-right? trees tree))
|
||
|
(cdr (scan-left? trees tree))
|
||
|
(cdr (scan-down? trees tree))
|
||
|
(cdr (scan-up? trees tree))))
|
||
|
|
||
|
(defun trees-from-file-lines (lines)
|
||
|
(let* ((split-lines-into-digits (mapcar (lambda (line)
|
||
|
(str:split "" line :omit-nulls t))
|
||
|
lines))
|
||
|
(numbers (mapcar (lambda (row)
|
||
|
(mapcar 'parse-integer row))
|
||
|
split-lines-into-digits))
|
||
|
(x (length (nth 0 numbers)))
|
||
|
(y (length numbers)))
|
||
|
(make-array (list x y) :initial-contents numbers)))
|
||
|
|
||
|
(defun solution-part-1 (trees)
|
||
|
(iter (with width = (- (array-dimension trees 1) 1))
|
||
|
(with height = (- (array-dimension trees 0) 1))
|
||
|
(for y from 1 to (- height 1))
|
||
|
(sum (iter (for x from 1 to (- width 1))
|
||
|
(for tree = (make-instance 'tree :x x :y y))
|
||
|
(counting (tree-visible? trees tree)))
|
||
|
into visible-interior-trees)
|
||
|
(finally (return (+ visible-interior-trees (* width 2) (* height 2))))))
|
||
|
|
||
|
(defun solution-part-2 (trees)
|
||
|
(iter (with width = (- (array-dimension trees 1) 1))
|
||
|
(with height = (- (array-dimension trees 0) 1))
|
||
|
(for y from 1 to (- height 1))
|
||
|
(appending (iter (for x from 1 to (- width 1))
|
||
|
(for tree = (make-instance 'tree :x x :y y))
|
||
|
(collect (scenic-score trees tree)))
|
||
|
into scores)
|
||
|
(finally (return (let* ((sorted-scores (sort scores '>)))
|
||
|
(car sorted-scores))))))
|
||
|
|
||
|
(let ((trees (trees-from-file-lines (uiop:read-file-lines "example.txt"))))
|
||
|
(assert (= 21 (solution-part-1 trees))))
|
||
|
|
||
|
(let ((trees (trees-from-file-lines (uiop:read-file-lines "input.txt"))))
|
||
|
(assert (= 1736 (solution-part-1 trees))))
|
||
|
|
||
|
(let ((trees (trees-from-file-lines (uiop:read-file-lines "example.txt"))))
|
||
|
(assert (= 8 (solution-part-2 trees))))
|
||
|
|
||
|
(let ((trees (trees-from-file-lines (uiop:read-file-lines "input.txt"))))
|
||
|
(assert (= 268800 (solution-part-2 trees))))
|
||
|
|
||
|
;; Local Variables:
|
||
|
;; mode: lisp
|
||
|
;; End:
|