advent-of-code/advent-of-code.org

35 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