aoc-2022/common-lisp/day-8/solution.lisp

135 lines
5.0 KiB
Common Lisp
Executable File

#!/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: