advent-of-code/2018-12-12.lisp -rw-r--r-- 2.6 KiB View raw
                                                                                
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
109
(defpackage "AOC/12" (:use "CL"))
(in-package "AOC/12")

(defvar *test-input* "initial state: #..#.#..##......###...###

...## => #
..#.. => #
.#... => #
.#.#. => #
.#.## => #
.##.. => #
.#### => #
#.#.# => #
#.### => #
##.#. => #
##.## => #
###.. => #
###.# => #
####. => #")

(defvar *input* "initial state: #..######..#....#####..###.##..#######.####...####.##..#....#.##.....########.#...#.####........#.#.

#...# => .
##.## => .
###.. => .
.#### => .
#.#.# => .
##..# => #
..#.# => #
.##.. => #
##... => #
#..## => #
#..#. => .
.###. => #
#.##. => .
..### => .
.##.# => #
....# => .
##### => .
#.### => .
.#..# => .
#.... => .
...## => .
.#.## => .
##.#. => #
#.#.. => #
..... => .
.#... => #
...#. => #
..#.. => .
..##. => .
###.# => .
####. => .
.#.#. => .
")

(defun parse-input (stream)
  (let* ((line (read-line stream))
         (state (make-string (- (length line) 15)))
         (rules (make-hash-table :test 'equal)))
    (assert (string= (subseq line 0 15) "initial state: "))
    (replace state (subseq line 15))
    (read-line stream)
    (loop for line = (read-line stream nil)
          while line
          do (setf (gethash (subseq line 0 5) rules) (aref line 9)))
    (cons (cons 0 state)
          rules)))

(defun trim (state)
  (let ((offset (caar state))
        (pos (position #\# (cdar state) :test #'eql)))
    (cons (cons (+ offset pos) (subseq (cdar state) pos (1+ (position #\# (cdar state) :test #'eql :from-end t))))
          (cdr state))))

(defun turn (state)
  ;; This conses more than it should, but … it’s a puzzle, not
  ;; production code.
  (let* ((vector
           (replace
            (make-string (+ (length (cdar state)) 8) :initial-element #\.)
            (cdar state)
            :start1 4))
         (rules (cdr state))
         (new-vector (copy-seq vector)))
    (loop for i from 0 below (- (length new-vector) 5)
          do (setf (aref new-vector (+ i 2))
                   (gethash (subseq vector i (+ i 5)) rules #\.)))
    (trim (cons (cons (- (caar state) 4) new-vector) rules))))

(defun run (state turns)
  (dotimes (i turns state)
    (setf state (turn state))))

(defun solution-1 ()
  (with-input-from-string (s *input*)
    (let ((end (run (parse-input s) 20)))
      (loop for i from (caar end) and pot across (cdar end)
         when (char= pot #\#)
         sum i))))

(defun solution-2 ()
  ;; I cheated and just submitted 3150000000905
  (with-input-from-string (s *input*)
    (let ((end (run (parse-input s) 5000000000)))
      (loop for i from (caar end) and pot across (cdar end)
            when (char= pot #\#)
              sum i))))