aboutsummaryrefslogtreecommitdiff
path: root/src/2015.01.02-more-lispy-this-time.lisp
blob: cd82411d95e5b56ba148119fbd61cb3979adc3f5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
;;;; 2015.01.02-more-lispy-this-time.lisp
;;;; Advent of Code 2015
;;;; Day 1: Not Quite Lisp
;;;; Attempt 2: More Lispy This Time

;; ---------------------------------------------------------------------
;;; Package Definition
;; ---------------------------------------------------------------------

(defpackage :2015-01-02-more-lispy-this-time
  (:use #:common-lisp))
(in-package :2015-01-02-more-lispy-this-time)




;; ---------------------------------------------------------------------
;;; Definitions
;; ---------------------------------------------------------------------

(defconstant +PUZZLE-INPUT-FILE+ "~/proj/Learn/aoc/src/2015.01._PUZZLE-INPUT.txt"
  "File to be used as input to the program.")

(defconstant +PUZZLE-INPUT-STRING+ (uiop:read-file-string +PUZZLE-INPUT-FILE+)
  "String version of the text in `+PUZZLE-INPUT-FILE+'.")

(defconstant +PUZZLE-INPUT-LIST+ (loop for char across +PUZZLE-INPUT-STRING+
                                       collect char)
  "Puzzle input in lisp list form.")

(defconstant +PUZZLE-INPUT-VALUES-LIST+ (mapcar (lambda (INPUT-LIST)
                                                   (cond ((eql INPUT-LIST #\() 1)
                                                         ((eql INPUT-LIST #\)) -1)))
                                                 +PUZZLE-INPUT-LIST+)
  "Puzzle input converted into floor direction values.")




;; ---------------------------------------------------------------------
;;; Part 1
;; -------
;; Santa is trying to deliver presents in a large apartment building, but
;; he can't find the right floor - the directions he got are a little
;; confusing. He starts on the ground floor (floor 0) and then follows
;; the instructions one character at a time.
;;
;; An opening parenthesis, (, means he should go up one floor, and a
;; closing parenthesis, ), means he should go down one floor.
;;
;; The apartment building is very tall, and the basement is very deep;
;; he will never find the top or bottom floors.
;;
;; For example:
;;
;;     (()) and ()() both result in floor 0.
;;     ((( and (()(()( both result in floor 3.
;;     ))((((( also results in floor 3.
;;     ()) and ))( both result in floor -1 (the first basement level).
;;     ))) and )())()) both result in floor -3.
;;
;; To what floor do the instructions take Santa?
;; ---------------------------------------------------------------------

(defun final-floor (INPUT)
  "Calculate the final floor Santa ends up on given the provided `INPUT'."
  (apply #'+ INPUT))

(assert (= 138 (final-floor +PUZZLE-INPUT-VALUES-LIST+)))




;; ---------------------------------------------------------------------
;;; Part 2
;; -------
;; Now, given the same instructions, find the position of the first
;; character that causes him to enter the basement (floor -1). The first
;; character in the instructions has position 1, the second character
;; has position 2, and so on.
;;
;; For example:
;;
;;     ) causes him to enter the basement at character position 1.
;;     ()()) causes him to enter the basement at character position 5.
;;
;; What is the position of the character that causes Santa to first enter the basement?
;; ---------------------------------------------------------------------

(defun next-floor ()
  "Determine the result of the next button press, go in that direction, and destroy the information so the Nazis don't get their dirty hands on it."
  (let ((FLOOR-NUMBER 0)
        (INPUT-POSITION 0)
        (INPUT +PUZZLE-INPUT-VALUES-LIST+))
    (lambda ()
      (list (incf FLOOR-NUMBER (pop INPUT))
            (incf INPUT-POSITION)))))
(defvar next-floor (next-floor))

(defun first-basement-input ()
  "Determine the position of the input in `+PUZZLE-INPUT-VALUES-LIST' which results in the first entry into the basement (floor -1)."
  (let ((RESULT (funcall next-floor)))
    (loop until (= -1 (car RESULT))
          do (setf RESULT (funcall next-floor)))
    (cdr RESULT)))

;; Test for correct result
(assert (= 1771 (first-basement-input)))