advent-of-code/advent-of-code.org
2016-01-05 02:40:56 -05:00

127 KiB

Advent of Code

Day 1: Not Quite Lisp

Santa was hoping for a white Christmas, but his weather machine's "snow" function is powered by stars, and he's fresh out! To save Christmas, he needs you to collect fifty stars by December 25th.

Collect stars by helping Santa solve puzzles. Two puzzles will be made available on each day in the advent calendar; the second puzzle is unlocked when you complete the first. Each puzzle grants one star. Good luck!

Here's an easy puzzle to warm you up.

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 day1/parse-directions (directions)
    (seq-map
                   (lambda (char)
                     (cond ((eq char ?\() 1)
                           ((eq char ?\)) -1)
                           (t 0)))
                   directions))

  (seq-reduce #'+
              (day1/parse-directions input)
              0)
74

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 day1/steps-until (predicate reduce-fn sequence initial-value)
    (car (seq-reduce
          (lambda (acc next)
            (let ((counter (car acc))
                  (value (cdr acc)))
              (if (funcall predicate value) acc
                (cons (+ 1 counter)
                      (funcall reduce-fn value next)))))
          sequence
          (cons 0 initial-value))))

  (day1/steps-until
   (lambda (floor) (= floor -1))
   #'+
   (day1/parse-directions input)
   0)
1795

Day 2: I Was Told There Would Be No Math

The elves are running low on wrapping paper, and so they need to submit an order for more. They have a list of the dimensions (length l, width w, and height h) of each present, and only want to order exactly as much as they need.

Fortunately, every present is a box (a perfect right rectangular prism), which makes calculating the required wrapping paper for each gift a little easier: find the surface area of the box, which is 2*l*w + 2*w*h + 2*h*l. The elves also need a little extra paper for each present: the area of the smallest side.

For example:

  • A present with dimensions 2x3x4 requires 2*6 + 2*12 + 2*8 = 52 square feet of wrapping paper plus 6 square feet of slack, for a total of 58 square feet.
  • A present with dimensions 1x1x10 requires 2*1 + 2*10 + 2*10 = 42 square feet of wrapping paper plus 1 square foot of slack, for a total of 43 square feet.

All numbers in the elves' list are in feet. How many total square feet of wrapping paper should they order?


  20x3x11
  15x27x5
  6x29x7
  30x15x9
  19x29x21
  10x4x15
  1x26x4
  1x5x18
  10x15x23
  10x14x20
  3x5x18
  29x23x30
  7x4x10
  22x24x29
  30x1x2
  19x2x5
  11x9x22
  23x15x10
  11x11x10
  30x28x5
  22x5x4
  6x26x20
  16x12x30
  10x20x5
  25x14x24
  16x17x22
  11x28x26
  1x11x10
  1x24x15
  13x17x21
  30x3x13
  20x25x17
  22x12x5
  22x20x24
  9x2x14
  6x18x8
  27x28x24
  11x17x1
  1x4x12
  5x20x13
  24x23x23
  22x1x25
  18x19x5
  5x23x13
  8x16x4
  20x21x9
  1x7x11
  8x30x17
  3x30x9
  6x16x18
  22x25x27
  9x20x26
  16x21x23
  5x24x17
  15x17x15
  26x15x10
  22x16x3
  20x24x24
  8x18x10
  23x19x16
  1x21x24
  23x23x9
  14x20x6
  25x5x5
  16x3x1
  29x29x20
  11x4x26
  10x23x24
  29x25x16
  27x27x22
  9x7x22
  6x21x18
  25x11x19
  14x13x3
  15x28x17
  14x3x12
  29x8x19
  30x14x20
  20x23x4
  8x16x5
  4x11x18
  20x8x24
  21x13x21
  14x26x29
  27x4x17
  27x4x25
  5x28x6
  23x24x11
  29x22x5
  30x20x6
  23x2x10
  11x4x7
  27x23x6
  10x20x19
  8x20x22
  5x29x22
  16x13x2
  2x11x14
  6x12x4
  3x13x6
  16x5x18
  25x3x28
  21x1x5
  20x16x19
  28x30x27
  26x7x18
  25x27x24
  11x19x7
  21x19x17
  2x12x27
  20x5x14
  8x5x8
  6x24x8
  7x28x20
  3x20x28
  5x20x30
  13x29x1
  26x29x5
  19x28x25
  5x19x11
  11x20x22
  4x23x1
  19x25x12
  3x10x6
  3x14x10
  28x16x12
  23x12x2
  23x12x19
  20x28x10
  9x10x25
  16x21x16
  1x18x20
  9x4x26
  3x25x8
  17x16x28
  9x28x16
  27x3x12
  17x24x12
  13x21x10
  7x17x13
  6x10x9
  7x29x25
  11x19x30
  1x24x5
  20x16x23
  24x28x21
  6x29x19
  25x2x19
  12x5x26
  25x29x12
  16x28x22
  26x26x15
  9x13x5
  10x29x7
  1x24x16
  22x2x2
  6x16x13
  3x12x28
  4x12x13
  14x27x21
  14x23x26
  7x5x18
  8x30x27
  15x9x18
  26x16x5
  3x29x17
  19x7x18
  16x18x1
  26x15x30
  24x30x21
  13x20x7
  4x12x10
  27x20x11
  28x29x21
  20x14x30
  28x12x3
  19x1x8
  4x8x6
  21x14x2
  27x19x21
  17x24x14
  15x18x11
  18x7x26
  25x28x29
  27x26x9
  18x12x17
  24x28x25
  13x24x14
  26x9x28
  9x3x30
  9x2x9
  8x1x29
  18x30x10
  18x14x5
  26x8x30
  12x1x1
  30x5x28
  26x17x21
  10x10x10
  20x7x27
  13x17x6
  21x13x17
  2x16x8
  7x9x9
  15x26x4
  11x28x25
  10x6x19
  21x6x29
  15x5x6
  28x9x16
  14x3x10
  12x29x5
  22x19x19
  25x15x22
  30x6x28
  11x23x13
  20x25x14
  26x1x13
  6x14x15
  16x25x17
  28x4x13
  10x24x25
  4x13x10
  9x15x16
  15x24x6
  22x9x19
  11x11x8
  4x19x12
  24x5x4
  27x12x13
  7x27x16
  2x6x9
  29x27x15
  18x26x23
  19x16x15
  14x5x25
  9x16x30
  4x6x4
  13x10x10
  1x8x29
  23x5x17
  19x20x20
  11x27x24
  27x15x5
  15x11x12
  21x11x3
  1x13x22
  17x8x8
  13x14x14
  17x22x7
  9x5x8
  2x6x3
  25x9x15
  11x8x13
  9x25x12
  3x16x12
  12x16x8
  16x24x17
  4x6x26
  22x29x11
  14x17x19
  28x2x27
  24x22x19
  22x20x30
  23x28x4
  16x12x14
  22x24x22
  29x1x28
  26x29x16
  3x25x30
  27x3x13
  22x24x26
  25x3x2
  7x24x2
  10x5x3
  28x8x29
  25x6x4
  12x17x14
  24x3x5
  23x27x7
  26x23x30
  11x10x19
  23x7x11
  26x14x15
  14x3x25
  12x24x14
  2x14x12
  9x12x16
  9x2x28
  3x8x2
  22x6x9
  2x30x2
  25x1x9
  20x11x2
  14x11x12
  7x14x12
  24x8x26
  13x21x23
  18x17x23
  13x6x17
  20x20x19
  13x17x29
  7x24x24
  23x8x6
  19x10x28
  3x8x21
  15x20x18
  11x27x1
  11x24x28
  13x20x11
  18x19x22
  27x22x12
  28x3x2
  13x4x29
  26x5x6
  14x29x25
  7x4x7
  5x17x7
  2x8x1
  22x30x24
  22x21x28
  1x28x13
  11x20x4
  25x29x19
  9x23x4
  30x6x11
  25x18x10
  28x10x24
  3x5x20
  19x28x10
  27x19x2
  26x20x4
  19x21x6
  2x12x30
  8x26x27
  11x27x10
  14x13x17
  4x3x21
  2x20x21
  22x30x3
  2x23x2
  3x16x12
  22x28x22
  3x23x29
  8x25x15
  9x30x4
  10x11x1
  24x8x20
  10x7x27
  7x22x4
  27x13x17
  5x28x5
  30x15x13
  10x8x17
  8x21x5
  8x17x26
  25x16x4
  9x7x25
  13x11x20
  6x30x9
  15x14x12
  30x1x23
  5x20x24
  22x7x6
  26x11x23
  29x7x5
  13x24x28
  22x20x10
  18x3x1
  15x19x23
  28x28x20
  7x26x2
  9x12x20
  15x4x6
  1x17x21
  3x22x17
  9x4x20
  25x19x5
  9x11x22
  14x1x17
  14x5x16
  30x5x18
  19x6x12
  28x16x22
  13x4x25
  29x23x18
  1x27x3
  12x14x4
  10x25x19
  15x19x30
  11x30x4
  11x22x26
  13x25x2
  17x13x27
  11x30x24
  15x1x14
  17x18x4
  26x11x3
  16x22x28
  13x20x9
  1x18x3
  25x11x12
  20x21x1
  22x27x4
  8x28x23
  7x13x27
  17x9x26
  27x27x20
  11x20x12
  26x21x11
  29x14x12
  27x25x1
  28x29x25
  21x23x28
  5x18x18
  19x5x4
  7x6x30
  27x8x11
  12x24x12
  16x25x22
  26x11x29
  25x22x17
  15x23x23
  17x9x6
  30x10x16
  21x3x5
  18x27x2
  28x21x14
  16x18x17
  4x18x2
  9x1x14
  9x1x9
  5x27x12
  8x16x30
  3x19x19
  16x26x24
  1x6x9
  15x14x3
  11x7x19
  8x19x3
  17x26x26
  6x18x11
  19x12x4
  29x20x16
  20x17x23
  6x6x5
  20x30x19
  18x25x18
  2x26x2
  3x1x1
  14x25x18
  3x1x6
  11x14x18
  17x23x27
  25x29x9
  6x25x20
  20x10x9
  17x5x18
  29x14x8
  14x25x26
  10x15x29
  23x19x11
  22x2x2
  4x5x5
  13x23x25
  19x13x19
  20x18x6
  30x7x28
  26x18x17
  29x18x10
  30x29x1
  12x26x24
  18x17x26
  29x28x15
  3x12x20
  24x10x8
  30x15x6
  28x23x15
  14x28x11
  10x27x19
  14x8x21
  24x1x23
  1x3x27
  6x15x6
  8x25x26
  13x10x25
  6x9x8
  10x29x29
  26x23x5
  14x24x1
  25x6x22
  17x11x18
  1x27x26
  18x25x23
  20x15x6
  2x21x28
  2x10x13
  12x25x14
  2x14x23
  30x5x23
  29x19x21
  29x10x25
  14x22x16
  17x11x26
  12x17x30
  8x17x7
  20x25x28
  20x11x30
  15x1x12
  13x3x24
  16x23x23
  27x3x3
  26x3x27
  18x5x12
  12x26x7
  19x27x12
  20x10x28
  30x12x25
  3x14x10
  21x26x1
  24x26x26
  7x21x30
  3x29x12
  29x28x5
  5x20x7
  27x11x2
  15x20x4
  16x15x15
  19x13x7
  7x17x15
  27x24x15
  9x17x28
  20x21x14
  14x29x29
  23x26x13
  27x23x21
  18x13x6
  26x16x21
  18x26x27
  9x3x12
  30x18x24
  12x11x29
  5x15x1
  1x16x3
  14x28x11
  2x18x1
  19x18x19
  18x28x21
  2x3x14
  22x16x5
  28x18x28
  24x16x18
  7x4x10
  19x26x19
  24x17x7
  25x9x6
  25x17x7
  20x22x20
  3x3x7
  23x19x15
  21x27x21
  1x23x11
  9x19x4
  22x4x18
  6x15x5
  15x25x2
  23x11x20
  27x16x6
  27x8x5
  10x10x19
  22x14x1
  7x1x29
  8x11x17
  27x9x27
  28x9x24
  17x7x3
  26x23x8
  7x6x30
  25x28x2
  1x30x25
  3x18x18
  28x27x15
  14x14x1
  10x25x29
  18x12x9
  20x28x16
  26x27x22
  8x26x1
  21x2x12
  25x16x14
  21x19x5
  12x9x22
  16x5x4
  5x4x16
  25x29x3
  4x29x13
  15x16x29
  8x11x24
  30x11x20
  17x21x14
  12x24x10
  10x12x6
  3x26x30
  15x14x25
  20x12x21
  13x11x16
  15x13x3
  5x17x29
  6x3x23
  9x26x11
  30x1x8
  14x10x30
  18x30x10
  13x19x19
  16x19x17
  28x7x10
  28x29x4
  3x21x10
  4x28x24
  7x28x9
  2x4x9
  25x27x13
  6x12x15
  4x18x20
  20x1x16
  5x13x24
  11x11x10
  12x9x23
  1x9x30
  17x28x24
  9x5x27
  21x15x16
  17x4x14
  8x14x4
  13x10x7
  17x12x14
  9x19x19
  2x7x21
  8x24x23
  19x5x12
  11x23x21
  13x3x1
  5x27x15
  12x25x25
  13x21x16
  9x17x11
  1x15x21
  4x26x17
  11x5x15
  23x10x15
  12x17x21
  27x15x1
  4x29x14
  5x24x25
  10x10x12
  18x12x9
  11x24x23
  24x23x3
  28x12x15
  29x9x14
  11x25x8
  5x12x2
  26x26x29
  9x21x2
  8x8x25
  1x16x30
  17x29x20
  9x22x13
  7x18x16
  3x3x23
  26x25x30
  15x23x24
  20x23x5
  20x16x10
  23x7x8
  20x18x26
  8x27x6
  30x23x23
  7x7x24
  21x11x15
  1x30x25
  26x27x22
  30x28x13
  20x13x13
  3x1x15
  16x7x1
  7x25x15
  12x7x18
  16x9x23
  16x12x18
  29x5x2
  17x7x7
  21x17x5
  9x9x17
  26x16x10
  29x29x23
  17x26x10
  5x19x17
  1x10x1
  14x21x20
  13x6x4
  13x13x3
  23x4x18
  4x16x3
  16x30x11
  2x11x2
  15x30x15
  20x30x22
  18x12x16
  23x5x16
  6x14x15
  9x4x11
  30x23x21
  20x7x12
  7x18x6
  15x6x5
  18x22x19
  16x10x22
  26x20x25
  9x25x25
  29x21x10
  9x21x24
  7x18x21
  14x3x15
  18x19x19
  4x29x17
  14x10x9
  2x26x14
  13x3x24
  4x4x17
  6x27x24
  2x18x3
  14x25x2
  30x14x17
  11x6x14
  4x10x18
  15x4x2
  27x7x10
  13x24x1
  7x12x6
  25x22x26
  19x2x18
  23x29x2
  2x15x4
  12x6x9
  16x14x29
  9x17x3
  21x9x12
  23x18x22
  10x8x4
  29x2x7
  19x27x15
  4x24x27
  25x20x14
  8x23x19
  1x24x19
  6x20x10
  15x8x5
  18x28x5
  17x23x22
  9x16x13
  30x24x4
  26x3x13
  12x22x18
  29x17x29
  26x4x16
  15x7x20
  9x15x30
  12x7x18
  28x19x18
  11x23x23
  24x20x1
  20x3x24
  1x26x1
  14x10x6
  5x27x24
  13x21x12
  20x20x5
  6x28x9
  11x26x11
  26x29x12
  21x4x11
  20x11x17
  22x27x20
  19x11x21
  2x11x11
  13x5x7
  12x10x25
  21x28x1
  15x30x17
  28x19x1
  4x19x12
  11x4x12
  4x10x30
  11x18x5
  22x20x12
  3x7x27
  20x26x4
  13x27x26
  23x14x13
  4x19x7
  26x27x16
  20x5x20
  18x5x8
  19x21x1
  22x8x1
  29x4x1
  24x10x15
  24x9x20
  10x3x8
  29x30x3
  2x8x24
  16x7x18
  2x11x23
  23x15x16
  21x12x6
  24x28x9
  6x1x13
  14x29x20
  27x24x13
  16x26x8
  5x6x17
  21x8x1
  28x19x21
  1x14x16
  18x2x9
  29x28x10
  22x26x27
  18x26x23
  22x24x2
  28x26x1
  27x29x12
  30x13x11
  1x25x5
  13x30x18
  3x13x22
  22x10x11
  2x7x7
  18x17x8
  9x22x26
  30x18x16
  10x2x3
  7x27x13
  3x20x16
  9x21x16
  1x18x15
  21x30x30
  4x25x23
  3x11x7
  5x6x12
  27x1x20
  13x15x24
  23x29x2
  13x5x24
  22x16x15
  28x14x3
  29x24x9
  2x20x4
  30x10x4
  23x7x20
  22x12x21
  3x19x11
  4x28x28
  5x4x7
  28x12x25
  2x16x26
  23x20x7
  5x21x29
  9x21x16
  9x6x10
  9x6x4
  24x14x29
  28x11x6
  10x22x1
  21x30x20
  13x17x8
  2x25x24
  19x21x3
  28x8x14
  6x29x28
  27x10x28
  30x11x12
  17x2x10
  14x19x17
  2x11x4
  26x1x2
  13x4x4
  23x20x18
  2x17x21
  28x7x15
  3x3x27
  24x17x30
  28x28x20
  21x5x29
  13x12x19
  24x29x29
  19x10x6
  19x12x14
  21x4x17
  27x16x1
  4x17x30
  23x23x18
  23x15x27
  26x2x11
  12x8x8
  15x23x26
  30x17x15
  17x17x15
  24x4x30
  9x9x10
  14x25x20
  25x11x19
  20x7x1
  9x21x3
  7x19x9
  10x6x19
  26x12x30
  21x9x20
  15x11x6
  30x21x9
  10x18x17
  22x9x8
  8x30x26
  28x12x27
  17x17x7
  11x13x8
  5x3x21
  24x1x29
  1x28x2
  18x28x10
  8x29x14
  26x26x27
  17x10x25
  22x30x3
  27x9x13
  21x21x4
  30x29x16
  22x7x20
  24x10x2
  16x29x17
  28x15x17
  19x19x22
  9x8x6
  26x23x24
  25x4x27
  16x12x2
  11x6x18
  19x14x8
  9x29x13
  23x30x19
  10x16x1
  4x21x28
  23x25x25
  19x9x16
  30x11x12
  24x3x9
  28x19x4
  18x12x9
  7x1x25
  28x7x1
  24x3x12
  30x24x22
  27x24x26
  9x30x30
  29x10x8
  4x6x18
  10x1x15
  10x4x26
  23x20x16
  6x3x14
  30x8x16
  25x14x20
  11x9x3
  15x23x25
  8x30x22
  22x19x18
  25x1x12
  27x25x7
  25x23x3
  13x20x8
  5x30x7
  18x19x27
  20x23x3
  1x17x21
  21x21x27
  13x1x24
  7x30x20
  21x9x18
  23x26x6
  22x9x29
  17x6x21
  28x28x29
  19x25x26
  9x27x21
  5x26x8
  11x19x1
  10x1x18
  29x4x8
  21x2x22
  14x12x8
  (defun day2/surface-area (w h l)
    "Calculate the surface area of a box."
    (+ (* 2 l w)
       (* 2 w h)
       (* 2 h l)))

  (defun day2/slack (w h l)
    "Find the area of the smallest side of a box.

  The smallest side is the side with the smallest area."
    (min (* l w)
         (* w h)
         (* h l)))

  (defun day2/wrapping-paper (w h l)
    "Find the area of wrapping paper needed to wrap a box."
    (+ (day2/surface-area w h l)
       (day2/slack w h l)))

  (ert-deftest day2/wrapping-paper ()
    (should (eq 58 (day2/wrapping-paper 2 3 4)))
    (should (eq 43 (day2/wrapping-paper 1 1 10))))

  (defun day2/parse-dimensions (dimension-string)
    "Parse a string representing the dimensions of a box separated
  by the character 'x' into a list of integers."
    (seq-map #'string-to-int
             (split-string dimension-string "x")))

  (defun day2/sum-list (input)
    (seq-reduce
     #'+
     (seq-map (lambda (dimension-string)
                (let ((dimensions (day2/parse-dimensions dimension-string)))
                  (eval (cons 'day2/wrapping-paper dimensions))))
              (split-string input))
     0))

  (ert-deftest day2/sum-list ()
    (let ((test-data (string-join '("2x3x4" "1x1x10") "\n")))
      (should (eq (+ 58 43)
                  (day2/sum-list test-data)))))

  (day2/sum-list input)
1606483

Part 2

The elves are also running low on ribbon. Ribbon is all the same width, so they only have to worry about the length they need to order, which they would again like to be exact.

The ribbon required to wrap a present is the shortest distance around its sides, or the smallest perimeter of any one face. Each present also requires a bow made out of ribbon as well; the feet of ribbon required for the perfect bow is equal to the cubic feet of volume of the present. Don't ask how they tie the bow, though; they'll never tell.

For example:

  • A present with dimensions 2x3x4 requires 2+2+3+3 = 10 feet of ribbon to wrap the present plus 2*3*4 = 24 feet of ribbon for the bow, for a total of 34 feet.
  • A present with dimensions 1x1x10 requires 1+1+1+1 = 4 feet of ribbon to wrap the present plus 1*1*10 = 10 feet of ribbon for the bow, for a total of 14 feet.

How many total feet of ribbon should they order?


  (defun day2/smallest-perimeter (w h l)
    (min (* 2 (+ l w))
         (* 2 (+ w h))
         (* 2 (+ h l))))

  (defun day2/volume (w h l)
    (* w h l))

  (defun day2/ribbon (w h l)
    (+ (day2/smallest-perimeter w h l)
       (day2/volume w h l)))

  (ert-deftest day2/ribbon ()
    (should (eq 34 (day2/ribbon 2 3 4)))
    (should (eq 14 (day2/ribbon 1 1 10))))

  (defun day2/sum-ribbon (input)
    (seq-reduce
     #'+
     (seq-map (lambda (dimension-string)
                (let ((dimensions (day2/parse-dimensions dimension-string)))
                  (eval (cons 'day2/ribbon dimensions))))
              (split-string input))
     0))

  (day2/sum-ribbon input)
3842356

Day 3: Perfectly Spherical Houses in a Vacuum

Santa is delivering presents to an infinite two-dimensional grid of houses.

He begins by delivering a present to the house at his starting location, and then an elf at the North Pole calls him via radio and tells him where to move next. Moves are always exactly one house to the north (^), south (v), east (>), or west (<). After each move, he delivers another present to the house at his new location.

However, the elf back at the north pole has had a little too much eggnog, and so his directions are a little off, and Santa ends up visiting some houses more than once. How many houses receive at least one present?

For example:

  • > delivers presents to 2 houses: one at the starting location, and one to the east.
  • ^>v< delivers presents to 4 houses in a square, including twice to the house at his starting/ending location.
  • ^v^v^v^v^v delivers a bunch of presents to some very lucky children at only 2 houses.

  >^^v^<>v<<<v<v^>>v^^^<v<>^^><^<<^vv>>>^<<^>><vv<<v^<^^><>>><>v<><>^^<^^^<><>>vv>vv>v<<^>v<>^>v<v^<>v>><>^v<<<<v^vv^><v>v^>>>vv>v^^^<^^<>>v<^^v<>^<vv^^<^><<>^>><^<>>><><vv><>v<<<><><>v><<>^^^^v>>^>^<v<<vv^^<v<^<^>^^v^^^^^v<><^v><<><^v^>v<<>^<>^^v^<>v<v^>v>^^<vv^v><^<>^v<><^><v^><><><<<<>^vv^>^vvvvv><><^<vv^v^v>v<<^<^^v^<>^<vv><v<v^v<<v<<^^>>^^^v^>v<><^vv<<^<>v<v><><v^^><v<>^^>^^>v^>^<<<<v><v<<>v><^v>^>><v^^<^>v<vvvv<>>>>>^v^^>v<v<^<vv>^>^vv^>vv^^v<<^<^^<>v>vv^v>><>>>v^>^>^^v<>^<v<<>^vv>v^<<v>v<<><v>^vvv<v<vvv^v<vv<v^^^>v><<^<>><v^^>^v^>>^v<^<><v<>>v^<>>v<>>v^^^><^>>vvvv>^v<^><<>>^<>^>vv><v<<>>^^>v^^^><^<<^^v>v<^<<>v>^^vvv^v^>v^<>^^<>v^v>v>v<v^>vv>^^v<>v>>^<>><>v>v^<<vvvv<vvv><v^<^>^v<>>^><v>><>^<v>v<v>vv^>>vvv<>v>v<v^>>^>>v<<>^<>^<>>>^v<<<^<^v>vv^>><<><v^>^v^^^v<>^^vv><>><>>^>v^<v<>v<>>^<<^v>^^^<>^v^><>v<<v>vv^>vv<<>>><<^v^<>v<vv>>>^^<>^><<^>vv>>^<<v^^vv<>>><v>v><^<v<<>>>^^<>>^<^v><>vv^^^v>vvv>^><<>^^>^<<v^<v<^v<<>vvv<^<<>^>^v<vv<^>vvv>v>vv^<v^><>>^vv<^^^vv><^vv<v^<><v^vvv><<^>^^><v<<vv^>v<vv<v>^<>^v<<>v<v^v^>^>^>v<<^vvv<<<v>^^>^<<<<>vv>>^<>^>>>v<v>^^<v^<v<>>>vv>^^v<<>>>^^v><<<v<v<^v<>^^><v<^v<<v^><><^<><v<^^v>>><v^^v<<v^><^<><<v^>><^<>v>v^<><^<v>^v^>^>^vv^>^^<<vv^>vv<^vvv<>>^^<^>v^>^>^<v^><v<v>>>v<<<><^v<<><^<vv^v^^^>v<^^<v^vvv<v<><v<vv<^vv<>vv<v^<>>vvvvv<<>^v^v>vv>>>vvv^^<^<^<><>v<v>><^v><^<<<>><<<v>^>v<>^>^v>>^<>v^<^>><<>^<v>^>^^^>^^<v>>>><>^v^v><<<<vv^<vv<>vv>v<>v^<v^>v><>>>v^<><^vvv>vv^<^<<^<^^v>^>>>v<^<^v^^<^<^>>><v>vv>^<<><>^>>v>^<<>><^<>v<>vv^^>^>vvv^v<<^<^^<vv<>^vvv<^^v^vv^>>v<^>^^<v^<>v<^<^vv>v<<vv>vv>^>vvv>>>^^>v<>^v>v^<^>>v>^^v>>>>v^<v>v<^>v<v<<>>^v<^^<v><^<>>^<<vv^>>v<<v>^v<>><^>vv<v<^>>^^<vvvvvvvvv>>>v<v<>v^<>>^vv<v^^v<<^vvv^<<^><>vv<><<>>v>vv^><>>^^v^>>v^v^><<<>>^^<^v<<^<>>>>^<^>v^><<^>v<^v<^>>^^<<<<><^<^v^v<>>^v<^<<vv^<><^^vv><v^v^v>^>>^>^vv^>^v<v^v<<vvv^><>>^v^^><>v>vv><^>>vv<vvv<<<<^<>vvv^v<v>^<v<^>^<^<v<><>v^^^^<<vv<^^vv<v>><<v^><>>><v^>^v><^>^><vv^<><^<v>><<^vv<>>v^<<v<>v><v<><><vv>^>>v^<^<v>^><>>><^><v^v<>>>^^<^>v<v>vvv<>^<<><v^^>^>>v<^v>^>v>>>vv>v>>v^^^<^<vvv^<>^>^<v^<v^v>v>^>vv>vvv<>v<^>v>^^>>^<vv^^v>v^^^^^v^vv><^<><>^>vv<^>>^vvvv^^^>^<vv>^v<<^><^^>^<>^^>^<<v<^>>>^><<^^>v^v>>^>vvvv>^^v><v>>vv><<<vv<^>v>^^^<v>v^vvv<^><<^>^<>^><<<<<v^<<vv^v>^<>v<v>^>^>><>v^v<^vv^^>vv<<v^v>vv^vvv<<<<>^v<v^^v^v>v<<v>^^<>^vv^^>^>^v^vv^>>v^vv^^<vv><<v^v^^v><vv<^vvv<vv^^<<v>v^v^^^^v<^<^>v>^>v>^vv^v^^<v<^vvvv<<<>^<^^^<^^<>^<><vv<^^<<^>>><v^vvvv>^<>>^^>v^^v^<<v^^^<<<><^<v^v^^v<v^<>v><<v<>^v>v<^><^>vv^^<vvv<^v>>v>^<><v^><^^^<v^>>vv<<<<<^<>^v^v>^vv^<>v>v<^>vv<<^vv>vv<v<><>>v>><v<^<^^>><<v^v<<^><v<^<vv<v<<vv^>^<<><^^>^<^>>^<vv>><v<<vvv<^^v^>^^<^v>^v<v<>v><v^v^<<^<><<v<<^v>v<<>>^>v>>v>>v<^<<^<^>>>v>^^^v><^>^^>>v<<>^v><v>vvv^vv<<<>vvv<<>^>>>v<v<v^<^<^>^<^>v^^v<^^<v<>v<>>^^>^v^>v<<<<^<>v^><<<v>>>><<v^<^vv>v>><>>^<<<^<^^>v<>>v<>vv<<^<<><<^>v^^^vv^>vvvv>>v>v^><<v<>vv^<<><<vvv>^>>>^<<<^<^<<v>^>v<>>v>>vv^^><<<<^^^v>><<^><v><v^^><v<<v^^v^^v>>v<><><<>^><v><^<vv>><^v<>v<vvv<>^>><v>>v<^><<v>^<>^v><^><^^<v>^><^^v^<<><>>^>v^<^v^vv<><^>vv^>v^vvv^<>>^><^<^<>^<<v^v<^v><>^v<v>>^>>^v^vv>><vv><v^^<<^v^<>^v<<>^><^>><v>>v<<<v^^vv<>^^v>>><><><<v^<<<v^<^^><v^>v^^vv<v^<>>vv^<^v<>^v>>v^v>v<^^vv><>^v<<>v^<>v^>>v>vvv<^><><^^>^vv^>>v^>^<^^<><>><<>^^^><^v^v><<<><<^v^vv>v>><^>>><v^>v<v><><v^v<>v^^>>v<<>v>v<v<v<^^<><>v^^<>>v<^v<v>v<><v<v>^<<>v>vv^^<>>^^^<>^^>^v>v>>>^v^v><v^^<><v>^^v^v<^<^^><<v<^<^<>^<>><<>^>>^>^^><v><>v<><>><<<>>>>vv>>>^>>^v<^>v^^^v<<vv>><<<^<<<>>>>>^>vv<^v^<>^<v^>^v><v>vvv<>>>^v^^^v<<<<>>^^<vv<^<^^>^<>v<^<<<>><>>v<^<>^<vvv<^<>><><<v>^^^>^^<<v<v^>^^v^>><<^vv><v>^v>>^<v>v>^^>^v>^vvv<>v^v^^<><vv>vv^>>><>v<^><v<v^<><<<>^v>^v<<<^>^>^>v^v<<><vvv<<v^^<><v>^>>><vv>><v>>v^<vv>>vv<<^v^v<<><^v<vv>>>vv<>>>>^vv>v^<>vv>v^v<v^><v<^^^^^>vv<><<vvv^<v><^<vv><^^^vv^<>^^^^<^><^<>v^<v^v<<^v<<^^<>>^<v^^>>>vv<vvv<>v<<>><^vvv^<<^^<<>>>^<>>>v^^><>><<>><v^v>>>>>><>>><v^<<vvv^>v<>>v^<>vv<><^^^^v^<<^<v^vv><<^^>v<^vvv^v>>v>^>>v>^^><<v^<>v<>vv<^v^vv><v><<vv^v>>v^>>v<^^^>^><<v<>^><>v>>>vvv<v<vv<^>>^v<v>^<^^^^^v><>v><>v^v^v<v^vv^v>vvvv<>vv<<<vv<v<<>^<^>^^v^<<>^<v><^><v<v<><<>v^<<^<><vv>v<<^v>>^v<><v>^>>^^><>v^<^<vvv^>^>^<<<<>vv>^v^v<^^^<vv>><>^^<<v<^<^^>>>v^v<<^^^<v<v<^<>^v<v><v^vv^^v^^v^^<vv<>^<><vv^<^v^<<^><<vvv>^^<^^^<^v>^>^vv><<<^v<v>vv>v<>v^v<v^>v^>>>v^v<>^v<<>^vv>v>v>v^<^>v^^<^>^^^^vv>^^><^>vv^>>^^v>><<<<^><>v<>^<v<vv^>^^><<^><v>v^>^^<^>>><>><v^v<v^<v<vv^v^<<^<vvv>>><vv<^^>>^>^><<v^<>>v>v^v^^><<>vv^v>v^<v><^<>^^<^>v>^<><<<v>^<^<^>^>^>^^v^<<^^v^^<^<>><^>v>>^^<>^^^<<<<v^>^v<^vv>^<<<v<><<v<>vv>>>v><>>><>>v<<<vv><>^v>v<^>><^><><v<>^v^>^v>^v<<><<^<>>v>^><>^>><>><^<v^><v^^<><v><^^>^v^^<>v^<v^<^v<v^^^^^v^<<^>^^^<^v><>^^<<<><<<<<^^>v^vvvv>v<>>vv<^>^v^>v<^vv^v<<><<v>v^v>^^><><^<v^>v><vv><>>><<>^vv<>v>>v<^v>>>v<v>v>v>^vv<<>^^vv<v<^v^<v<v>vv<>^<^<vv<v^<^v^^><<>^>><^v>vv^^v<<^^><<>v^^<><><v^^<v^v>^>^>^>v<^<v>^v^^>v<>vvv<^v<v^v><<v^><<^^><^<<v^v^>v<>^>v><><v>^<v<v>^<^^^>^v<<><<><>vv>v^<>v^><v^v<v><><<v>v<vv><<v>>v>^<<<>vv>>vvv>^^vv^v^^<^^<>v^^<>v>>^^>^>^>v>><^>><>>^<<>><^>v<<<<<<<^v^v<v^<v^^>^<><<v<^>v^>v^vv<<^^vv^>>>>^<>v<^v<>v<vv<^>>v^vv>vv><vv<<^>v>><vv>>>vv^<<<<vv^>v<<<<^^>^^v^><<^<v^>v^>^^<v<>vvv^>^<>vvv<v<^^>v^<<v>><>v<v<>^^<vvv>^>vv><><<<^^vv<v^<v<>v<>><<v><^vv^>^<^>^^^<<<v>vv^<^<<>^>^<vv>v><v<<^><^>^^<vv^v^^>>>>vv^><^^vv><>^<v^v>v<vv>v><<<v>v<v>^><v^^><v>v<^v^>>^^<v^>^^>vv>>vv^><^vv^vv<<^>vv>^v<v><vv><v<vvvvv>^^v^v><v>>>^vv<>v>^^^^<^>><>^v^^^>v<^^<<^^v<vv<>vvv<^>><><^>>^><^<>v<v<<><<v><v^v<>><^>v><<v^<v>v<^<vv^v^v^>vvv^^>v>^<vv^>v^v^<>v>^>>vv>><^^<v<<>^vv<><><<^v<v>v<<vv><>><^v<v>>v^>vvv^v^<<^><v<>^vv^>v^<v<^>>v<v><v><v>>^<<<v^<><<>v>^>^^<v<>>^<>^>^><<<^<<^<<^>^v>>><vvv>><<<<v>>>>>>>^<^v<^>v<>vv<><>v>>^>>^>vv^^><<^<v<v>>^^<<^>v<^>>vv>^<>v><^>v<vv>>>>>>^v<^<<<v^><vv<<>>vv<<><v<><<<v<^<v<>>v<^^^^v^^<^^^<^<vv><<^>><>v<<>v<v<>>>><>v^vv>^>^>>vv^v<v<<><^v>vv^><v<<>v^v<^>vv<<^^v><^>>^^vv<^<>>v^^>><v>^v>>>^>>v>v<>v<^vv><>^<<^>vv>>><><>v^><>v^>v>v><^v<><v<v>^v<<^vv^><^^>><^^^<<<^>v>^v>>><^>><^>>>^^^<^>vv<><<<v^>^<^^>>^^^v^v^v>v<v>>>><^>>>v>^vv<<^^^<^^vv>v<<><v<<^^>v>><<v^^><^>^<^>^v^>v><^<^vv>v>><>^<<vv<<v>v<vv<v>^>^>><^^<v>^v^v<><<>vvv<^<v>^><>^>vvv>>>^><<>><v^^<^<<^v>>^v<v<vv>vv^v^>v<<vvv<^^v^v>^<^>>^>v<^>^v<<><<<^>^<^^^>vv<^^^^vv<v<^^v<<<<v<^v^<><v<<^><<>vv>>><^<^<>>>^>^>>^<<<<<^^v>^>^<>vvv^^<^><^>^^v>^vv^><v^<^<<v^<vvv<<^v<><^><^>>>v>^v>^>^v<vv^v>><v><^><v^^>v^>^<><<><>v<v^>vvv^>^>>v<>^><^>^><vvv>^^v^v>v<>^v^><^>>v>v^><<<^>>^<>^<>>v><>>v^>^>^^<>>v^>^<vvvv<^vvvv^>>vv^<v^v>^vv<>v<>^<v<v>v>^^><^>vv^<^v^<<^<^<><vv<^v<^v><>>>^v^<<^><^>vv<v>v<^>vv^>v<<<>^<><v<^^^>v><^^<>^<^<v^vv^<<^>><<v^v<^vvv<<<>>vvvv^v^^^>v<>>><<>vvv<<^^^>v>v>>v<<v<v^v^>^^v>^><^<><<v^<v<v^^^><>v^^^<v>vv<>^>^^vv>^<<^v<^v><v>>>^>>><^<<>^v>>^>vv<<<v<>^<v><v^<^<>v>v^^v^>><<^v<<<<>v>v>v^^<^><>^^<<<v>vv<>>>^>>v<><v^>^<><vv>v>v^v<v^<^>>^>><<^^<^^v<vv<>><<<v<^<<^^^>vvv^<vvv<^>vv><>><<<^<v^v^^<<^vvv^^<^<><<>^<^<>>vvv<>^<>v^v<><>>v^v><<>>>vvv>v<>^>>^><^>vv<<>>v<<^><>v>>^^<v>^>^<<>><^<<vv<^<vv^vv><>>>><^<v>^>vv<v><>^<>vvvvv^vv<<v<>>>^<<><>^^vvv>>>vv<<^^><^v^^v<>^^>^><^>v^^^^v<^<<vv<vv<>vv^^>v^vv>v><>>vv>^<^<v^v^>>v^v^^v>^>vv^>v<vvvv<^v<^v>^v>^^v<<^>^^<<>^><^v>>>vv^>^^>vvvv>>v<^<v>^>>>v^<><^<^^<v>vv^^><v>v^<>^^^>>><^^v>v>^<<>^<v^>vvv^>^^^><v<^>>v<v>>^v><<><<>v<^<<>^><>^>vv>^<v>^^v<<^v^vvv^^>^vv^<^>^>^^v>v^>^<<><<^>v>>vv^vv><v>>^<<^<v^^<^<v^^vv^><^^<^^><v^^>v^^^<^<>^<>>^v<^vvv^^v^<><^>>>>>v><><<<>vv<^v>><<>vvv<><<vv<<<^>v^^>>^>^v>><><^^v<>><>>v^>^<vv><<<>><><<v>^^<>>v<><^<vv>vv<^v>^<<<<v<^<<^^>>^<><^>><<>^>v>^^^v>>^<^^v><v^v>^><<><>>^>>^<<v<>^v<>^>^<v>>vv>^vvv<<v<<^>^>^<<^^<>^^^^vvv<>^vv<vvvvv^^>^^<^>>><>v^<><^<<^>v^^v<>>^vv<>v^^<>>v^vvvvv<<v^<v^^>>><vvvvv>><^>vv>v^v^<v<^>^^><^>^^^^v<><^v<<>v^>v>>vv<<>^<v^^>vvv>^^<v^<>vv^><>><v^^v<>^>>^>v><>>^^v>^>^>>>^>v<^v>v>^<^^^^^>>v<v<>>v<<^>^<v<<>^^>><<^><>v<>^^^vv<>^^>><<^^>v>vv>vv>v^>^v>v^^<>>><<v><v<<>>v><>vvv^^v>^^>^vvvv^>^<>^vvvv><v><v<>>><>^<^vv<>^v<^v<>^vvv<<>><vvv^>>^><<vv^<v^>^<v<<^^>^^<^^v^>v<>v^v><>><v^^>>^vvv><^vv>v^<^<^v>>v^^>^vvv^<v^^v^^>v<^<>>^<>>>^^<><^^vv<>^vv^<>>>>^^<<^^<>vv^^><>^^<v<<v>^<v^^>^v<><><>vvv>^v^>>vv<<^v<<>><v>^><^>>>^<^<^^>vv^<<^<>>^^><><<v>^^<v>>v<<vvvv>^v^vv>><^^<<^>>v>v<^^^<^><^^vv>^vv<^<vv<>v><^<><v><^^^>>^<><^<v>>>>v^<v>>>>>v<><^^>v<^<^>><v<>^>vv>^^v^v^<<v<><<<^v^><<^<><<<<v<^>><<<>v>>vv><vv<><<^<^<><vv>^^^^<>v<<<<v>vv<>vv^^^>><>vv^><>>^vv<<><^^vv<>v^>>^<<>^<v^<^>v<
  (defun day3/make-coord (x y)
    (cons x y))

  (defun day3/coord-x (coord)
    (car coord))

  (defun day3/coord-y (coord)
    (cdr coord))

  (defun day3/add-coords (a b)
    (day3/make-coord
     (+ (day3/coord-x a)
        (day3/coord-x b))
     (+ (day3/coord-y a)
        (day3/coord-y b))))

  (defun day3/arrow-to-coord (arrow)
    (cond ((eq arrow ?>) (day3/make-coord 1 0))
          ((eq arrow ?<) (day3/make-coord -1 0))
          ((eq arrow ?^) (day3/make-coord 0 1))
          ((eq arrow ?v) (day3/make-coord 0 -1))
          (t (day3/make-coord 0 0))))

  (defun day3/make-map ()
    (make-hash-table :test #'equal))

  (defun day3/map-visit (map coord)
    (puthash coord
             (+ 1 (gethash coord map 0))
             map))

  (defun day3/deliver (directions)
    (let ((map (day3/make-map)))
      (day3/map-visit map (day3/make-coord 0 0))
      (cdr (seq-reduce
            (lambda (acc next)
              (let* ((loc (car acc))
                     (map (cdr acc))
                     (next-loc (day3/add-coords loc
                                                (day3/arrow-to-coord next))))
                (day3/map-visit map next-loc)
                (cons next-loc map)))
            directions
            (cons (day3/make-coord 0 0)
                  map)))))

  (defun day3/map-count-visited (map)
    (hash-table-count map))

  (ert-deftest day3/map-count-visited ()
    (should (eq 2 (day3/map-count-visited
                   (day3/deliver ">"))))
    (should (eq 4 (day3/map-count-visited
                   (day3/deliver "^>v<"))))
    (should (eq 2 (day3/map-count-visited
                   (day3/deliver "^v^v^v^v^v")))))

  (day3/map-count-visited
   (day3/deliver input))
2592

Part 2

The next year, to speed up the process, Santa creates a robot version of himself, Robo-Santa, to deliver presents with him.

Santa and Robo-Santa start at the same location (delivering two presents to the same starting house), then take turns moving based on instructions from the elf, who is eggnoggedly reading from the same script as the previous year.

This year, how many houses receive at least one present?

For example:

  • ^v delivers presents to 3 houses, because Santa goes north, and then Robo-Santa goes south.
  • ^>v< now delivers presents to 3 houses, and Santa and Robo-Santa end up back where they started.
  • ^v^v^v^v^v now delivers presents to 11 houses, with Santa going one direction and Robo-Santa going the other.

  (require 'dash)

  (defun day3/alternate (count sequence)
    (->> (-zip (seq-into sequence 'list)
               (number-sequence 1 (seq-length sequence)))
         (-group-by (lambda (x) (mod (cdr x) count)))
         (-map (lambda (x) (-map #'car (cdr x))))))

  (defun day3/map-visit-n (map coord times)
    (puthash coord
             (+ times (gethash coord map 0))
             map))

  (defun day3/map-visits (map coord)
    (gethash coord map 0))

  (defun day3/map-locations (map)
    (hash-table-keys map))

  (defun day3/map-merge (a &rest maps)
    (-map (lambda (map)
            (-map (lambda (coord)
                    (day3/map-visit-n a coord (day3/map-visits map coord)))
                  (day3/map-locations map)))
          maps)
    a)

  (defun day3/deliver-with-robosanta (directions)
    (let* ((alternated (day3/alternate 2 (string-to-list directions)))
           (santa-directions (car alternated))
           (robot-directions (cadr alternated)))
      (day3/map-merge
       (day3/deliver santa-directions)
       (day3/deliver robot-directions))))

  (ert-deftest day3/deliver-with-robosanta ()
    (should (eq 3 (day3/map-count-visited
                   (day3/deliver-with-robosanta "^v"))))
    (should (eq 3 (day3/map-count-visited
                   (day3/deliver-with-robosanta "^>v<"))))
    (should (eq 11 (day3/map-count-visited
                    (day3/deliver-with-robosanta "^v^v^v^v^v")))))

  (day3/map-count-visited
   (day3/deliver-with-robosanta input))
2360

Day 4: The Ideal Stocking Stuffer

Santa needs help mining some AdventCoins (very similar to bitcoins) to use as gifts for all the economically forward-thinking little girls and boys.

To do this, he needs to find MD5 hashes which, in hexadecimal, start with at least five zeroes. The input to the MD5 hash is some secret key (your puzzle input, given below) followed by a number in decimal. To mine AdventCoins, you must find Santa the lowest positive number (no leading zeroes: 1, 2, 3, …) that produces such a hash.

For example:

  • If your secret key is abcdef, the answer is 609043, because the MD5 hash of abcdef609043 starts with five zeroes (000001dbbfa...), and it is the lowest such number to do so.
  • If your secret key is pqrstuv, the lowest number it combines with to make an MD5 hash starting with five zeroes is 1048970; that is, the MD5 hash of pqrstuv1048970 looks like 000006136ef....

  ckczppom
  (defun day4/mine-hash (key n)
    (md5 (format "%s%d" key n)))

  (defun day4/adventcoin-hash-p (hash)
    (string-equal
     "00000"
     (substring hash 0 5)))

  (defun day4/first-adventcoin (secret)
    (loop for x from 0
          while (not (day4/adventcoin-hash-p (day4/mine-hash secret x)))
          count x))

  (ert-deftest day4/first-adventcoin ()
    (should (eq 609043 (day4/first-adventcoin "abcdef")))
    (should (eq 1048970 (day4/first-adventcoin "pqrstuv"))))

  (day4/first-adventcoin (string-trim input))
117946

Part 2

Now find one that starts with six zeroes.


  (defun day4/adventcoin-hash-6-p (n hash)
    (string-equal
     "000000"
     (substring hash 0 6)))

  (defun day4/first-adventcoin-n (n secret)
    (loop for x from 0
          while (not (day4/adventcoin-hash-6-p n (day4/mine-hash secret x)))
          count x))

  (day4/first-adventcoin-n 6 (string-trim input))
3938038

Day 5: Doesn't He Have Intern-Elves For This?

Santa needs help figuring out which strings in his text file are naughty or nice.

A nice string is one with all of the following properties:

  • It contains at least three vowels (aeiou only), like aei, xazegov, or aeiouaeiouaeiou.
  • It contains at least one letter that appears twice in a row, like xx, abcdde (dd), or aabbccdd (aa, bb, cc, or dd).
  • It does not contain the strings ab, cd, pq, or xy, even if they are part of one of the other requirements.

For example:

  • ugknbfddgicrmopn is nice because it has at least three vowels (u...i...o...), a double letter (...dd...), and none of the disallowed substrings.
  • aaa is nice because it has at least three vowels and a double letter, even though the letters used by different rules overlap.
  • jchzalrnumimnmhp is naughty because it has no double letter.
  • haegwjzuvuyypxyu is naughty because it contains the string xy.
  • =dvszwmarrgswjxmb- is naughty because it contains only one vowel.

How many strings are nice?


  sszojmmrrkwuftyv
  isaljhemltsdzlum
  fujcyucsrxgatisb
  qiqqlmcgnhzparyg
  oijbmduquhfactbc
  jqzuvtggpdqcekgk
  zwqadogmpjmmxijf
  uilzxjythsqhwndh
  gtssqejjknzkkpvw
  wrggegukhhatygfi
  vhtcgqzerxonhsye
  tedlwzdjfppbmtdx
  iuvrelxiapllaxbg
  feybgiimfthtplui
  qxmmcnirvkzfrjwd
  vfarmltinsriqxpu
  oanqfyqirkraesfq
  xilodxfuxphuiiii
  yukhnchvjkfwcbiq
  bdaibcbzeuxqplop
  ivegnnpbiyxqsion
  ybahkbzpditgwdgt
  dmebdomwabxgtctu
  ibtvimgfaeonknoh
  jsqraroxudetmfyw
  dqdbcwtpintfcvuz
  tiyphjunlxddenpj
  fgqwjgntxagidhah
  nwenhxmakxqkeehg
  zdoheaxqpcnlhnen
  tfetfqojqcdzlpbm
  qpnxkuldeiituggg
  xwttlbdwxohahwar
  hjkwzadmtrkegzye
  koksqrqcfwcaxeof
  wulwmrptktliyxeq
  gyufbedqhhyqgqzj
  txpunzodohikzlmj
  jloqfuejfkemcrvu
  amnflshcheuddqtc
  pdvcsduggcogbiia
  yrioavgfmeafjpcz
  uyhbtmbutozzqfvq
  mwhgfwsgyuwcdzik
  auqylgxhmullxpaa
  lgelzivplaeoivzh
  uyvcepielfcmswoa
  qhirixgwkkccuzlp
  zoonniyosmkeejfg
  iayfetpixkedyana
  ictqeyzyqswdskiy
  ejsgqteafvmorwxe
  lhaiqrlqqwfbrqdx
  ydjyboqwhfpqfydc
  dwhttezyanrnbybv
  edgzkqeqkyojowvr
  rmjfdwsqamjqehdq
  ozminkgnkwqctrxz
  bztjhxpjthchhfcd
  vrtioawyxkivrpiq
  dpbcsznkpkaaclyy
  vpoypksymdwttpvz
  hhdlruwclartkyap
  bqkrcbrksbzcggbo
  jerbbbnxlwfvlaiw
  dwkasufidwjrjfbf
  kkfxtjhbnmqbmfwf
  vmnfziwqxmioukmj
  rqxvcultipkecdtu
  fhmfdibhtjzkiqsd
  hdpjbuzzbyafqrpd
  emszboysjuvwwvts
  msyigmwcuybfiooq
  druyksfnbluvnwoh
  fvgstvynnfbvxhsx
  bmzalvducnqtuune
  lzwkzfzttsvpllei
  olmplpvjamynfyfd
  padcwfkhystsvyfb
  wjhbvxkwtbfqdilb
  hruaqjwphonnterf
  bufjobjtvxtzjpmj
  oiedrjvmlbtwyyuy
  sgiemafwfztwsyju
  nsoqqfudrtwszyqf
  vonbxquiiwxnazyl
  yvnmjxtptujwqudn
  rrnybqhvrcgwvrkq
  taktoxzgotzxntfu
  quffzywzpxyaepxa
  rfvjebfiddcfgmwv
  iaeozntougqwnzoh
  scdqyrhoqmljhoil
  bfmqticltmfhxwld
  brbuktbyqlyfpsdl
  oidnyhjkeqenjlhd
  kujsaiqojopvrygg
  vebzobmdbzvjnjtk
  uunoygzqjopwgmbg
  piljqxgicjzgifso
  ikgptwcjzywswqnw
  pujqsixoisvhdvwi
  trtuxbgigogfsbbk
  mplstsqclhhdyaqk
  gzcwflvmstogdpvo
  tfjywbkmimyyqcjd
  gijutvhruqcsiznq
  ibxkhjvzzxgavkha
  btnxeqvznkxjsgmq
  tjgofgauxaelmjoq
  sokshvyhlkxerjrv
  ltogbivktqmtezta
  uduwytzvqvfluyuf
  msuckpthtgzhdxan
  fqmcglidvhvpirzr
  gwztkqpcwnutvfga
  bsjfgsrntdhlpqbx
  xloczbqybxmiopwt
  orvevzyjliomkkgu
  mzjbhmfjjvaziget
  tlsdxuhwdmghdyjb
  atoecyjhwmznaewi
  pyxpyvvipbqibiox
  ajbfmpqqobfsmesj
  siknbzefjblnohgd
  eqfhgewbblwdfkmc
  opylbscrotckkrbk
  lbwxbofgjkzdxkle
  ceixfjstaptdomvm
  hnkrqxifjmmjktie
  aqykzeuzvvetoygd
  fouahjimfcisxima
  prkzhutbqsyrhjzx
  qqwliakathnsbzne
  sayhgqtlcqqidqhj
  ygduolbysehdudra
  zricvxhdzznuxuce
  ucvzakslykpgsixd
  udirhgcttmyspgsb
  yuwzppjzfsjhhdzi
  gtqergjiuwookwre
  xvxexbjyjkxovvwf
  mlpaqhnnkqxrmwmm
  ezuqbrjozwuqafhb
  mcarusdthcbsonoq
  weeguqeheeiigrue
  pngtfugozxofaqxv
  copphvbjcmfspenv
  jiyahihykjjkdaya
  gdqnmesvptuyrfwp
  vbdscfywqmfxbohh
  crtrfuxyjypzubrg
  seihvevtxywxhflp
  fvvpmgttnapklwou
  qmqaqsajmqwhetpk
  zetxvrgjmblxvakr
  kpvwblrizaabmnhz
  mwpvvzaaicntrkcp
  clqyjiegtdsswqfm
  ymrcnqgcpldgfwtm
  nzyqpdenetncgnwq
  cmkzevgacnmdkqro
  kzfdsnamjqbeirhi
  kpxrvgvvxapqlued
  rzskbnfobevzrtqu
  vjoahbfwtydugzap
  ykbbldkoijlvicbl
  mfdmroiztsgjlasb
  quoigfyxwtwprmdr
  ekxjqafwudgwfqjm
  obtvyjkiycxfcdpb
  lhoihfnbuqelthof
  eydwzitgxryktddt
  rxsihfybacnpoyny
  bsncccxlplqgygtw
  rvmlaudsifnzhcqh
  huxwsyjyebckcsnn
  gtuqzyihwhqvjtes
  zreeyomtngvztveq
  nwddzjingsarhkxb
  nuqxqtctpoldrlsh
  wkvnrwqgjooovhpf
  kwgueyiyffudtbyg
  tpkzapnjxefqnmew
  ludwccvkihagvxal
  lfdtzhfadvabghna
  njqmlsnrkcfhtvbb
  cajzbqleghhnlgap
  vmitdcozzvqvzatp
  eelzefwqwjiywbcz
  uyztcuptfqvymjpi
  aorhnrpkjqqtgnfo
  lfrxfdrduoeqmwwp
  vszpjvbctblplinh
  zexhadgpqfifcqrz
  ueirfnshekpemqua
  qfremlntihbwabtb
  nwznunammfexltjc
  zkyieokaaogjehwt
  vlrxgkpclzeslqkq
  xrqrwfsuacywczhs
  olghlnfjdiwgdbqc
  difnlxnedpqcsrdf
  dgpuhiisybjpidsj
  vlwmwrikmitmoxbt
  sazpcmcnviynoktm
  pratafauetiknhln
  ilgteekhzwlsfwcn
  ywvwhrwhkaubvkbl
  qlaxivzwxyhvrxcf
  hbtlwjdriizqvjfb
  nrmsononytuwslsa
  mpxqgdthpoipyhjc
  mcdiwmiqeidwcglk
  vfbaeavmjjemfrmo
  qzcbzmisnynzibrc
  shzmpgxhehhcejhb
  wirtjadsqzydtyxd
  qjlrnjfokkqvnpue
  dxawdvjntlbxtuqc
  wttfmnrievfestog
  eamjfvsjhvzzaobg
  pbvfcwzjgxahlrag
  omvmjkqqnobvnzkn
  lcwmeibxhhlxnkzv
  uiaeroqfbvlazegs
  twniyldyuonfyzqw
  wgjkmsbwgfotdabi
  hnomamxoxvrzvtew
  ycrcfavikkrxxfgw
  isieyodknagzhaxy
  mgzdqwikzullzyco
  mumezgtxjrrejtrs
  nwmwjcgrqiwgfqel
  wjgxmebfmyjnxyyp
  durpspyljdykvzxf
  zuslbrpooyetgafh
  kuzrhcjwbdouhyme
  wyxuvbciodscbvfm
  kbnpvuqwmxwfqtqe
  zddzercqogdpxmft
  sigrdchxtgavzzjh
  lznjolnorbuddgcs
  ycnqabxlcajagwbt
  bnaudeaexahdgxsj
  rlnykxvoctfwanms
  jngyetkoplrstfzt
  tdpxknwacksotdub
  yutqgssfoptvizgr
  lzmqnxeqjfnsxmsa
  iqpgfsfmukovsdgu
  qywreehbidowtjyz
  iozamtgusdctvnkw
  ielmujhtmynlwcfd
  hzxnhtbnmmejlkyf
  ftbslbzmiqkzebtd
  bcwdqgiiizmohack
  dqhfkzeddjzbdlxu
  mxopokqffisxosci
  vciatxhtuechbylk
  khtkhcvelidjdena
  blatarwzfqcapkdt
  elamngegnczctcck
  xeicefdbwrxhuxuf
  sawvdhjoeahlgcdr
  kmdcimzsfkdfpnir
  axjayzqlosrduajb
  mfhzreuzzumvoggr
  iqlbkbhrkptquldb
  xcvztvlshiefuhgb
  pkvwyqmyoazocrio
  ajsxkdnerbmhyxaj
  tudibgsbnpnizvsi
  cxuiydkgdccrqvkh
  cyztpjesdzmbcpot
  nnazphxpanegwitx
  uphymczbmjalmsct
  yyxiwnlrogyzwqmg
  gmqwnahjvvdyhnfa
  utolskxpuoheugyl
  mseszdhyzoyavepd
  ycqknvbuvcjfgmlc
  sknrxhxbfpvpeorn
  zqxqjetooqcodwml
  sesylkpvbndrdhsy
  fryuxvjnsvnjrxlw
  mfxusewqurscujnu
  mbitdjjtgzchvkfv
  ozwlyxtaalxofovd
  wdqcduaykxbunpie
  rlnhykxiraileysk
  wgoqfrygttlamobg
  kflxzgxvcblkpsbz
  tmkisflhativzhde
  owsdrfgkaamogjzd
  gaupjkvkzavhfnes
  wknkurddcknbdleg
  lltviwincmbtduap
  qwzvspgbcksyzzmb
  ydzzkumecryfjgnk
  jzvmwgjutxoysaam
  icrwpyhxllbardkr
  jdopyntshmvltrve
  afgkigxcuvmdbqou
  mfzzudntmvuyhjzt
  duxhgtwafcgrpihc
  tsnhrkvponudumeb
  sqtvnbeiigdzbjgv
  eczmkqwvnsrracuo
  mhehsgqwiczaiaxv
  kaudmfvifovrimpd
  lupikgivechdbwfr
  mwaaysrndiutuiqx
  aacuiiwgaannunmm
  tjqjbftaqitukwzp
  lrcqyskykbjpaekn
  lirrvofbcqpjzxmr
  jurorvzpplyelfml
  qonbllojmloykjqe
  sllkzqujfnbauuqp
  auexjwsvphvikali
  usuelbssqmbrkxyc
  wyuokkfjexikptvv
  wmfedauwjgbrgytl
  sfwvtlzzebxzmuvw
  rdhqxuechjsjcvaf
  kpavhqkukugocsxu
  ovnjtumxowbxduts
  zgerpjufauptxgat
  pevvnzjfwhjxdoxq
  pmmfwxajgfziszcs
  difmeqvaghuitjhs
  icpwjbzcmlcterwm
  ngqpvhajttxuegyh
  mosjlqswdngwqsmi
  frlvgpxrjolgodlu
  eazwgrpcxjgoszeg
  bbtsthgkjrpkiiyk
  tjonoglufuvsvabe
  xhkbcrofytmbzrtk
  kqftfzdmpbxjynps
  kmeqpocbnikdtfyv
  qjjymgqxhnjwxxhp
  dmgicrhgbngdtmjt
  zdxrhdhbdutlawnc
  afvoekuhdboxghvx
  hiipezngkqcnihty
  bbmqgheidenweeov
  suprgwxgxwfsgjnx
  adeagikyamgqphrj
  zzifqinoeqaorjxg
  adhgppljizpaxzld
  lvxyieypvvuqjiyc
  nljoakatwwwoovzn
  fcrkfxclcacshhmx
  ownnxqtdhqbgthch
  lmfylrcdmdkgpwnj
  hlwjfbvlswbzpbjr
  mkofhdtljdetcyvp
  synyxhifbetzarpo
  agnggugngadrcxoc
  uhttadmdmhidpyjw
  ohfwjfhunalbubpr
  pzkkkkwrlvxiuysn
  kmidbxmyzkjrwjhu
  egtitdydwjxmajnw
  civoeoiuwtwgbqqs
  dfptsguzfinqoslk
  tdfvkreormspprer
  zvnvbrmthatzztwi
  ffkyddccrrfikjde
  hrrmraevdnztiwff
  qaeygykcpbtjwjbr
  purwhitkmrtybslh
  qzziznlswjaussel
  dfcxkvdpqccdqqxj
  tuotforulrrytgyn
  gmtgfofgucjywkev
  wkyoxudvdkbgpwhd
  qbvktvfvipftztnn
  otckgmojziezmojb
  inxhvzbtgkjxflay
  qvxapbiatuudseno
  krpvqosbesnjntut
  oqeukkgjsfuqkjbb
  prcjnyymnqwqksiz
  vuortvjxgckresko
  orqlyobvkuwgathr
  qnpyxlnazyfuijox
  zwlblfkoklqmqzkw
  hmwurwtpwnrcsanl
  jzvxohuakopuzgpf
  sfcpnxrviphhvxmx
  qtwdeadudtqhbely
  dbmkmloasqphnlgj
  olylnjtkxgrubmtk
  nxsdbqjuvwrrdbpq
  wbabpirnpcsmpipw
  hjnkyiuxpqrlvims
  enzpntcjnxdpuqch
  vvvqhlstzcizyimn
  triozhqndbttglhv
  fukvgteitwaagpzx
  uhcvukfbmrvskpen
  tizcyupztftzxdmt
  vtkpnbpdzsaluczz
  wodfoyhoekidxttm
  otqocljrmwfqbxzu
  linfbsnfvixlwykn
  vxsluutrwskslnye
  zbshygtwugixjvsi
  zdcqwxvwytmzhvoo
  wrseozkkcyctrmei
  fblgtvogvkpqzxiy
  opueqnuyngegbtnf
  qxbovietpacqqxok
  zacrdrrkohfygddn
  gbnnvjqmkdupwzpq
  qgrgmsxeotozvcak
  hnppukzvzfmlokid
  dzbheurndscrrtcl
  wbgdkadtszebbrcw
  fdmzppzphhpzyuiz
  bukomunhrjrypohj
  ohodhelegxootqbj
  rsplgzarlrknqjyh
  punjjwpsxnhpzgvu
  djdfahypfjvpvibm
  mlgrqsmhaozatsvy
  xwktrgyuhqiquxgn
  wvfaoolwtkbrisvf
  plttjdmguxjwmeqr
  zlvvbwvlhauyjykw
  cigwkbyjhmepikej
  masmylenrusgtyxs
  hviqzufwyetyznze
  nzqfuhrooswxxhus
  pdbdetaqcrqzzwxf
  oehmvziiqwkzhzib
  icgpyrukiokmytoy
  ooixfvwtiafnwkce
  rvnmgqggpjopkihs
  wywualssrmaqigqk
  pdbvflnwfswsrirl
  jeaezptokkccpbuj
  mbdwjntysntsaaby
  ldlgcawkzcwuxzpz
  lwktbgrzswbsweht
  ecspepmzarzmgpjm
  qmfyvulkmkxjncai
  izftypvwngiukrns
  zgmnyjfeqffbooww
  nyrkhggnprhedows
  yykzzrjmlevgffah
  mavaemfxhlfejfki
  cmegmfjbkvpncqwf
  zxidlodrezztcrij
  fseasudpgvgnysjv
  fupcimjupywzpqzp
  iqhgokavirrcvyys
  wjmkcareucnmfhui
  nftflsqnkgjaexhq
  mgklahzlcbapntgw
  kfbmeavfxtppnrxn
  nuhyvhknlufdynvn
  nviogjxbluwrcoec
  tyozixxxaqiuvoys
  kgwlvmvgtsvxojpr
  moeektyhyonfdhrb
  kahvevmmfsmiiqex
  xcywnqzcdqtvhiwd
  fnievhiyltbvtvem
  jlmndqufirwgtdxd
  muypbfttoeelsnbs
  rypxzbnujitfwkou
  ubmmjbznskildeoj
  ofnmizdeicrmkjxp
  rekvectjbmdnfcib
  yohrojuvdexbctdh
  gwfnfdeibynzjmhz
  jfznhfcqdwlpjull
  scrinzycfhwkmmso
  mskutzossrwoqqsi
  rygoebkzgyzushhr
  jpjqiycflqkexemx
  arbufysjqmgaapnl
  dbjerflevtgweeoj
  snybnnjlmwjvhois
  fszuzplntraprmbj
  mkvaatolvuggikvg
  zpuzuqygoxesnuyc
  wnpxvmxvllxalulm
  eivuuafkvudeouwy
  rvzckdyixetfuehr
  qgmnicdoqhveahyx
  miawwngyymshjmpj
  pvckyoncpqeqkbmx
  llninfenrfjqxurv
  kzbjnlgsqjfuzqtp
  rveqcmxomvpjcwte
  bzotkawzbopkosnx
  ktqvpiribpypaymu
  wvlzkivbukhnvram
  uohntlcoguvjqqdo
  ajlsiksjrcnzepkt
  xsqatbldqcykwusd
  ihbivgzrwpmowkop
  vfayesfojmibkjpb
  uaqbnijtrhvqxjtb
  hhovshsfmvkvymba
  jerwmyxrfeyvxcgg
  hncafjwrlvdcupma
  qyvigggxfylbbrzt
  hiiixcyohmvnkpgk
  mmitpwopgxuftdfu
  iaxderqpceboixoa
  zodfmjhuzhnsqfcb
  sthtcbadrclrazsi
  bkkkkcwegvypbrio
  wmpcofuvzemunlhj
  gqwebiifvqoeynro
  juupusqdsvxcpsgv
  rbhdfhthxelolyse
  kjimpwnjfrqlqhhz
  rcuigrjzarzpjgfq
  htxcejfyzhydinks
  sxucpdxhvqjxxjwf
  omsznfcimbcwaxal
  gufmtdlhgrsvcosb
  bssshaqujtmluerz
  uukotwjkstgwijtr
  kbqkneobbrdogrxk
  ljqopjcjmelgrakz
  rwtfnvnzryujwkfb
  dedjjbrndqnilbeh
  nzinsxnpptzagwlb
  lwqanydfirhnhkxy
  hrjuzfumbvfccxno
  okismsadkbseumnp
  sfkmiaiwlktxqvwa
  hauwpjjwowbunbjj
  nowkofejwvutcnui
  bqzzppwoslaeixro
  urpfgufwbtzenkpj
  xgeszvuqwxeykhef
  yxoldvkyuikwqyeq
  onbbhxrnmohzskgg
  qcikuxakrqeugpoa
  lnudcqbtyzhlpers
  nxduvwfrgzaailgl
  xniuwvxufzxjjrwz
  ljwithcqmgvntjdj
  awkftfagrfzywkhs
  uedtpzxyubeveuek
  bhcqdwidbjkqqhzl
  iyneqjdmlhowwzxx
  kvshzltcrrururty
  zgfpiwajegwezupo
  tkrvyanujjwmyyri
  ercsefuihcmoaiep
  ienjrxpmetinvbos
  jnwfutjbgenlipzq
  bgohjmrptfuamzbz
  rtsyamajrhxbcncw
  tfjdssnmztvbnscs
  bgaychdlmchngqlp
  kfjljiobynhwfkjo
  owtdxzcpqleftbvn
  ltjtimxwstvzwzjj
  wbrvjjjajuombokf
  zblpbpuaqbkvsxye
  gwgdtbpnlhyqspdi
  abipqjihjqfofmkx
  nlqymnuvjpvvgova
  avngotmhodpoufzn
  qmdyivtzitnrjuae
  xfwjmqtqdljuerxi
  csuellnlcyqaaamq
  slqyrcurcyuoxquo
  dcjmxyzbzpohzprl
  uqfnmjwniyqgsowb
  rbmxpqoblyxdocqc
  ebjclrdbqjhladem
  ainnfhxnsgwqnmyo
  eyytjjwhvodtzquf
  iabjgmbbhilrcyyp
  pqfnehkivuelyccc
  xgjbyhfgmtseiimt
  jwxyqhdbjiqqqeyy
  gxsbrncqkmvaryln
  vhjisxjkinaejytk
  seexagcdmaedpcvh
  lvudfgrcpjxzdpvd
  fxtegyrqjzhmqean
  dnoiseraqcoossmc
  nwrhmwwbykvwmgep
  udmzskejvizmtlce
  hbzvqhvudfdlegaa
  cghmlfqejbxewskv
  bntcmjqfwomtbwsb
  qezhowyopjdyhzng
  todzsocdkgfxanbz
  zgjkssrjlwxuhwbk
  eibzljqsieriyrzr
  wamxvzqyycrxotjp
  epzvfkispwqynadu
  dwlpfhtrafrxlyie
  qhgzujhgdruowoug
  girstvkahaemmxvh
  baitcrqmxhazyhbl
  xyanqcchbhkajdmc
  gfvjmmcgfhvgnfdq
  tdfdbslwncbnkzyz
  jojuselkpmnnbcbb
  hatdslkgxtqpmavj
  dvelfeddvgjcyxkj
  gnsofhkfepgwltse
  mdngnobasfpewlno
  qssnbcyjgmkyuoga
  glvcmmjytmprqwvn
  gwrixumjbcdffsdl
  lozravlzvfqtsuiq
  sicaflbqdxbmdlch
  inwfjkyyqbwpmqlq
  cuvszfotxywuzhzi
  igfxyoaacoarlvay
  ucjfhgdmnjvgvuni
  rvvkzjsytqgiposh
  jduinhjjntrmqroz
  yparkxbgsfnueyll
  lyeqqeisxzfsqzuj
  woncskbibjnumydm
  lltucklragtjmxtl
  ubiyvmyhlesfxotj
  uecjseeicldqrqww
  xxlxkbcthufnjbnm
  lhqijovvhlffpxga
  fzdgqpzijitlogjz
  efzzjqvwphomxdpd
  jvgzvuyzobeazssc
  hejfycgxywfjgbfw
  yhjjmvkqfbnbliks
  sffvfyywtlntsdsz
  dwmxqudvxqdenrur
  asnukgppdemxrzaz
  nwqfnumblwvdpphx
  kqsmkkspqvxzuket
  cpnraovljzqiquaz
  qrzgrdlyyzbyykhg
  opoahcbiydyhsmqe
  hjknnfdauidjeydr
  hczdjjlygoezadow
  rtflowzqycimllfv
  sfsrgrerzlnychhq
  bpahuvlblcolpjmj
  albgnjkgmcrlaicl
  pijyqdhfxpaxzdex
  eeymiddvcwkpbpux
  rqwkqoabywgggnln
  vckbollyhgbgmgwh
  ylzlgvnuvpynybkm
  hpmbxtpfosbsjixt
  ocebeihnhvkhjfqz
  tvctyxoujdgwayze
  efvhwxtuhapqxjen
  rusksgefyidldmpo
  nkmtjvddfmhirmzz
  whvtsuadwofzmvrt
  iiwjqvsdxudhdzzk
  gucirgxaxgcassyo
  rmhfasfzexeykwmr
  hynlxcvsbgosjbis
  huregszrcaocueen
  pifezpoolrnbdqtv
  unatnixzvdbqeyox
  xtawlpduxgacchfe
  bdvdbflqfphndduf
  xtdsnjnmzccfptyt
  nkhsdkhqtzqbphhg
  aqcubmfkczlaxiyb
  moziflxpsfubucmv
  srdgnnjtfehiimqx
  pwfalehdfyykrohf
  sysxssmvewyfjrve
  brsemdzosgqvvlxe
  bimbjoshuvflkiat
  hkgjasmljkpkwwku
  sbnmwjvodygobpqc
  bbbqycejueruihhd
  corawswvlvneipyc
  gcyhknmwsczcxedh
  kppakbffdhntmcqp
  ynulzwkfaemkcefp
  pyroowjekeurlbii
  iwksighrswdcnmxf
  glokrdmugreygnsg
  xkmvvumnfzckryop
  aesviofpufygschi
  csloawlirnegsssq
  fkqdqqmlzuxbkzbc
  uzlhzcfenxdfjdzp
  poaaidrktteusvyf
  zrlyfzmjzfvivcfr
  qwjulskbniitgqtx
  gjeszjksbfsuejki
  vczdejdbfixbduaq
  knjdrjthitjxluth
  jweydeginrnicirl
  bottrfgccqhyycsl
  eiquffofoadmbuhk
  lbqfutmzoksscswf
  xfmdvnvfcnzjprba
  uvugkjbkhlaoxmyx
  wadlgtpczgvcaqqv
  inzrszbtossflsxk
  dbzbtashaartczrj
  qbjiqpccefcfkvod
  hluujmokjywotvzy
  thwlliksfztcmwzh
  arahybspdaqdexrq
  nuojrmsgyipdvwyx
  hnajdwjwmzattvst
  sulcgaxezkprjbgu
  rjowuugwdpkjtypw
  oeugzwuhnrgiaqga
  wvxnyymwftfoswij
  pqxklzkjpcqscvde
  tuymjzknntekglqj
  odteewktugcwlhln
  exsptotlfecmgehc
  eeswfcijtvzgrqel
  vjhrkiwmunuiwqau
  zhlixepkeijoemne
  pavfsmwesuvebzdd
  jzovbklnngfdmyws
  nbajyohtzfeoiixz
  ciozmhrsjzrwxvhz
  gwucrxieqbaqfjuv
  uayrxrltnohexawc
  flmrbhwsfbcquffm
  gjyabmngkitawlxc
  rwwtggvaygfbovhg
  xquiegaisynictjq
  oudzwuhexrwwdbyy
  lengxmguyrwhrebb
  uklxpglldbgqsjls
  dbmvlfeyguydfsxq
  zspdwdqcrmtmdtsc
  mqfnzwbfqlauvrgc
  amcrkzptgacywvhv
  ndxmskrwrqysrndf
  mwjyhsufeqhwisju
  srlrukoaenyevykt
  tnpjtpwawrxbikct
  geczalxmgxejulcv
  tvkcbqdhmuwcxqci
  tiovluvwezwwgaox
  zrjhtbgajkjqzmfo
  vcrywduwsklepirs
  lofequdigsszuioy
  wxsdzomkjqymlzat
  iabaczqtrfbmypuy
  ibdlmudbajikcncr
  rqcvkzsbwmavdwnv
  ypxoyjelhllhbeog
  fdnszbkezyjbttbg
  uxnhrldastpdjkdz
  xfrjbehtxnlyzcka
  omjyfhbibqwgcpbv
  eguucnoxaoprszmp
  xfpypldgcmcllyzz
  aypnmgqjxjqceelv
  mgzharymejlafvgf
  tzowgwsubbaigdok
  ilsehjqpcjwmylxc
  pfmouwntfhfnmrwk
  csgokybgdqwnduwp
  eaxwvxvvwbrovypz
  nmluqvobbbmdiwwb
  lnkminvfjjzqbmio
  mjiiqzycqdhfietz
  towlrzriicyraevq
  obiloewdvbrsfwjo
  lmeooaajlthsfltw
  ichygipzpykkesrw
  gfysloxmqdsfskvt
  saqzntehjldvwtsx
  pqddoemaufpfcaew
  mjrxvbvwcreaybwe
  ngfbrwfqnxqosoai
  nesyewxreiqvhald
  kqhqdlquywotcyfy
  liliptyoqujensfi
  nsahsaxvaepzneqq
  zaickulfjajhctye
  gxjzahtgbgbabtht
  koxbuopaqhlsyhrp
  jhzejdjidqqtjnwe
  dekrkdvprfqpcqki
  linwlombdqtdeyop
  dvckqqbnigdcmwmx
  yaxygbjpzkvnnebv
  rlzkdkgaagmcpxah
  cfzuyxivtknirqvt
  obivkajhsjnrxxhn
  lmjhayymgpseuynn
  bbjyewkwadaipyju
  lmzyhwomfypoftuu
  gtzhqlgltvatxack
  jfflcfaqqkrrltgq
  txoummmnzfrlrmcg
  ohemsbfuqqpucups
  imsfvowcbieotlok
  tcnsnccdszxfcyde
  qkcdtkwuaquajazz
  arcfnhmdjezdbqku
  srnocgyqrlcvlhkb
  mppbzvfmcdirbyfw
  xiuarktilpldwgwd
  ypufwmhrvzqmexpc
  itpdnsfkwgrdujmj
  cmpxnodtsswkyxkr
  wayyxtjklfrmvbfp
  mfaxphcnjczhbbwy
  sjxhgwdnqcofbdra
  pnxmujuylqccjvjm
  ivamtjbvairwjqwl
  deijtmzgpfxrclss
  bzkqcaqagsynlaer
  tycefobvxcvwaulz
  ctbhnywezxkdsswf
  urrxxebxrthtjvib
  fpfelcigwqwdjucv
  ngfcyyqpqulwcphb
  rltkzsiipkpzlgpw
  qfdsymzwhqqdkykc
  balrhhxipoqzmihj
  rnwalxgigswxomga
  ghqnxeogckshphgr
  lyyaentdizaumnla
  exriodwfzosbeoib
  speswfggibijfejk
  yxmxgfhvmshqszrq
  hcqhngvahzgawjga
  qmhlsrfpesmeksur
  eviafjejygakodla
  kvcfeiqhynqadbzv
  fusvyhowslfzqttg
  girqmvwmcvntrwau
  yuavizroykfkdekz
  jmcwohvmzvowrhxf
  kzimlcpavapynfue
  wjudcdtrewfabppq
  yqpteuxqgbmqfgxh
  xdgiszbuhdognniu
  jsguxfwhpftlcjoh
  whakkvspssgjzxre
  ggvnvjurlyhhijgm
  krvbhjybnpemeptr
  pqedgfojyjybfbzr
  jzhcrsgmnkwwtpdo
  yyscxoxwofslncmp
  gzjhnxytmyntzths
  iteigbnqbtpvqumi
  zjevfzusnjukqpfw
  xippcyhkfuounxqk
  mcnhrcfonfdgpkyh
  pinkcyuhjkexbmzj
  lotxrswlxbxlxufs
  fmqajrtoabpckbnu
  wfkwsgmcffdgaqxg
  qfrsiwnohoyfbidr
  czfqbsbmiuyusaqs
  ieknnjeecucghpoo
  cevdgqnugupvmsge
  gjkajcyjnxdrtuvr
  udzhrargnujxiclq
  zqqrhhmjwermjssg
  ggdivtmgoqajydzz
  wnpfsgtxowkjiivl
  afbhqawjbotxnqpd
  xjpkifkhfjeqifdn
  oyfggzsstfhvticp
  kercaetahymeawxy
  khphblhcgmbupmzt
  iggoqtqpvaebtiol
  ofknifysuasshoya
  qxuewroccsbogrbv
  apsbnbkiopopytgu
  zyahfroovfjlythh
  bxhjwfgeuxlviydq
  uvbhdtvaypasaswa
  qamcjzrmesqgqdiz
  hjnjyzrxntiycyel
  wkcrwqwniczwdxgq
  hibxlvkqakusswkx
  mzjyuenepwdgrkty
  tvywsoqslfsulses
  jqwcwuuisrclircv
  xanwaoebfrzhurct
  ykriratovsvxxasf
  qyebvtqqxbjuuwuo
  telrvlwvriylnder
  acksrrptgnhkeiaa
  yemwfjhiqlzsvdxf
  banrornfkcymmkcc
  ytbhxvaeiigjpcgm
  crepyazgxquposkn
  xlqwdrytzwnxzwzv
  xtrbfbwopxscftps
  kwbytzukgseeyjla
  qtfdvavvjogybxjg
  ytbmvmrcxwfkgvzw
  nbscbdskdeocnfzr
  sqquwjbdxsxhcseg
  ewqxhigqcgszfsuw
  cvkyfcyfmubzwsee
  dcoawetekigxgygd
  ohgqnqhfimyuqhvi
  otisopzzpvnhctte
  bauieohjejamzien
  ewnnopzkujbvhwce
  aeyqlskpaehagdiv
  pncudvivwnnqspxy
  ytugesilgveokxcg
  zoidxeelqdjesxpr
  ducjccsuaygfchzj
  smhgllqqqcjfubfc
  nlbyyywergronmir
  prdawpbjhrzsbsvj
  nmgzhnjhlpcplmui
  eflaogtjghdjmxxz
  qolvpngucbkprrdc
  ixywxcienveltgho
  mwnpqtocagenkxut
  iskrfbwxonkguywx
  ouhtbvcaczqzmpua
  srewprgddfgmdbao
  dyufrltacelchlvu
  czmzcbrkecixuwzz
  dtbeojcztzauofuk
  prrgoehpqhngfgmw
  baolzvfrrevxsyke
  zqadgxshwiarkzwh
  vsackherluvurqqj
  surbpxdulvcvgjbd
  wqxytarcxzgxhvtx
  vbcubqvejcfsgrac
  zqnjfeapshjowzja
  hekvbhtainkvbynx
  knnugxoktxpvoxnh
  knoaalcefpgtvlwm
  qoakaunowmsuvkus
  ypkvlzcduzlezqcb
  ujhcagawtyepyogh
  wsilcrxncnffaxjf
  gbbycjuscquaycrk
  aduojapeaqwivnly
  ceafyxrakviagcjy
  nntajnghicgnrlst
  vdodpeherjmmvbje
  wyyhrnegblwvdobn
  xlfurpghkpbzhhif
  xyppnjiljvirmqjo
  kglzqahipnddanpi
  omjateouxikwxowr
  ocifnoopfglmndcx
  emudcukfbadyijev
  ooktviixetfddfmh
  wtvrhloyjewdeycg
  cgjncqykgutfjhvb
  nkwvpswppeffmwad
  hqbcmfhzkxmnrivg
  mdskbvzguxvieilr
  anjcvqpavhdloaqh
  erksespdevjylenq
  fadxwbmisazyegup
  iyuiffjmcaahowhj
  ygkdezmynmltodbv
  fytneukxqkjattvh
  woerxfadbfrvdcnz
  iwsljvkyfastccoa
  movylhjranlorofe
  drdmicdaiwukemep
  knfgtsmuhfcvvshg
  ibstpbevqmdlhajn
  tstwsswswrxlzrqs
  estyydmzothggudf
  jezogwvymvikszwa
  izmqcwdyggibliet
  nzpxbegurwnwrnca
  kzkojelnvkwfublh
  xqcssgozuxfqtiwi
  tcdoigumjrgvczfv
  ikcjyubjmylkwlwq
  kqfivwystpqzvhan
  bzukgvyoqewniivj
  iduapzclhhyfladn
  fbpyzxdfmkrtfaeg
  yzsmlbnftftgwadz
  (defun day5/vowels (string)
    (seq-filter
     (apply-partially 'seq-contains "aeiou")
     string))

  (defun day5/has-doubles? (string)
    (string-match-p "\\([a-z]\\)\\1" string))

  (defun day5/naughty? (string)
       (-any
        (lambda (naughty-pattern)
          (s-contains? naughty-pattern string))
        '("ab" "cd" "pq" "xy")))

  (defun day5/nice? (string)
    (and (<= 3 (length (day5/vowels string)))
         (day5/has-doubles? string)
         (not (day5/naughty? string))))

  (ert-deftest day5/nice? ()
    (should (day5/nice? "ugknbfddgicrmopn"))
    (should (day5/nice? "aaa"))
    (should-not (day5/nice? "jchzalrnumimnmhp"))
    (should-not (day5/nice? "haegwjzuvuyypxyu"))
    (should-not (day5/nice? "dvszwmarrgswjxmb")))

  (length
   (-filter #'day5/nice?
            (split-string input)))
255

Part 2

Realizing the error of his ways, Santa has switched to a better model of determining whether a string is naughty or nice. None of the old rules apply, as they are all clearly ridiculous.

Now, a nice string is one with all of the following properties:

  • It contains a pair of any two letters that appears at least twice in the string without overlapping, like xyxy (xy) or aabcdefgaa (aa), but not like aaa (aa, but it overlaps).
  • It contains at least one letter which repeats with exactly one letter between them, like xyx, abcdefeghi (efe), or even aaa.

For example:

  • qjhvhtzxzqqjkmpb is nice because is has a pair that appears twice (qj) and a letter that repeats with exactly one letter between them (zxz).
  • xxyxx is nice because it has a pair that appears twice and a letter that repeats with one between, even though the letters used by each rule overlap.
  • uurcxstgmygtbstg is naughty because it has a pair (tg) but no repeat with a single letter between them.
  • ieodomkazucvgmuy is naughty because it has a repeating letter with one between (odo), but no pair that appears twice.

How many strings are nice under these new rules?


  (defun day5/double-pair? (string)
    (string-match-p "\\([a-z][a-z]\\).*\\1"
                    string))

  (ert-deftest day5/double-pair? ()
    (should (day5/double-pair? "xyxy"))
    (should (day5/double-pair? "aabcdefgaa"))
    (should-not (day5/double-pair? "aaa")))

  (defun day5/letter-sandwich? (string)
    (string-match-p "\\([a-z]\\)[a-z]\\1"
                    string))

  (ert-deftest day5/letter-sandwich? ()
    (should (day5/letter-sandwich? "xyx"))
    (should (day5/letter-sandwich? "abcdefeghi"))
    (should (day5/letter-sandwich? "aaa")))

  (defun day5/nice?? (string)
    (and (day5/double-pair? string)
         (day5/letter-sandwich? string)))

  (ert-deftest day5/nice?? ()
    (should (day5/nice?? "qjhvhtzxzqqjkmpb"))
    (should (day5/nice?? "xxyxx"))
    (should-not (day5/nice?? "uurcxstgmygtbstg"))
    (should-not (day5/nice?? "ieodomkazucvgmuy")))

  (length
   (-filter #'day5/nice??
            (split-string input)))
55

Day 6: Probably a Fire Hazard

Because your neighbors keep defeating you in the holiday house decorating contest year after year, you've decided to deploy one million lights in a 1000x1000 grid.

Furthermore, because you've been especially nice this year, Santa has mailed you instructions on how to display the ideal lighting configuration.

Lights in your grid are numbered from 0 to 999 in each direction; the lights at each corner are at 0,0, 0,999, 999,999, and 999,0. The instructions include whether to turn on, turn off, or toggle various inclusive ranges given as coordinate pairs. Each coordinate pair represents opposite corners of a rectangle, inclusive; a coordinate pair like 0,0 through 2,2 therefore refers to 9 lights in a 3x3 square. The lights all start turned off.

To defeat your neighbors this year, all you have to do is set up your lights by doing the instructions Santa sent you in order.

For example:

  • turn on 0,0 through 999,999 would turn on (or leave on) every light.
  • toggle 0,0 through 999,0 would toggle the first line of 1000 lights, turning off the ones that were on, and turning on the ones that were off.
  • turn off 499,499 through 500,500 would turn off (or leave off) the middle four lights.

After following the instructions, how many lights are lit?


  turn on 887,9 through 959,629
  turn on 454,398 through 844,448
  turn off 539,243 through 559,965
  turn off 370,819 through 676,868
  turn off 145,40 through 370,997
  turn off 301,3 through 808,453
  turn on 351,678 through 951,908
  toggle 720,196 through 897,994
  toggle 831,394 through 904,860
  toggle 753,664 through 970,926
  turn off 150,300 through 213,740
  turn on 141,242 through 932,871
  toggle 294,259 through 474,326
  toggle 678,333 through 752,957
  toggle 393,804 through 510,976
  turn off 6,964 through 411,976
  turn off 33,572 through 978,590
  turn on 579,693 through 650,978
  turn on 150,20 through 652,719
  turn off 782,143 through 808,802
  turn off 240,377 through 761,468
  turn off 899,828 through 958,967
  turn on 613,565 through 952,659
  turn on 295,36 through 964,978
  toggle 846,296 through 969,528
  turn off 211,254 through 529,491
  turn off 231,594 through 406,794
  turn off 169,791 through 758,942
  turn on 955,440 through 980,477
  toggle 944,498 through 995,928
  turn on 519,391 through 605,718
  toggle 521,303 through 617,366
  turn off 524,349 through 694,791
  toggle 391,87 through 499,792
  toggle 562,527 through 668,935
  turn off 68,358 through 857,453
  toggle 815,811 through 889,828
  turn off 666,61 through 768,87
  turn on 27,501 through 921,952
  turn on 953,102 through 983,471
  turn on 277,552 through 451,723
  turn off 64,253 through 655,960
  turn on 47,485 through 734,977
  turn off 59,119 through 699,734
  toggle 407,898 through 493,955
  toggle 912,966 through 949,991
  turn on 479,990 through 895,990
  toggle 390,589 through 869,766
  toggle 593,903 through 926,943
  toggle 358,439 through 870,528
  turn off 649,410 through 652,875
  turn on 629,834 through 712,895
  toggle 254,555 through 770,901
  toggle 641,832 through 947,850
  turn on 268,448 through 743,777
  turn off 512,123 through 625,874
  turn off 498,262 through 930,811
  turn off 835,158 through 886,242
  toggle 546,310 through 607,773
  turn on 501,505 through 896,909
  turn off 666,796 through 817,924
  toggle 987,789 through 993,809
  toggle 745,8 through 860,693
  toggle 181,983 through 731,988
  turn on 826,174 through 924,883
  turn on 239,228 through 843,993
  turn on 205,613 through 891,667
  toggle 867,873 through 984,896
  turn on 628,251 through 677,681
  toggle 276,956 through 631,964
  turn on 78,358 through 974,713
  turn on 521,360 through 773,597
  turn off 963,52 through 979,502
  turn on 117,151 through 934,622
  toggle 237,91 through 528,164
  turn on 944,269 through 975,453
  toggle 979,460 through 988,964
  turn off 440,254 through 681,507
  toggle 347,100 through 896,785
  turn off 329,592 through 369,985
  turn on 931,960 through 979,985
  toggle 703,3 through 776,36
  toggle 798,120 through 908,550
  turn off 186,605 through 914,709
  turn off 921,725 through 979,956
  toggle 167,34 through 735,249
  turn on 726,781 through 987,936
  toggle 720,336 through 847,756
  turn on 171,630 through 656,769
  turn off 417,276 through 751,500
  toggle 559,485 through 584,534
  turn on 568,629 through 690,873
  toggle 248,712 through 277,988
  toggle 345,594 through 812,723
  turn off 800,108 through 834,618
  turn off 967,439 through 986,869
  turn on 842,209 through 955,529
  turn on 132,653 through 357,696
  turn on 817,38 through 973,662
  turn off 569,816 through 721,861
  turn on 568,429 through 945,724
  turn on 77,458 through 844,685
  turn off 138,78 through 498,851
  turn on 136,21 through 252,986
  turn off 2,460 through 863,472
  turn on 172,81 through 839,332
  turn on 123,216 through 703,384
  turn off 879,644 through 944,887
  toggle 227,491 through 504,793
  toggle 580,418 through 741,479
  toggle 65,276 through 414,299
  toggle 482,486 through 838,931
  turn off 557,768 through 950,927
  turn off 615,617 through 955,864
  turn on 859,886 through 923,919
  turn on 391,330 through 499,971
  toggle 521,835 through 613,847
  turn on 822,787 through 989,847
  turn on 192,142 through 357,846
  turn off 564,945 through 985,945
  turn off 479,361 through 703,799
  toggle 56,481 through 489,978
  turn off 632,991 through 774,998
  toggle 723,526 through 945,792
  turn on 344,149 through 441,640
  toggle 568,927 through 624,952
  turn on 621,784 through 970,788
  toggle 665,783 through 795,981
  toggle 386,610 through 817,730
  toggle 440,399 through 734,417
  toggle 939,201 through 978,803
  turn off 395,883 through 554,929
  turn on 340,309 through 637,561
  turn off 875,147 through 946,481
  turn off 945,837 through 957,922
  turn off 429,982 through 691,991
  toggle 227,137 through 439,822
  toggle 4,848 through 7,932
  turn off 545,146 through 756,943
  turn on 763,863 through 937,994
  turn on 232,94 through 404,502
  turn off 742,254 through 930,512
  turn on 91,931 through 101,942
  toggle 585,106 through 651,425
  turn on 506,700 through 567,960
  turn off 548,44 through 718,352
  turn off 194,827 through 673,859
  turn off 6,645 through 509,764
  turn off 13,230 through 821,361
  turn on 734,629 through 919,631
  toggle 788,552 through 957,972
  toggle 244,747 through 849,773
  turn off 162,553 through 276,887
  turn off 569,577 through 587,604
  turn off 799,482 through 854,956
  turn on 744,535 through 909,802
  toggle 330,641 through 396,986
  turn off 927,458 through 966,564
  toggle 984,486 through 986,913
  toggle 519,682 through 632,708
  turn on 984,977 through 989,986
  toggle 766,423 through 934,495
  turn on 17,509 through 947,718
  turn on 413,783 through 631,903
  turn on 482,370 through 493,688
  turn on 433,859 through 628,938
  turn off 769,549 through 945,810
  turn on 178,853 through 539,941
  turn off 203,251 through 692,433
  turn off 525,638 through 955,794
  turn on 169,70 through 764,939
  toggle 59,352 through 896,404
  toggle 143,245 through 707,320
  turn off 103,35 through 160,949
  toggle 496,24 through 669,507
  turn off 581,847 through 847,903
  turn on 689,153 through 733,562
  turn on 821,487 through 839,699
  turn on 837,627 through 978,723
  toggle 96,748 through 973,753
  toggle 99,818 through 609,995
  turn on 731,193 through 756,509
  turn off 622,55 through 813,365
  turn on 456,490 through 576,548
  turn on 48,421 through 163,674
  turn off 853,861 through 924,964
  turn off 59,963 through 556,987
  turn on 458,710 through 688,847
  toggle 12,484 through 878,562
  turn off 241,964 through 799,983
  turn off 434,299 through 845,772
  toggle 896,725 through 956,847
  turn on 740,289 through 784,345
  turn off 395,840 through 822,845
  turn on 955,224 through 996,953
  turn off 710,186 through 957,722
  turn off 485,949 through 869,985
  turn on 848,209 through 975,376
  toggle 221,241 through 906,384
  turn on 588,49 through 927,496
  turn on 273,332 through 735,725
  turn on 505,962 through 895,962
  toggle 820,112 through 923,143
  turn on 919,792 through 978,982
  toggle 489,461 through 910,737
  turn off 202,642 through 638,940
  turn off 708,953 through 970,960
  toggle 437,291 through 546,381
  turn on 409,358 through 837,479
  turn off 756,279 through 870,943
  turn off 154,657 through 375,703
  turn off 524,622 through 995,779
  toggle 514,221 through 651,850
  toggle 808,464 through 886,646
  toggle 483,537 through 739,840
  toggle 654,769 through 831,825
  turn off 326,37 through 631,69
  turn off 590,570 through 926,656
  turn off 881,913 through 911,998
  turn on 996,102 through 998,616
  turn off 677,503 through 828,563
  turn on 860,251 through 877,441
  turn off 964,100 through 982,377
  toggle 888,403 through 961,597
  turn off 632,240 through 938,968
  toggle 731,176 through 932,413
  turn on 5,498 through 203,835
  turn on 819,352 through 929,855
  toggle 393,813 through 832,816
  toggle 725,689 through 967,888
  turn on 968,950 through 969,983
  turn off 152,628 through 582,896
  turn off 165,844 through 459,935
  turn off 882,741 through 974,786
  turn off 283,179 through 731,899
  toggle 197,366 through 682,445
  turn on 106,309 through 120,813
  toggle 950,387 through 967,782
  turn off 274,603 through 383,759
  turn off 155,665 through 284,787
  toggle 551,871 through 860,962
  turn off 30,826 through 598,892
  toggle 76,552 through 977,888
  turn on 938,180 through 994,997
  toggle 62,381 through 993,656
  toggle 625,861 through 921,941
  turn on 685,311 through 872,521
  turn on 124,934 through 530,962
  turn on 606,379 through 961,867
  turn off 792,735 through 946,783
  turn on 417,480 through 860,598
  toggle 178,91 through 481,887
  turn off 23,935 through 833,962
  toggle 317,14 through 793,425
  turn on 986,89 through 999,613
  turn off 359,201 through 560,554
  turn off 729,494 through 942,626
  turn on 204,143 through 876,610
  toggle 474,97 through 636,542
  turn off 902,924 through 976,973
  turn off 389,442 through 824,638
  turn off 622,863 through 798,863
  turn on 840,622 through 978,920
  toggle 567,374 through 925,439
  turn off 643,319 through 935,662
  toggle 185,42 through 294,810
  turn on 47,124 through 598,880
  toggle 828,303 through 979,770
  turn off 174,272 through 280,311
  turn off 540,50 through 880,212
  turn on 141,994 through 221,998
  turn on 476,695 through 483,901
  turn on 960,216 through 972,502
  toggle 752,335 through 957,733
  turn off 419,713 through 537,998
  toggle 772,846 through 994,888
  turn on 881,159 through 902,312
  turn off 537,651 through 641,816
  toggle 561,947 through 638,965
  turn on 368,458 through 437,612
  turn on 290,149 through 705,919
  turn on 711,918 through 974,945
  toggle 916,242 through 926,786
  toggle 522,272 through 773,314
  turn on 432,897 through 440,954
  turn off 132,169 through 775,380
  toggle 52,205 through 693,747
  toggle 926,309 through 976,669
  turn off 838,342 through 938,444
  turn on 144,431 through 260,951
  toggle 780,318 through 975,495
  turn off 185,412 through 796,541
  turn on 879,548 through 892,860
  turn on 294,132 through 460,338
  turn on 823,500 through 899,529
  turn off 225,603 through 483,920
  toggle 717,493 through 930,875
  toggle 534,948 through 599,968
  turn on 522,730 through 968,950
  turn off 102,229 through 674,529
  (defun day6/make-light ()
    nil)

  (defun day6/turn-on-light (light)
    t)

  (defun day6/turn-off-light (light)
    nil)

  (defun day6/toggle-light (light)
    (not light))

  (defun day6/lit? (light)
    light)

  (defun day6/make-grid (size)
    (let ((table (make-hash-table :size (* size size))))
      (-each (number-sequence 0 (- (* size size) 1))
        (lambda (pos) (puthash pos (day6/make-light) table)))
      (cons size
            table)))

  (defun day6/grid-size (grid)
    (car grid))

  (defun day6/grid-table (grid)
    (cdr grid))

  (defun day6/grid-lights (grid)
    (hash-table-values (day6/grid-table grid)))

  (defun day6/grid-location (grid x y)
    (+ x (* y (day6/grid-size grid))))

  (ert-deftest day6/grid-location ()
    (should (eq 99 (let ((grid (day6/make-grid 100)))
                     (day6/grid-location grid 99 0))))
    (should (eq 100 (let ((grid (day6/make-grid 100)))
                      (day6/grid-location grid 0 1)))))

  (defun day6/grid-light (grid location)
    (gethash location (day6/grid-table grid)))

  (defun day6/grid-do (grid fun location)
    (puthash location
             (funcall fun (day6/grid-light grid location))
             (day6/grid-table grid)))

  (defun day6/change-range (grid light-fun x1 y1 x2 y2)
    (loop for x from x1 to x2
          do (loop for y from y1 to y2
                   do (let* ((location (day6/grid-location grid x y)))
                        (day6/grid-do grid light-fun location)))))

  (defun day6/lit-count (grid)
    (length (-filter #'day6/lit? (day6/grid-lights grid))))

  (ert-deftest day6/lit-count ()
    (should (eq 1000000
                (let ((grid (day6/make-grid 1000)))
                  (day6/change-range grid #'day6/turn-on-light
                                     0 0 999 999)
                  (day6/lit-count grid))))
    (should (eq 4
                (let ((grid (day6/make-grid 1000)))
                  (day6/change-range grid #'day6/turn-on-light
                                     499 499 500 500)
                  (day6/lit-count grid)))))

  (defun day6/parse-instruction (instruction)
    (if (string-match (concat "\\(turn \\(on\\|off\\)\\|toggle\\) "
                              "\\([0-9]+\\),\\([0-9]+\\)"
                              " through "
                              "\\([0-9]+\\),\\([0-9]+\\)")
                      instruction)
        (list (cond ((string-equal "turn on" (match-string 1 instruction))
                     #'day6/turn-on-light)
                    ((string-equal "turn off" (match-string 1 instruction))
                     #'day6/turn-off-light)
                    ((string-equal "toggle" (match-string 1 instruction))
                     #'day6/toggle-light))
              (string-to-int (match-string 3 instruction))
              (string-to-int (match-string 4 instruction))
              (string-to-int (match-string 5 instruction))
              (string-to-int (match-string 6 instruction)))))

  (ert-deftest day6/parse-instruction ()
    (should (equal '(day6/turn-on-light 887 9 959 629)
                   (day6/parse-instruction "turn on 887,9 through 959,629")))
    (should (equal '(day6/turn-off-light 539 243 559 965)
                   (day6/parse-instruction "turn off 539,243 through 559,965")))
    (should (equal '(day6/toggle-light 720 196 897 994)
                   (day6/parse-instruction "toggle 720,196 through 897,994"))))

  (defun day6/run-instruction (grid instruction)
    (let ((parsed-instruction (day6/parse-instruction instruction)))
      (eval (append '(day6/change-range grid)
                    `(',(first parsed-instruction))
                    (rest parsed-instruction)))))

  (let ((grid (day6/make-grid 1000)))
    (-each (split-string input "\n" t)
      (apply-partially 'day6/run-instruction grid))
    (day6/lit-count grid))
377891

Part 2

You just finish implementing your winning light pattern when you realize you mistranslated Santa's message from Ancient Nordic Elvish.

The light grid you bought actually has individual brightness controls; each light can have a brightness of zero or more. The lights all start at zero.

The phrase turn on actually means that you should increase the brightness of those lights by 1.

The phrase turn off actually means that you should decrease the brightness of those lights by 1, to a minimum of zero.

The phrase toggle actually means that you should increase the brightness of those lights by 2.

What is the total brightness of all lights combined after following Santa's instructions?

For example:

  • turn on 0,0 through 0,0 would increase the total brightness by 1.
  • toggle 0,0 through 999,999 would increase the total brightness by 2000000.

  (defun day6.2/make-light ()
    0)

  (defun day6.2/turn-on-light (light)
    (+ 1 light))

  (defun day6.2/turn-off-light (light)
    (if (>= 0 light) 0
      (- light 1)))

  (defun day6.2/toggle-light (light)
    (+ 2 light))

  (defun day6.2/parse-instruction (instruction)
    (if (string-match (concat "\\(turn \\(on\\|off\\)\\|toggle\\) "
                              "\\([0-9]+\\),\\([0-9]+\\)"
                              " through "
                              "\\([0-9]+\\),\\([0-9]+\\)")
                      instruction)
        (list (cond ((string-equal "turn on" (match-string 1 instruction))
                     #'day6.2/turn-on-light)
                    ((string-equal "turn off" (match-string 1 instruction))
                     #'day6.2/turn-off-light)
                    ((string-equal "toggle" (match-string 1 instruction))
                     #'day6.2/toggle-light))
              (string-to-int (match-string 3 instruction))
              (string-to-int (match-string 4 instruction))
              (string-to-int (match-string 5 instruction))
              (string-to-int (match-string 6 instruction)))))

  (defun day6.2/run-instruction (grid instruction)
    (let ((parsed-instruction (day6.2/parse-instruction instruction)))
      (eval (append '(day6/change-range grid)
                    `(',(first parsed-instruction))
                    (rest parsed-instruction)))))

  (defun day6.2/make-grid (size)
    (let ((table (make-hash-table :size (* size size))))
      (-each (number-sequence 0 (- (* size size) 1))
        (lambda (pos) (puthash pos (day6.2/make-light) table)))
      (cons size
            table)))

  (defun day6.2/total-brightness (grid)
    (-reduce #'+
             (day6/grid-lights grid)))

  (let ((grid (day6.2/make-grid 1000)))
    (-each (split-string input "\n" t)
      (apply-partially 'day6.2/run-instruction grid))
    (day6.2/total-brightness grid))
14110788

Day 7: Some Assembly Required

This year, Santa brought little Bobby Tables a set of wires and bitwise logic gates! Unfortunately, little Bobby is a little under the recommended age range, and he needs help assembling the circuit.

Each wire has an identifier (some lowercase letters) and can carry a 16-bit signal (a number from 0 to 65535). A signal is provided to each wire by a gate, another wire, or some specific value. Each wire can only get a signal from one source, but can provide its signal to multiple destinations. A gate provides no signal until all of its inputs have a signal.

The included instructions booklet describes how to connect the parts together: x AND y -> z means to connect wires x and y to an AND gate, and then connect its output to wire z.

For example:

  • 123 -> x means that the signal 123 is provided to wire x.
  • x AND y -> z means that the bitwise AND of wire x and wire y is provided to wire z.
  • p LSHIFT 2 -> q means that the value from wire p is left-shifted by 2 and then provided to wire q.
  • NOT e -> f means that the bitwise complement of the value from wire e is provided to wire f.

Other possible gates include OR (bitwise OR) and RSHIFT (right-shift). If, for some reason, you'd like to emulate the circuit instead, almost all programming languages (for example, C, JavaScript, or Python) provide operators for these gates.

For example, here is a simple circuit:

123 -> x
456 -> y
x AND y -> d
x OR y -> e
x LSHIFT 2 -> f
y RSHIFT 2 -> g
NOT x -> h
NOT y -> i

After it is run, these are the signals on the wires:

d: 72
e: 507
f: 492
g: 114
h: 65412
i: 65079
x: 123
y: 456

In little Bobby's kit's instructions booklet (provided as your puzzle input), what signal is ultimately provided to wire a?


  af AND ah -> ai
  NOT lk -> ll
  hz RSHIFT 1 -> is
  NOT go -> gp
  du OR dt -> dv
  x RSHIFT 5 -> aa
  at OR az -> ba
  eo LSHIFT 15 -> es
  ci OR ct -> cu
  b RSHIFT 5 -> f
  fm OR fn -> fo
  NOT ag -> ah
  v OR w -> x
  g AND i -> j
  an LSHIFT 15 -> ar
  1 AND cx -> cy
  jq AND jw -> jy
  iu RSHIFT 5 -> ix
  gl AND gm -> go
  NOT bw -> bx
  jp RSHIFT 3 -> jr
  hg AND hh -> hj
  bv AND bx -> by
  er OR es -> et
  kl OR kr -> ks
  et RSHIFT 1 -> fm
  e AND f -> h
  u LSHIFT 1 -> ao
  he RSHIFT 1 -> hx
  eg AND ei -> ej
  bo AND bu -> bw
  dz OR ef -> eg
  dy RSHIFT 3 -> ea
  gl OR gm -> gn
  da LSHIFT 1 -> du
  au OR av -> aw
  gj OR gu -> gv
  eu OR fa -> fb
  lg OR lm -> ln
  e OR f -> g
  NOT dm -> dn
  NOT l -> m
  aq OR ar -> as
  gj RSHIFT 5 -> gm
  hm AND ho -> hp
  ge LSHIFT 15 -> gi
  jp RSHIFT 1 -> ki
  hg OR hh -> hi
  lc LSHIFT 1 -> lw
  km OR kn -> ko
  eq LSHIFT 1 -> fk
  1 AND am -> an
  gj RSHIFT 1 -> hc
  aj AND al -> am
  gj AND gu -> gw
  ko AND kq -> kr
  ha OR gz -> hb
  bn OR by -> bz
  iv OR jb -> jc
  NOT ac -> ad
  bo OR bu -> bv
  d AND j -> l
  bk LSHIFT 1 -> ce
  de OR dk -> dl
  dd RSHIFT 1 -> dw
  hz AND ik -> im
  NOT jd -> je
  fo RSHIFT 2 -> fp
  hb LSHIFT 1 -> hv
  lf RSHIFT 2 -> lg
  gj RSHIFT 3 -> gl
  ki OR kj -> kk
  NOT ak -> al
  ld OR le -> lf
  ci RSHIFT 3 -> ck
  1 AND cc -> cd
  NOT kx -> ky
  fp OR fv -> fw
  ev AND ew -> ey
  dt LSHIFT 15 -> dx
  NOT ax -> ay
  bp AND bq -> bs
  NOT ii -> ij
  ci AND ct -> cv
  iq OR ip -> ir
  x RSHIFT 2 -> y
  fq OR fr -> fs
  bn RSHIFT 5 -> bq
  0 -> c
  14146 -> b
  d OR j -> k
  z OR aa -> ab
  gf OR ge -> gg
  df OR dg -> dh
  NOT hj -> hk
  NOT di -> dj
  fj LSHIFT 15 -> fn
  lf RSHIFT 1 -> ly
  b AND n -> p
  jq OR jw -> jx
  gn AND gp -> gq
  x RSHIFT 1 -> aq
  ex AND ez -> fa
  NOT fc -> fd
  bj OR bi -> bk
  as RSHIFT 5 -> av
  hu LSHIFT 15 -> hy
  NOT gs -> gt
  fs AND fu -> fv
  dh AND dj -> dk
  bz AND cb -> cc
  dy RSHIFT 1 -> er
  hc OR hd -> he
  fo OR fz -> ga
  t OR s -> u
  b RSHIFT 2 -> d
  NOT jy -> jz
  hz RSHIFT 2 -> ia
  kk AND kv -> kx
  ga AND gc -> gd
  fl LSHIFT 1 -> gf
  bn AND by -> ca
  NOT hr -> hs
  NOT bs -> bt
  lf RSHIFT 3 -> lh
  au AND av -> ax
  1 AND gd -> ge
  jr OR js -> jt
  fw AND fy -> fz
  NOT iz -> ja
  c LSHIFT 1 -> t
  dy RSHIFT 5 -> eb
  bp OR bq -> br
  NOT h -> i
  1 AND ds -> dt
  ab AND ad -> ae
  ap LSHIFT 1 -> bj
  br AND bt -> bu
  NOT ca -> cb
  NOT el -> em
  s LSHIFT 15 -> w
  gk OR gq -> gr
  ff AND fh -> fi
  kf LSHIFT 15 -> kj
  fp AND fv -> fx
  lh OR li -> lj
  bn RSHIFT 3 -> bp
  jp OR ka -> kb
  lw OR lv -> lx
  iy AND ja -> jb
  dy OR ej -> ek
  1 AND bh -> bi
  NOT kt -> ku
  ao OR an -> ap
  ia AND ig -> ii
  NOT ey -> ez
  bn RSHIFT 1 -> cg
  fk OR fj -> fl
  ce OR cd -> cf
  eu AND fa -> fc
  kg OR kf -> kh
  jr AND js -> ju
  iu RSHIFT 3 -> iw
  df AND dg -> di
  dl AND dn -> do
  la LSHIFT 15 -> le
  fo RSHIFT 1 -> gh
  NOT gw -> gx
  NOT gb -> gc
  ir LSHIFT 1 -> jl
  x AND ai -> ak
  he RSHIFT 5 -> hh
  1 AND lu -> lv
  NOT ft -> fu
  gh OR gi -> gj
  lf RSHIFT 5 -> li
  x RSHIFT 3 -> z
  b RSHIFT 3 -> e
  he RSHIFT 2 -> hf
  NOT fx -> fy
  jt AND jv -> jw
  hx OR hy -> hz
  jp AND ka -> kc
  fb AND fd -> fe
  hz OR ik -> il
  ci RSHIFT 1 -> db
  fo AND fz -> gb
  fq AND fr -> ft
  gj RSHIFT 2 -> gk
  cg OR ch -> ci
  cd LSHIFT 15 -> ch
  jm LSHIFT 1 -> kg
  ih AND ij -> ik
  fo RSHIFT 3 -> fq
  fo RSHIFT 5 -> fr
  1 AND fi -> fj
  1 AND kz -> la
  iu AND jf -> jh
  cq AND cs -> ct
  dv LSHIFT 1 -> ep
  hf OR hl -> hm
  km AND kn -> kp
  de AND dk -> dm
  dd RSHIFT 5 -> dg
  NOT lo -> lp
  NOT ju -> jv
  NOT fg -> fh
  cm AND co -> cp
  ea AND eb -> ed
  dd RSHIFT 3 -> df
  gr AND gt -> gu
  ep OR eo -> eq
  cj AND cp -> cr
  lf OR lq -> lr
  gg LSHIFT 1 -> ha
  et RSHIFT 2 -> eu
  NOT jh -> ji
  ek AND em -> en
  jk LSHIFT 15 -> jo
  ia OR ig -> ih
  gv AND gx -> gy
  et AND fe -> fg
  lh AND li -> lk
  1 AND io -> ip
  kb AND kd -> ke
  kk RSHIFT 5 -> kn
  id AND if -> ig
  NOT ls -> lt
  dw OR dx -> dy
  dd AND do -> dq
  lf AND lq -> ls
  NOT kc -> kd
  dy AND ej -> el
  1 AND ke -> kf
  et OR fe -> ff
  hz RSHIFT 5 -> ic
  dd OR do -> dp
  cj OR cp -> cq
  NOT dq -> dr
  kk RSHIFT 1 -> ld
  jg AND ji -> jj
  he OR hp -> hq
  hi AND hk -> hl
  dp AND dr -> ds
  dz AND ef -> eh
  hz RSHIFT 3 -> ib
  db OR dc -> dd
  hw LSHIFT 1 -> iq
  he AND hp -> hr
  NOT cr -> cs
  lg AND lm -> lo
  hv OR hu -> hw
  il AND in -> io
  NOT eh -> ei
  gz LSHIFT 15 -> hd
  gk AND gq -> gs
  1 AND en -> eo
  NOT kp -> kq
  et RSHIFT 5 -> ew
  lj AND ll -> lm
  he RSHIFT 3 -> hg
  et RSHIFT 3 -> ev
  as AND bd -> bf
  cu AND cw -> cx
  jx AND jz -> ka
  b OR n -> o
  be AND bg -> bh
  1 AND ht -> hu
  1 AND gy -> gz
  NOT hn -> ho
  ck OR cl -> cm
  ec AND ee -> ef
  lv LSHIFT 15 -> lz
  ks AND ku -> kv
  NOT ie -> if
  hf AND hl -> hn
  1 AND r -> s
  ib AND ic -> ie
  hq AND hs -> ht
  y AND ae -> ag
  NOT ed -> ee
  bi LSHIFT 15 -> bm
  dy RSHIFT 2 -> dz
  ci RSHIFT 2 -> cj
  NOT bf -> bg
  NOT im -> in
  ev OR ew -> ex
  ib OR ic -> id
  bn RSHIFT 2 -> bo
  dd RSHIFT 2 -> de
  bl OR bm -> bn
  as RSHIFT 1 -> bl
  ea OR eb -> ec
  ln AND lp -> lq
  kk RSHIFT 3 -> km
  is OR it -> iu
  iu RSHIFT 2 -> iv
  as OR bd -> be
  ip LSHIFT 15 -> it
  iw OR ix -> iy
  kk RSHIFT 2 -> kl
  NOT bb -> bc
  ci RSHIFT 5 -> cl
  ly OR lz -> ma
  z AND aa -> ac
  iu RSHIFT 1 -> jn
  cy LSHIFT 15 -> dc
  cf LSHIFT 1 -> cz
  as RSHIFT 3 -> au
  cz OR cy -> da
  kw AND ky -> kz
  lx -> a
  iw AND ix -> iz
  lr AND lt -> lu
  jp RSHIFT 5 -> js
  aw AND ay -> az
  jc AND je -> jf
  lb OR la -> lc
  NOT cn -> co
  kh LSHIFT 1 -> lb
  1 AND jj -> jk
  y OR ae -> af
  ck AND cl -> cn
  kk OR kv -> kw
  NOT cv -> cw
  kl AND kr -> kt
  iu OR jf -> jg
  at AND az -> bb
  jp RSHIFT 2 -> jq
  iv AND jb -> jd
  jn OR jo -> jp
  x OR ai -> aj
  ba AND bc -> bd
  jl OR jk -> jm
  b RSHIFT 1 -> v
  o AND q -> r
  NOT p -> q
  k AND m -> n
  as RSHIFT 2 -> at
  (defun day7/parse-expression (expression-string)
    (cond ((s-numeric? expression-string)
           (string-to-int expression-string))
          ((s-contains? " " expression-string)
           (let ((expression (-map #'day7/parse-expression
                                   (split-string expression-string))))
             (cond ((= 1 (length expression)) ;; single term
                    (car expression))
                   ((= 3 (length expression)) ;; re-order infix operation
                    (list (cadr expression)
                          (car expression)
                          (caddr expression)))
                   (t expression))))
          (t (intern (downcase expression-string)))))

  (ert-deftest day7/parse-expression ()
    (should (equal 123
                   (day7/parse-expression "123")))
    (should (equal 'x
                   (day7/parse-expression "x")))
    (should (equal 'ab
                   (day7/parse-expression "ab")))
    (should (equal '(and x y)
                   (day7/parse-expression "x AND y"))))

  (defun day7/parse-connection (connection-string)
    (string-match "\\(.*?\\) -> \\(.*\\)"
                  connection-string)
    (cons (day7/parse-expression (match-string 2 connection-string))
          (day7/parse-expression (match-string 1 connection-string))))

  (ert-deftest day7/parse-connection ()
    (should (equal '(x . 123)
                   (day7/parse-connection "123 -> x")))
    (should (equal '(d . (and x y))
                   (day7/parse-connection "x AND y -> d"))))

  (defun day7/make-circuit (connection-strings)
    (let ((expressions (-map #'day7/parse-connection
                             connection-strings))
          (circuit (make-hash-table :size (length connection-strings))))
      (-each expressions
        (lambda (expr) (puthash (car expr)
                                (cdr expr)
                                circuit)))
      circuit))

  (defun day7/circuit-get (circuit wire)
    (or (gethash wire circuit)
        (error (format "Unknown wire: %s" wire))))

  (defun day7/circuit-put (circuit wire value)
    (puthash wire value circuit))

  (defun day7/truncate-to-16bit (num)
    (string-to-number
     (substring (format "%04x" num) -4)
     16))

  (defun day7/and (a b)
    (logand a b))

  (defun day7/or (a b)
    (logior a b))

  (defun day7/not (n)
    (day7/truncate-to-16bit (lognot n)))

  (defun day7/rshift (n count)
    (lsh n (- count)))

  (defun day7/lshift (n count)
    (day7/truncate-to-16bit (lsh n count)))

  (defun day7/evaluate (circuit expr)
    (cond ((numberp expr) (day7/truncate-to-16bit expr))
          ((symbolp expr)
           ;; Evaluate and store the result in the circuit table for
           ;; future lookups
           (let ((result (day7/evaluate circuit
                                        (day7/circuit-get circuit expr))))
             (day7/circuit-put circuit expr result)
             result))
          ((listp expr)
           (let ((op (cond ((eq 'and (car expr)) #'day7/and)
                           ((eq 'or (car expr)) #'day7/or)
                           ((eq 'not (car expr)) #'day7/not)
                           ((eq 'lshift (car expr)) #'day7/lshift)
                           ((eq 'rshift (car expr)) #'day7/rshift)))
                 (args (-map (apply-partially 'day7/evaluate circuit)
                             (cdr expr))))
             (apply op args)))
          (t expr))
    )

  (ert-deftest day7/evaluate ()
    (let* ((sample-input (list "123 -> x"
                               "456 -> y"
                               "x AND y -> d"
                               "x OR y -> e"
                               "x LSHIFT 2 -> f"
                               "y RSHIFT 2 -> g"
                               "NOT x -> h"
                               "NOT y -> i"))
           (circuit (day7/make-circuit sample-input)))
      (should (eq 72 (day7/evaluate circuit 'd)))
      (should (eq 507 (day7/evaluate circuit 'e)))
      (should (eq 492 (day7/evaluate circuit 'f)))
      (should (eq 114 (day7/evaluate circuit 'g)))
      (should (eq 65412 (day7/evaluate circuit 'h)))
      (should (eq 65079 (day7/evaluate circuit 'i)))
      (should (eq 123 (day7/evaluate circuit 'x)))
      (should (eq 456 (day7/evaluate circuit 'y)))))

  (let* ((connection-strings (split-string input "\n" t))
         (circuit (day7/make-circuit connection-strings)))
    (day7/evaluate circuit 'a))
956

Part 2

Now, take the signal you got on wire a, override wire b to that signal, and reset the other wires (including wire a). What new signal is ultimately provided to wire a?


  (let* ((connection-strings (split-string input "\n" t))
         (circuit (day7/make-circuit connection-strings)))
    (day7/circuit-put circuit 'b 956)
    (day7/evaluate circuit 'a))
40149

Day 8: Matchsticks

Space on the sleigh is limited this year, and so Santa will be bringing his list as a digital copy. He needs to know how much space it will take up when stored.

It is common in many programming languages to provide a way to escape special characters in strings. For example, C, JavaScript, Perl, Python, and even PHP handle special characters in very similar ways.

However, it is important to realize the difference between the number of characters in the code representation of the string literal and the number of characters in the in-memory string itself.

For example:

  • "" is 2 characters of code (the two double quotes), but the string contains zero characters.
  • "abc" is 5 characters of code, but 3 characters in the string data.
  • "aaa\"aaa" is 10 characters of code, but the string itself contains six "a" characters and a single, escaped quote character, for a total of 7 characters in the string data.
  • "\x27" is 6 characters of code, but the string itself contains just one - an apostrophe ('), escaped using hexadecimal notation.

Santa's list is a file that contains many double-quoted string literals, one on each line. The only escape sequences used are \\ (which represents a single backslash), \" (which represents a lone double-quote character), and \x plus two hexadecimal characters (which represents a single character with that ASCII code).

Disregarding the whitespace in the file, what is the number of characters of code for string literals minus the number of characters in memory for the values of the strings in total for the entire file?

For example, given the four strings above, the total number of characters of string code (2 + 5 + 10 + 6 = 23) minus the total number of characters in memory for string values (0 + 3 + 7 + 1 = 11) is 23 - 11 = 12.


  "qxfcsmh"
  "ffsfyxbyuhqkpwatkjgudo"
  "byc\x9dyxuafof\\\xa6uf\\axfozomj\\olh\x6a"
  "jtqvz"
  "uzezxa\"jgbmojtwyfbfguz"
  "vqsremfk\x8fxiknektafj"
  "wzntebpxnnt\"vqndz\"i\x47vvjqo\""
  "higvez\"k\"riewqk"
  "dlkrbhbrlfrp\\damiauyucwhty"
  "d\""
  "qlz"
  "ku"
  "yy\"\"uoao\"uripabop"
  "saduyrntuswlnlkuppdro\\sicxosted"
  "tj"
  "zzphopswlwdhebwkxeurvizdv"
  "xfoheirjoakrpofles\"nfu"
  "q\xb7oh\"p\xce\"n"
  "qeendp\"ercwgywdjeylxcv"
  "dcmem"
  "\"i\x13r\"l"
  "ikso\xdcbvqnbrjduh\"uqudzki\xderwk"
  "wfdsn"
  "pwynglklryhtsqbno"
  "hcoj\x63iccz\"v\"ttr"
  "zf\x23\\hlj\\kkce\\d\\asy\"yyfestwcdxyfj"
  "xs"
  "m\"tvltapxdvtrxiy"
  "bmud"
  "k\"a"
  "b\"oas"
  "\"yexnjjupoqsxyqnquy\"uzfdvetqrc"
  "vdw\xe3olxfgujaj"
  "qomcxdnd\"\\cfoe\""
  "fpul"
  "m\"avamefphkpv"
  "vvdnb\\x\\uhnxfw\"dpubfkxfmeuhnxisd"
  "hey\\"
  "ldaeigghlfey"
  "eure\"hoy\xa5iezjp\\tm"
  "yygb\"twbj\\r\"\x10gmxuhmp\""
  "weirebp\x39mqonbtmfmd"
  "ltuz\\hs\"e"
  "ysvmpc"
  "g\x8amjtt\"megl\"omsaihifwa"
  "yimmm"
  "iiyqfalh"
  "cwknlaaf"
  "q\x37feg\xc6s\"xx"
  "uayrgeurgyp\\oi"
  "xhug\"pt\"axugllbdiggzhvy"
  "kdaarqmsjfx\xc3d"
  "\"vkwla"
  "d\""
  "tmroz\"bvfinxoe\\mum\"wmm"
  "\"n\"bbswxne\\p\\yr\"qhwpdd"
  "skzlkietklkqovjhvj\xfe"
  "pbg\\pab\"bubqaf\"obzcwxwywbs\\dhtq"
  "xxjidvqh\"lx\\wu\"ij"
  "daef\x5fe\x5b\\kbeeb\x13qnydtboof"
  "ogvazaqy\"j\x73"
  "y"
  "n\"tibetedldy\\gsamm\"nwu"
  "wldkvgdtqulwkad"
  "dpmxnj"
  "twybw\"cdvf\"mjdajurokbce"
  "ru\"\\lasij\"i"
  "roc\\vra\\lhrm"
  "pbkt\x60booz\"fjlkc"
  "j\x4dytvjwrzt"
  "\\uiwjkniumxcs"
  "cbhm\"nexccior\"v\"j\"nazxilmfp\x47"
  "qdxngevzrlgoq"
  "\"lrzxftytpobsdfyrtdqpjbpuwmm\x9e"
  "mdag\x0asnck\xc2ggj\"slb\"fjy"
  "wyqkhjuazdtcgkcxvjkpnjdae"
  "aixfk\xc0iom\x21vueob"
  "dkiiakyjpkffqlluhaetires"
  "ysspv\"lysgkvnmwbbsy"
  "gy\"ryexcjjxdm\"xswssgtr"
  "s"
  "ddxv"
  "qwt\"\x27puilb\"pslmbrsxhrz"
  "qdg\xc9e\\qwtknlvkol\x54oqvmchn\\"
  "lvo"
  "b"
  "fk\"aa\"\"yenwch\\\\on"
  "srig\x63hpwaavs\\\x80qzk\"xa\"\xe6u\\wr"
  "yxjxuj\"ghyhhxfj\"\xa6qvatre"
  "yoktqxjxkzrklkoeroil"
  "\"jfmik\""
  "smgseztzdwldikbqrh\""
  "jftahgctf\"hoqy"
  "tcnhicr\"znpgckt\"ble"
  "vqktnkodh\"lo\"a\\bkmdjqqnsqr"
  "ztnirfzqq"
  "s"
  "xx"
  "iqj\"y\\hqgzflwrdsusasekyrxbp\\ad"
  "\\xzjhlaiynkioz\"\"bxepzimvgwt"
  "s\x36rbw"
  "mniieztwrisvdx"
  "atyfxioy\x2b\\"
  "irde\x85\x5cvbah\\jekw\"ia"
  "bdmftlhkwrprmpat\"prfaocvp"
  "w\\k"
  "umbpausy"
  "zfauhpsangy"
  "p\"zqyw"
  "wtztypyqvnnxzvlvipnq\"zu"
  "deicgwq\\oqvajpbov\\or\"kgplwu"
  "mbzlfgpi\\\\zqcidjpzqdzxityxa"
  "lfkxvhma"
  "\xf2yduqzqr\"\\fak\"p\"n"
  "mpajacfuxotonpadvng"
  "anb\\telzvcdu\\a\xf2flfq"
  "lrs\"ebethwpmuuc\"\x86ygr"
  "qmvdbhtumzc\"ci"
  "meet"
  "yopg\x0fdxdq\"h\\ugsu\xffmolxjv"
  "uhy"
  "fzgidrtzycsireghazscvmwcfmw\\t"
  "cqohkhpgvpru"
  "bihyigtnvmevx\"xx"
  "xz"
  "zofomwotzuxsjk\"q\"mc\"js\"dnmalhxd"
  "\\ktnddux\\fqvt\"ibnjntjcbn"
  "ia"
  "htjadnefwetyp\xd5kbrwfycbyy"
  "\"\\hkuxqddnao"
  "meqqsz\x83luecpgaem"
  "cvks\x87frvxo\"svqivqsdpgwhukmju"
  "sgmxiai\\o\"riufxwjfigr\xdf"
  "fgywdfecqufccpcdn"
  "faghjoq\x28abxnpxj"
  "zuppgzcfb\"dctvp\"elup\"zxkopx"
  "xqs\x45xxdqcihbwghmzoa"
  "anbnlp\\cgcvm\"hc"
  "xf\"fgrngwzys"
  "nrxsjduedcy\x24"
  "\x71sxl\"gj\"sds\"ulcruguz\\t\\ssvjcwhi"
  "jhj\"msch"
  "qpovolktfwyiuyicbfeeju\x01"
  "nkyxmb\"qyqultgt\"nmvzvvnxnb"
  "ycsrkbstgzqb\"uv\\cisn"
  "s"
  "ueptjnn\"\"sh"
  "lp\"z\"d\"mxtxiy"
  "yzjtvockdnvbubqabjourf\"k\"uoxwle"
  "\x82\"wqm\""
  "\xb5cwtuks\x5fpgh"
  "wd"
  "tbvf"
  "ttbmzdgn"
  "vfpiyfdejyrlbgcdtwzbnm"
  "uc"
  "otdcmhpjagqix"
  "\\\xb1qso\"s"
  "scowax"
  "behpstjdh\xccqlgnqjyz\"eesn"
  "r\xe1cbnjwzveoomkzlo\\kxlfouhm"
  "jgrl"
  "kzqs\\r"
  "ctscb\x7fthwkdyko\"\x62pkf\"d\xe6knmhurg"
  "tc\"kw\x3ftt"
  "bxb\x5ccl"
  "jyrmfbphsldwpq"
  "jylpvysl\"\"juducjg"
  "en\\m\"kxpq\"wpb\\\""
  "madouht\"bmdwvnyqvpnawiphgac\""
  "vuxpk\"ltucrw"
  "aae\x60arr"
  "ttitnne\"kilkrgssnr\xfdurzh"
  "oalw"
  "pc\"\"gktkdykzbdpkwigucqni\"nxiqx"
  "dbrsaj"
  "bgzsowyxcbrvhtvekhsh\"qgd"
  "kudfemvk\"\"\"hkbrbil\"chkqoa"
  "zjzgj\\ekbhyfzufy"
  "\\acos\"fqekuxqzxbmkbnn\x1ejzwrm"
  "elxahvudn\"txtmomotgw"
  "\x2eoxmwdhelpr\"cgi\xf7pzvb"
  "eapheklx"
  "hfvma\"mietvc\"tszbbm\"czex"
  "h\"iiockj\\\xc1et"
  "d\"rmjjftm"
  "qlvhdcbqtyrhlc\\"
  "yy\"rsucjtulm\"coryri\"eqjlbmk"
  "tv"
  "r\"bfuht\\jjgujp\""
  "kukxvuauamtdosngdjlkauylttaokaj"
  "srgost\"\"rbkcqtlccu\x65ohjptstrjkzy"
  "yxwxl\\yjilwwxffrjjuazmzjs"
  "dxlw\\fkstu\"hjrtiafhyuoh\"sewabne"
  "\x88sj\"v"
  "rfzprz\xec\"oxqclu\"krzefp\\q"
  "cfmhdbjuhrcymgxpylllyvpni"
  "ucrmjvmimmcq\x88\xd9\"lz"
  "lujtt\""
  "gvbqoixn\"pmledpjmo\"flydnwkfxllf"
  "dvxqlbshhmelsk\x8big\"l"
  "mx\x54lma\x8bbguxejg"
  "\x66jdati\xeceieo"
  "\"iyyupixei\x54ff"
  "xohzf\"rbxsoksxamiu"
  "vlhthspeshzbppa\x4drhqnohjop\"\"mfjd"
  "f\"tvxxla\"vurian\"\"idjq\x3aptm\xc3olep"
  "gzqz"
  "kbq\\wogye\\altvi\\hbvmodny"
  "j\xd8"
  "ofjozdhkblvndl"
  "hbitoupimbawimxlxqze"
  "ypeleimnme"
  "xfwdrzsc\\oxqamawyizvi\\y"
  "enoikppx\xa1ixe\"yo\"gumye"
  "fb"
  "vzf"
  "zxidr"
  "cu\x31beirsywtskq"
  "lxpjbvqzztafwezd"
  "\\jyxeuo\x18bv"
  "b\"vawc\"p\\\\giern\"b"
  "odizunx\"\"t\\yicdn\"x\"sdiz"
  "\"\"tebrtsi"
  "ctyzsxv\xa6pegfkwsi\"tgyltaakytccb"
  "htxwbofchvmzbppycccliyik\xe5a"
  "ggsslefamsklezqkrd"
  "rcep\"fnimwvvdx\"l"
  "zyrzlqmd\x12egvqs\\llqyie"
  "\x07gsqyrr\\rcyhyspsvn"
  "butg\""
  "gb"
  "gywkoxf\"jsg\\wtopxvumirqxlwz"
  "rj\"ir\"wldwveair\x2es\"dhjrdehbqnzl"
  "ru\"elktnsbxufk\\ejufjfjlevt\\lrzd"
  "\"widsvok"
  "oy\"\x81nuesvw"
  "ay"
  "syticfac\x1cfjsivwlmy\"pumsqlqqzx"
  "m"
  "rjjkfh\x78cf\x2brgceg\"jmdyas\"\\xlv\xb6p"
  "tmuvo\"\x3ffdqdovjmdmkgpstotojkv\"as"
  "jd\\ojvynhxllfzzxvbn\"wrpphcvx"
  "pz"
  "\"twr"
  "n\\hdzmxe\"mzjjeadlz"
  "fb\"rprxuagvahjnri"
  "rfmexmjjgh\\xrnmyvnatrvfruflaqjnd"
  "obbbde\"co\"qr\"qpiwjgqahqm\\jjp\""
  "vpbq\"\"y\"czk\\b\x52ed\"lnzepobp"
  "syzeajzfarplydipny\"y\"\xe8ad"
  "mpyodwb"
  "\x47rakphlqqptd"
  "wa\"oj\"aiy"
  "a"
  "ropozx"
  "q\x51nbtlwa"
  "etukvgx\\jqxlkq"
  "\"tp\"rah\"pg\"s\"bpdtes\\tkasdhqd"
  "dn\"qqpkikadowssb\xcah\"dzpsf\\ect\"jdh"
  "pxunovbbrrn\\vullyn\"bno\"\"\"myfxlp\""
  "qaixyazuryvkmoulhcqaotegfj\\mpzm"
  "bvfrbicutzbjwn\\oml\"cf\"d\"ezcpv\"j"
  "rmbrdtneudemigdhelmb"
  "aq\\aurmbhy"
  "wujqvzw"
  "gf\"tssmvm\"gm\"hu\x9a\xb7yjawsa"
  "hrhqqxow\xe2gsydtdspcfqy\"zw\\ou"
  "ianwwf\\yko\\tdujhhqdi"
  "xylz\"zpvpab"
  "lwuopbeeegp"
  "aoop\x49jhhcexdmdtun"
  "\\\\mouqqcsgmz"
  "tltuvwhveau\x43b\"ymxjlcgiymcynwt"
  "gsugerumpyuhtjljbhrdyoj"
  "lnjm\xb8wg\"ajh"
  "zmspue\"nfttdon\\b\"eww"
  "\"w\x67jwaq\x7ernmyvs\\rmdsuwydsd\"th"
  "ogtgvtlmcvgllyv"
  "z\"fqi\"rvddoehrciyl"
  "yustxxtot\"muec\"xvfdbzunzvveq"
  "mqslw"
  "txqnyvzmibqgjs\xb6xy\x86nfalfyx"
  "kzhehlmkholov"
  "plpmywcnirrjutjguosh\\"
  "pydbnqofv\"dn\\m"
  "aegqof"
  "eambmxt\\dxagoogl\\zapfwwlmk"
  "afbmqitxxqhddlozuxcpjxgh"
  "vgts"
  "bfdpqtoxzzhmzcilehnflna"
  "s\"idpz"
  "\xcfhgly\"nlmztwybx\"ecezmsxaqw"
  "aackfgndqcqiy"
  "\x22unqdlsrvgzfaohoffgxzfpir\"s"
  "abh\"ydv\"kbpdhrerl"
  "bdzpg"
  "ekwgkywtmzp"
  "wtoodejqmrrgslhvnk\"pi\"ldnogpth"
  "njro\x68qgbx\xe4af\"\\suan"
  (defun day8/hex-replacements (string-literal)
    (-map (lambda (escaped-hex)
            (let ((hex-code (string-to-number (substring escaped-hex 2) 16)))
              (cons escaped-hex (char-to-string hex-code))))
          (-map #'car (s-match-strings-all "\\\\x[0-9,a-f][0-9,a-f]" string-literal))))

  (defun day8/parse-string (string-literal)
    (let ((contents (substring string-literal 1 -1)))
      (-reduce-from
       (lambda (acc replacement)
         (s-replace (car replacement)
                    (cdr replacement)
                    acc))
       contents
       (append '(("\\\"" . "\"")
                 ("\\\\" . "\\"))
               (day8/hex-replacements contents)))))

  (ert-deftest day8/parse-string ()
    (should (string-equal ""
                          (day8/parse-string "\"\"")))
    (should (string-equal "abc"
                          (day8/parse-string "\"abc\"")))
    (should (string-equal "aaa\"aaa"
                          (day8/parse-string "\"aaa\\\"aaa\"")))
    (should (string-equal "'"
                          (day8/parse-string "\"\\x27\""))))


  (let* ((code-strings (split-string input "\n" t))
         (string-values (-map #'day8/parse-string code-strings)))
    (- (-sum (-map #'length code-strings))
       (-sum (-map #'length string-values))))
1350

Part 2

Now, let's go the other way. In addition to finding the number of characters of code, you should now encode each code representation as a new string and find the number of characters of the new encoded representation, including the surrounding double quotes.

For example:

  • "" encodes to "\"\"", an increase from 2 characters to 6.
  • "abc" encodes to "\"abc\"", an increase from 5 characters to 9.
  • "aaa\"aaa" encodes to "\"aaa\\\"aaa\"", an increase from 10 characters to 16.
  • "\x27" encodes to "\"\\x27\"", an increase from 6 characters to 11.

Your task is to find the total number of characters to represent the newly encoded strings minus the number of characters of code in each original string literal. For example, for the strings above, the total encoded length (6 + 9 + 16 + 11 = 42) minus the characters in the original code representation (23, just like in the first part of this puzzle) is 42 - 23 = 19.


  (defun day8/encode-string (string-literal)
    (format "\"%s\""
            (-reduce-from
             (lambda (acc replacement)
               (s-replace (car replacement)
                          (cdr replacement)
                          acc))
             string-literal
             '(("\\" . "\\\\")
               ("\"" . "\\\"")))))

  (ert-deftest day8/encode-string ()
    (should (string-equal "\"\\\"\\\"\""
                          (day8/encode-string "\"\"")))
    (should (string-equal "\"\\\"abc\\\"\""
                          (day8/encode-string "\"abc\"")))
    (should (string-equal "\"\\\"aaa\\\\\\\"aaa\\\"\""
                          (day8/encode-string "\"aaa\\\"aaa\"")))
    (should (string-equal "\"\\\"\\\\x27\\\"\""
                          (day8/encode-string "\"\\x27\""))))

  (let* ((code-strings (split-string input "\n" t))
         (encoded-values (-map #'day8/encode-string code-strings)))
    (- (-sum (-map #'length encoded-values))
       (-sum (-map #'length code-strings))))
2085

Day 9: All in a Single Night

Every year, Santa manages to deliver all of his presents in a single night.

This year, however, he has some new locations to visit; his elves have provided him the distances between every pair of locations. He can start and end at any two (different) locations he wants, but he must visit each location exactly once. What is the shortest distance he can travel to achieve this?

For example, given the following distances:

London to Dublin = 464
London to Belfast = 518
Dublin to Belfast = 141

The possible routes are therefore:

Dublin -> London -> Belfast = 982
London -> Dublin -> Belfast = 605
London -> Belfast -> Dublin = 659
Dublin -> Belfast -> London = 659
Belfast -> Dublin -> London = 605
Belfast -> London -> Dublin = 982

The shortest of these is London -> Dublin -> Belfast = 605, and so the answer is 605 in this example.

What is the distance of the shortest route?


  Tristram to AlphaCentauri = 34
  Tristram to Snowdin = 100
  Tristram to Tambi = 63
  Tristram to Faerun = 108
  Tristram to Norrath = 111
  Tristram to Straylight = 89
  Tristram to Arbre = 132
  AlphaCentauri to Snowdin = 4
  AlphaCentauri to Tambi = 79
  AlphaCentauri to Faerun = 44
  AlphaCentauri to Norrath = 147
  AlphaCentauri to Straylight = 133
  AlphaCentauri to Arbre = 74
  Snowdin to Tambi = 105
  Snowdin to Faerun = 95
  Snowdin to Norrath = 48
  Snowdin to Straylight = 88
  Snowdin to Arbre = 7
  Tambi to Faerun = 68
  Tambi to Norrath = 134
  Tambi to Straylight = 107
  Tambi to Arbre = 40
  Faerun to Norrath = 11
  Faerun to Straylight = 66
  Faerun to Arbre = 144
  Norrath to Straylight = 115
  Norrath to Arbre = 135
  Straylight to Arbre = 127
  (defun day9/make-map ()
    (make-hash-table :test #'equal))

  (defun day9/store-distance (map a b distance)
    (puthash (cons a b) distance map))

  (defun day9/distance (map a b)
    (gethash (cons a b) map
             (gethash (cons b a) map 0)))

  (defun day9/parse-distance (distance-string)
    (if (string-match "\\(.*?\\) to \\(.*?\\) = \\([0-9]+\\)"
                      distance-string)
        (cons (cons (match-string-no-properties 1 distance-string)
                    (match-string-no-properties 2 distance-string))
              (string-to-number (match-string-no-properties 3 distance-string)))))

  (ert-deftest day9/parse-distance ()
    (should (equal '(("London" . "Dublin") . 464)
                   (day9/parse-distance "London to Dublin = 464"))))

  (defun day9/build-map (input)
    (let ((map (day9/make-map)))
      (-each (-map #'day9/parse-distance
                   (split-string input "\n" t))
        (lambda (distance)
          (day9/store-distance map
                               (caar distance)
                               (cdar distance)
                               (cdr distance))))
      map))

  (defun day9/trip-distance (map trip)
    (let ((start (first trip))
          (steps (rest trip)))
      (if (null steps) 0
        (+ (day9/distance map start (first steps))
           (day9/trip-distance map steps)))))

  (defun day9/trip-distance< (min current map trip)
    (let ((start (first trip))
          (steps (rest trip)))
      (cond ((and min (> current min)) nil)
            ((null steps) current)
            (t (let ((distance (day9/distance map start (first steps))))
                 (day9/trip-distance< min (+ distance current) map
                                      steps))))))

  (lexical-let ((example example))
    (ert-deftest day9/trip-distance ()
      (let ((map (day9/build-map example)))
        (should (eq 982 (day9/trip-distance map
                                            '("Dublin"
                                              "London"
                                              "Belfast")))))))

  (defun day9/permutations (lst)
    (if (not lst) '(nil)
      (mapcan
       (lambda (e)
         (mapcar (lambda (perm) (cons e perm))
                 (day9/permutations (-remove-item e lst))))
       lst)))

  (defun day9/trips (map)
    "Don't include reversed location permutations"
    (cl-loop for perm in (day9/permutations (day9/locations map))
              with unique-perms = (make-hash-table :test 'equal)
              unless (gethash (reverse perm) unique-perms)
              do (puthash perm t unique-perms)
              finally return (hash-table-keys unique-perms)))

  (defun day9/locations (map)
    (-distinct
     (append (-map #'car (hash-table-keys map))
             (-map #'cdr (hash-table-keys map)))))

  (lexical-let ((example example))
    (ert-deftest day9/locations ()
      (let ((map (day9/build-map example)))
        (should (seq-empty-p
                 (-difference '("Dublin" "London" "Belfast")
                              (day9/locations map)))))))

  (defun day9/min-trip-distance (map)
    (cl-loop for path in (day9/trips map)
             with min-distance
             do (let ((distance (day9/trip-distance< min-distance 0 map path)))
                  (if (and (null min-distance) distance)
                      (setf min-distance distance))
                  (if (and min-distance distance
                           (< distance min-distance))
                      (setf min-distance distance)))
             finally return min-distance))

  (day9/min-trip-distance
   (day9/build-map input))
251

Part 2

The next year, just to show off, Santa decides to take the route with the longest distance instead.

He can still start and end at any two (different) locations he wants, and he still must visit each location exactly once.

For example, given the distances above, the longest route would be 982 via (for example) Dublin -> London -> Belfast.

What is the distance of the longest route?


  (defun day9/trip-distance> (max current map trip)
    (let ((start (first trip))
          (steps (rest trip)))
      (cond ((null steps) current)
            (t (let ((distance (day9/distance map start (first steps))))
                 (day9/trip-distance> max (+ distance current) map
                                      steps))))))

  (defun day9/max-trip-distance (map)
    (cl-loop for path in (day9/trips map)
             with max-distance
             do (let ((distance (day9/trip-distance> max-distance 0 map path)))
                  (if (and (null max-distance) distance)
                      (setf max-distance distance))
                  (if (and max-distance distance
                           (< max-distance distance))
                      (setf max-distance distance)))
             finally return max-distance))

  (day9/max-trip-distance
   (day9/build-map input))
898

Day 10: Elves Look, Elves Say

Today, the Elves are playing a game called look-and-say. They take turns making sequences by reading aloud the previous sequence and using that reading as the next sequence. For example, 211 is read as "one two, two ones", which becomes 1221 (1 2, 2 =1=s).

Look-and-say sequences are generated iteratively, using the previous value as input for the next step. For each step, take the previous value, and replace each run of digits (like 111) with the number of digits (3) followed by the digit itself (1).

For example:

  • 1 becomes 11 (1 copy of digit 1).
  • 11 becomes 21 (2 copies of digit 1).
  • 21 becomes 1211 (one 2 followed by one 1).
  • 1211 becomes 111221 (one 1, one 2, and two =1=s).
  • 111221 becomes 312211 (three 1=s, two =2=s, and one =1).

Starting with the digits in your puzzle input, apply this process 40 times. What is the length of the result?


3113322113
  (defun day10/say-sequence (seq)
    (let ((partitioned ))
      (mapconcat
       (lambda (chars)
         (format "%d%s" (length chars) (char-to-string (car chars))))
       (-partition-by #'identity (seq-into seq 'list))
       "")))

  (ert-deftest day10/say-sequence ()
    (should (string-equal "11" (day10/say-sequence "1")))
    (should (string-equal "21" (day10/say-sequence "11")))
    (should (string-equal "1211" (day10/say-sequence "21")))
    (should (string-equal "111221" (day10/say-sequence "1211")))
    (should (string-equal "312211" (day10/say-sequence "111221"))))

  (defun day10/say-sequence-n (times seq)
    (-reduce-from
     (lambda (acc next)
       (day10/say-sequence acc))
     seq
     (number-sequence 1 times)))

  (ert-deftest day10/say-sequence-n ()
    (should (string-equal "312211" (day10/say-sequence-n 5 "1"))))

  (length (day10/say-sequence-n 40 (string-trim input)))
329356

Part 2

Neat, right? You might also enjoy hearing John Conway talking about this sequence (that's Conway of Conway's Game of Life fame).

Now, starting again with the digits in your puzzle input, apply this process 50 times. What is the length of the new result?


  (length (day10/say-sequence-n 50 (string-trim input)))
4666278

Day 11: Corporate Policy

Santa's previous password expired, and he needs help choosing a new one.

To help him remember his new password after the old one expires, Santa has devised a method of coming up with a password based on the previous one. Corporate policy dictates that passwords must be exactly eight lowercase letters (for security reasons), so he finds his new password by incrementing his old password string repeatedly until it is valid.

Incrementing is just like counting with numbers: xx, xy, xz, ya, yb, and so on. Increase the rightmost letter one step; if it was z, it wraps around to a, and repeat with the next letter to the left until one doesn't wrap around.

Unfortunately for Santa, a new Security-Elf recently started, and he has imposed some additional password requirements:

  • Passwords must include one increasing straight of at least three letters, like abc, bcd, cde, and so on, up to xyz. They cannot skip letters; abd doesn't count.
  • Passwords may not contain the letters i, o, or l, as these letters can be mistaken for other characters and are therefore confusing.
  • Passwords must contain at least two different, non-overlapping pairs of letters, like aa, bb, or zz.

For example:

  • hijklmmn meets the first requirement (because it contains the straight hij) but fails the second requirement requirement (because it contains i and l).
  • abbceffg meets the third requirement (because it repeats bb and ff) but fails the first requirement.
  • abbcegjk fails the third requirement, because it only has one double letter (bb).
  • The next password after abcdefgh is abcdffaa.
  • The next password after ghijklmn is ghjaabcc, because you eventually skip all the passwords that start with ghi…, since i is not allowed.

Given Santa's current password (your puzzle input), what should his next password be?


cqjxjnds
  (defun day11/inc-password (password)
    (cl-loop with carry = t
             for char across (s-reverse password)
             for new-char = (if carry (+ 1 char)
                              char)
             if (> new-char ?z)
               concat "a" into next-password
               and do (setq carry t)
             else
               concat (char-to-string new-char) into next-password
               and do (setq carry nil)
             finally return (s-reverse
                             (if carry (s-concat next-password "a")
                               next-password))))

  (ert-deftest day11/inc-password ()
    (should (equal "xy" (day11/inc-password "xx")))
    (should (equal "xz" (day11/inc-password "xy")))
    (should (equal "ya" (day11/inc-password "xz")))
    (should (equal "aaa" (day11/inc-password "zz"))))

  (defun day11/includes-straight? (password)
    (if password
        (cl-loop with chars = (string-to-list password)
                 with straight = 1
                 for current = (car chars)
                 for next = (cadr chars)
                 while (and next (< straight 3))
                 do (if (eq next (+ 1 current))
                        (setq straight (+ 1 straight))
                      (setq straight 1))
                 (setq chars (rest chars))
                 finally return (eq straight 3))))

  (defun day11/no-confusing-letters? (password)
    (not (string-match-p "[iol]" password)))

  (defun day11/two-different-pairs? (password)
    (->> password
         string-to-list
         (-partition-by #'identity)
         (-filter (lambda (x) (>= (length x) 2)))
         (-map #'car)
         -distinct
         length
         (<= 2)))

  (defun day11/valid-password? (password)
    (and (day11/no-confusing-letters? password)
         (day11/two-different-pairs? password)
         (day11/includes-straight? password)))

  (ert-deftest day11/valid-password? ()
    (should-not (day11/valid-password? "hijklmmn"))
    (should-not (day11/valid-password? "abbceffg"))
    (should-not (day11/valid-password? "abbcefgk"))
    (should (day11/valid-password? "abcdffaa"))
    (should (day11/valid-password? "ghjaabcc")))

  (defun day11/next (next-fn predicate value)
    (cl-loop with v = value
             do (setq v (funcall next-fn v))
             until (funcall predicate v)
             finally return v))

  (defun day11/next-password (password)
    (day11/next
     #'day11/inc-password
     #'day11/valid-password?
     password))

  (ert-deftest day11/next-password ()
    (should (equal "abcdffaa"
                   (day11/next-password "abcdefgh")))
    (should (equal "ghjaabcc"
                   (day11/next-password "ghijklmn"))))
day11/next-password
  (defun day11/to-decimal (password)
    (cl-loop with p = ""
             for times from 0
             until (equal password p)
             do (setq p (day11/inc-password p))
             finally return times))

  (ert-deftest day11/to-decimal ()
    (should (eq 1 (day11/to-decimal "a")))
    (should (eq 27 (day11/to-decimal "aa")))
    (should (eq 731 (day11/to-decimal "abc"))))
day11/to-decimal
Password Decimal
a 1
aa 27
aaa 703
aaaa 18279
aa ba 26
aaa baa 676
aaaa baaa 17576
string e decimal 26^e 𝚫
z 1 26 26 0
zz 2 702 676 26
zzz 3 18278 17576 702
  (defun day11/max (pos)
    (1- (cl-loop for x from 0 to pos
                 sum (expt 26 x))))

  (cl-loop for x from 0 to 5
           collect (list x (day11/max x)))
0 0
1 26
2 702
3 18278
4 475254
5 12356630
  (cl-loop for pos from 0
           sum (expt 26 pos) into maximum
           until (> maximum 702)
           finally return pos)
2

731 = abc = (0 1 2)

  (defun day11/from-decimal (n)
    (cl-loop with remaining = n
             with max-pos = (cl-loop for pos from 0
                                     sum (expt 26 pos) into maximum
                                     until (> maximum n)
                                     finally return (1- pos))
             for pos downfrom max-pos to 0
             for value-at-pos = (if (= 0 (% remaining (expt 26 pos))) (1- (/ remaining (expt 26 pos)))
                                  (/ remaining (expt 26 pos)))
             for digit = (if (= 0 pos) value-at-pos
                           (1- value-at-pos))
             ;; collect (list pos digit)
             concat (char-to-string (+ ?a digit))
             do (setq remaining (- remaining (* value-at-pos (expt 26 pos))))
             ))

  (ert-deftest day11/from-decimal ()
    (should (equal "a" (day11/from-decimal 1)))
    (should (equal "z" (day11/from-decimal 26)))
    (should (equal "xz" (day11/from-decimal 650)))
    (should (equal "abc" (day11/from-decimal 731)))
    (should (equal "zzz" (day11/from-decimal 18278))))

  (defun day11/to-decimal (password)
    (cl-loop for chars = (string-to-list password) then (rest chars)
             while chars
             sum (* (1+ (- (first chars) ?a))
                    (expt 26 (1- (length chars))))))

  (defun day11/inc-password (password)
    (-> password
        day11/to-decimal
        1+
        day11/from-decimal))
day11/inc-password
  (defun day11/from-decimal (n)
    (cl-loop with remaining = n
             ;; How many digits long should this number be? This will
             ;; also be used as the max exponent of 26 to work down
             ;; from.
             with max-exp = (cl-loop for pos from 0
                                     sum (expt 26 pos) into maximum
                                     while (< (1- maximum) n)
                                     maximize pos)
             for exp downfrom max-exp to 0
             for exp-val = (expt 26 exp)
             if (<= 27 (/ remaining exp-val))
             ;; Too big, let the remaining digits absorb it
             collect 26 into values
             and do (setq remaining (- remaining (* 26 exp-val)))
             else if (and (> exp 0) (= 0 (% remaining 26)))
             ;; Perfectly divisible! Except, oh no, we don't have zeros.
             ;; Drop it a by multiple and carry the remainder through to
             ;; the next iteration.
             collect (/ (- remaining exp-val) exp-val) into values
             and do (setq remaining exp-val)
             else
             collect (/ remaining exp-val) into values
             and do (setq remaining (% remaining exp-val))
             finally return (->> values
                                (-map '1-)
                                (-map (apply-partially '+ ?a))
                                (apply 'string))))

  (day11/from-decimal 18279)
aaaa

Boo, next-password is still too slow. Slower, maybe.

  (defun day11/from-decimal (n)
    (->>
     (-reduce-from
      (lambda (acc exp-val)
        (let ((values (car acc))
              (remaining (cdr acc)))
          (cond ((<= 27 (/ remaining exp-val))
                 (cons (cons 26 values)
                       (- remaining (* 26 exp-val))))
                ((and (> exp-val 1) (= 0 (% remaining 26)))
                 (cons (cons (/ (- remaining exp-val) exp-val) values)
                       exp-val))
                (t
                 (cons (cons (/ remaining exp-val) values)
                       (% remaining exp-val))))
          ))
      (cons nil n)
      (reverse (cl-loop for pos from 0
                        sum (expt 26 pos) into maximum
                        while (< (1- maximum) n)
                        collect (expt 26 pos))))
     car
     reverse
     (-map '1-)
     (-map (apply-partially '+ ?a))
     (apply 'string)))

  (day11/from-decimal 18279)
aaaa