diff --git a/input/18.txt b/input/18.txt new file mode 100644 index 0000000..8dadac8 --- /dev/null +++ b/input/18.txt @@ -0,0 +1,100 @@ +[[8,8],5] +[[[[9,0],1],4],[[3,6],[0,5]]] +[[9,[0,[4,5]]],[1,[[6,8],4]]] +[[8,7],[[[8,5],[2,0]],[[6,3],[5,0]]]] +[[[1,8],2],[[[9,1],[2,0]],[1,[9,4]]]] +[[[6,[8,8]],[6,4]],[[8,2],[[0,8],9]]] +[[[6,3],[9,[9,1]]],[[0,0],1]] +[[[[2,7],[8,2]],[[9,6],[5,1]]],[[[7,6],[6,0]],[4,2]]] +[[[8,[9,1]],[9,3]],[[[5,4],[8,0]],[[3,5],[9,5]]]] +[[[3,[4,9]],2],[[7,9],7]] +[[[7,[9,0]],5],[[[3,4],[2,6]],[[3,5],[7,2]]]] +[[8,[8,9]],[[[3,2],[6,2]],4]] +[[[[8,0],3],[3,8]],[[[5,0],[7,3]],[5,[3,0]]]] +[4,[[3,[0,9]],[[5,0],[2,0]]]] +[[[[0,1],5],[3,[9,6]]],[[[4,4],5],[[3,8],[5,1]]]] +[[[[4,8],8],0],[5,[[1,7],[4,3]]]] +[[3,[[1,1],[5,6]]],[7,[[4,0],[0,7]]]] +[9,[4,[[1,3],2]]] +[[[1,[2,7]],[[4,7],3]],[2,1]] +[[[9,5],[2,5]],[[[8,9],[4,5]],2]] +[[2,[[7,4],6]],[[1,[0,7]],[[4,8],8]]] +[[[[0,5],3],[7,0]],9] +[[[[1,4],[4,3]],7],[[9,4],[6,[8,6]]]] +[[[7,2],[[3,3],1]],[5,9]] +[[[9,[6,2]],2],[[6,5],6]] +[[5,[3,2]],[[[2,4],[1,5]],[6,3]]] +[6,3] +[[9,6],[[[8,2],[5,6]],[[3,5],[3,3]]]] +[[[[2,5],7],4],[8,3]] +[[[[6,1],9],[0,6]],[6,2]] +[[[[8,4],2],[[0,1],[5,8]]],9] +[[[7,0],[4,9]],[[[9,9],[4,4]],[6,6]]] +[[[9,8],[2,0]],[[9,[6,2]],[6,[5,6]]]] +[[[9,8],[[0,6],[3,5]]],[[[4,7],[7,5]],[7,[8,5]]]] +[[[[9,0],[1,6]],[2,[5,3]]],[[[2,0],[0,3]],[[9,1],[7,7]]]] +[[[5,[2,2]],[2,[1,0]]],[1,1]] +[[[9,[7,2]],[[2,7],1]],[[5,7],[[8,7],7]]] +[[[9,[9,4]],[[0,8],2]],[0,[[2,2],[4,1]]]] +[[[5,5],[9,[2,0]]],[[[9,0],6],1]] +[[[1,9],[[9,5],[5,6]]],[6,[5,[9,4]]]] +[[[[8,6],9],9],[[7,2],[7,[2,6]]]] +[[[[6,4],7],7],[[2,[9,7]],7]] +[[7,[[5,6],9]],[[[9,8],8],[[8,9],[1,0]]]] +[[[0,[7,6]],0],[[[2,5],1],9]] +[[[3,[4,1]],[4,2]],[0,[[6,0],[1,6]]]] +[[9,[0,0]],[[[3,0],[9,9]],[1,[1,5]]]] +[[[[9,9],1],6],[5,6]] +[3,4] +[[[[5,4],9],6],2] +[[5,4],[[6,[7,4]],[[0,3],0]]] +[[[3,[9,6]],4],[[[9,8],6],3]] +[[5,[1,[5,5]]],[[[3,8],[0,1]],[[9,3],[6,2]]]] +[[4,[0,3]],1] +[[[7,[2,9]],[[5,8],2]],[[[4,4],[2,0]],8]] +[[[[4,0],0],8],7] +[[[[3,0],0],[[6,0],3]],[[[1,5],1],[3,[0,0]]]] +[[[[8,1],5],0],[[[3,9],[8,3]],[[6,9],[5,1]]]] +[[7,7],[[[8,5],2],[9,2]]] +[[[[4,9],9],[6,[5,3]]],[[[7,1],[7,1]],[[9,5],[7,0]]]] +[[7,[0,5]],[7,[2,[1,6]]]] +[[9,[0,[0,2]]],[[1,1],[[6,6],[5,3]]]] +[[[2,9],[[6,9],9]],[[[4,2],7],[1,[2,3]]]] +[[[0,1],[3,3]],[3,[[2,7],2]]] +[[[5,6],8],[[[4,9],[3,3]],[6,[5,2]]]] +[[4,[4,[2,5]]],[[2,[4,8]],[3,[7,7]]]] +[[2,5],[[[9,6],[9,3]],[[4,5],[2,3]]]] +[[5,[0,5]],[[[2,1],[0,5]],3]] +[[[[2,0],5],[[7,9],[4,5]]],[0,[[1,4],9]]] +[[[[1,3],2],[[3,9],[9,5]]],[[[4,1],[3,8]],0]] +[[[[1,8],[8,3]],[3,0]],[[5,1],[4,8]]] +[[1,6],[3,2]] +[[4,5],[[[9,3],[8,6]],[2,[8,6]]]] +[[[[4,4],1],[[7,3],2]],[[9,[2,1]],[8,2]]] +[0,[[2,[3,8]],9]] +[[1,[5,0]],[0,[[2,6],[8,5]]]] +[[6,[6,1]],[[2,[7,9]],[[8,3],1]]] +[[[2,[5,9]],[[8,9],1]],[[[5,2],2],4]] +[[[4,3],5],[[6,[3,6]],5]] +[1,[6,[6,2]]] +[[[[4,9],3],9],[[3,9],[8,[4,9]]]] +[[[[7,1],[1,6]],[[7,8],[3,7]]],[[[5,3],7],[9,[3,1]]]] +[[[[0,8],[8,9]],2],7] +[[[[3,7],[9,8]],[[7,1],8]],[[4,[4,6]],8]] +[3,[3,[[4,4],5]]] +[[3,[[2,3],7]],[[7,9],2]] +[[[[0,6],[5,1]],[[7,2],5]],[9,8]] +[[4,0],[[4,3],[7,2]]] +[[[8,[1,1]],[7,[9,1]]],[9,[9,[0,8]]]] +[9,[[[4,5],8],[[3,4],9]]] +[[[6,[4,7]],[8,7]],[[[3,8],5],[[2,1],[3,5]]]] +[[[[5,5],[6,8]],[[2,3],6]],[8,[5,7]]] +[[5,[[6,1],[3,6]]],[[[0,6],[7,1]],[9,[8,4]]]] +[[[[0,1],[4,9]],[[1,7],[3,3]]],[6,[3,[6,1]]]] +[[[[3,8],5],[[4,7],2]],2] +[[6,[[4,4],0]],[[2,[4,5]],[8,2]]] +[[6,[9,[7,0]]],[[9,[1,6]],[[6,1],1]]] +[[[[2,1],[5,7]],[5,[9,3]]],[[[7,9],[4,2]],4]] +[[3,1],[[7,8],[[8,8],9]]] +[[[[9,4],[1,8]],[9,[3,7]]],[[6,9],[[7,2],1]]] +[[[9,3],2],9] diff --git a/src/18.rkt b/src/18.rkt new file mode 100644 index 0000000..b38b08e --- /dev/null +++ b/src/18.rkt @@ -0,0 +1,209 @@ +#lang racket + +(require "../lib.rkt") + +;; raw is one of: +;; - number? +;; - (list raw? raw?) + +;; raw? +(define input + (for/list ([line (problem-input 18)]) + (read (open-input-string (string-replace line "," " "))))) + +;; type: (or/c 'root 'left 'right) +;; parent: (or/c pair? #f) +;; left right: (or/c number? pair?) +(struct pair (type parent left right) #:mutable #:transparent) + +;; (or/c number? pair?) (or/c number? pair?) -> pair? +;; Combine two pairs into a root pair +(define (combine left right) + (define root (pair 'root #f left right)) + (when (pair? left) + (set-pair-parent! left root) + (set-pair-type! left 'left)) + (when (pair? right) + (set-pair-parent! right root) + (set-pair-type! right 'right)) + root) + +;; raw? -> pair? +(define (raw->pair x) + (match x + [(? number? n) n] + [(list left right) + (define left-pair (raw->pair left)) + (define right-pair (raw->pair right)) + (combine left-pair right-pair)])) + +;; pair? -> string? +(define (pair->string p) + (if (number? p) + (format "~a" p) + (format "[~a,~a]" + (pair->string (pair-left p)) + (pair->string (pair-right p))))) + +;; EXPLODE ;; + +;; number? pair? -> void? +;; Effect: Adds given number to deepest left node +(define (add-leftmost! n p) + (define left (pair-left p)) + (if (number? left) + (set-pair-left! p (+ left n)) + (add-leftmost! n left))) + +;; number? pair? -> void? +;; Effect: Adds given number to deepest right node +(define (add-rightmost! n p) + (define right (pair-right p)) + (if (number? right) + (set-pair-right! p (+ right n)) + (add-rightmost! n right))) + +;; number? pair? -> void? +;; Effect: Adds given number to deepest left node in right node +(define (right-add-leftmost! n p) + (define right (pair-right p)) + (if (number? right) + (set-pair-right! p (+ right n)) + (add-leftmost! n right))) + +;; number? pair? -> void? +;; Effect: Adds given number to deepest right node in left node +(define (left-add-rightmost! n p) + (define left (pair-left p)) + (if (number? left) + (set-pair-left! p (+ left n)) + (add-rightmost! n left))) + +;; number? pair? -> void? +;; Effect: Adds given number to deepest left node of closest right sibling, +;; or does nothing if there is no right sibling +(define (up-add-leftmost! n p) + (match (pair-type p) + ['root (void)] + ['left (right-add-leftmost! n (pair-parent p))] + ['right (up-add-leftmost! n (pair-parent p))])) + +;; number? pair? -> void? +;; Effect: Adds given number to deepest right node of closest left sibling, +;; or does nothing if there is no left sibling +(define (up-add-rightmost! n p) + (match (pair-type p) + ['root (void)] + ['right (left-add-rightmost! n (pair-parent p))] + ['left (up-add-rightmost! n (pair-parent p))])) + +;; number? pair? -> (or/c 'exploded 'continue) +;; Explodes pairs at depth 4 or greater +(define (explode depth p) + (match p + [(pair 'left parent (? number? left) (? number? right)) + #:when (>= depth 4) + (right-add-leftmost! right parent) + (up-add-rightmost! left parent) + (set-pair-left! parent 0) + 'exploded] + [(pair 'right parent (? number? left) (? number? right)) + #:when (>= depth 4) + (left-add-rightmost! left parent) + (up-add-leftmost! right parent) + (set-pair-right! parent 0) + 'exploded] + [(pair type parent (? number? left) (? number? right)) + 'continue] + [(pair type parent (? number? left) (? pair? right)) + (explode (add1 depth) right)] + [(pair type parent (? pair? left) (? number? right?)) + (explode (add1 depth) left)] + [(pair type parent (? pair? left) (? pair? right)) + (define results + (list (explode (add1 depth) left) + (explode (add1 depth) right))) + (if (member 'exploded results) 'exploded 'continue)])) + +;; SPLIT ;; + +;; number? pair? -> void? +;; Effect: Sets left node to new pair consisting of halved number +;; rounded down and up +(define (split-left! left p) + (define halved (/ left 2)) + (set-pair-left! p (pair 'left p (floor halved) (ceiling halved)))) + +;; number? pair? -> void? +;; Effect: Sets right node to new pair consisting of halved number +;; rounded down and up +(define (split-right! right p) + (define halved (/ right 2)) + (set-pair-right! p (pair 'right p (floor halved) (ceiling halved)))) + +;; pair? -> (or/c 'split 'continue) +;; Splits leftmost number greater than 10 into a pair of halved numbers +(define (split p) + (match p + [(pair type parent (? number? left) (? number? right)) + (if (>= left 10) + (begin (split-left! left p) 'split) + (if (>= right 10) + (begin (split-right! right p) 'split) + 'continue))] + [(pair type parent (? number? left) (? pair? right)) + (if (>= left 10) + (begin (split-left! left p) 'split) + (split right))] + [(pair type parent (? pair? left) (? number? right)) + (match (split left) + ['split 'split] + ['continue + (if (>= right 10) + (begin (split-right! right p) 'split) + 'continue)])] + [(pair type parent (? pair? left) (? pair? right)) + (match (split left) + ['split 'split] + ['continue (split right)])])) + +;; REDUCE ;; + +;; pair? -> void? +;; Effect: Explodes then splits pair until a fixed point is reached +(define (reduce p) + (let loop ([status 'exploded]) + (if (symbol=? status 'continue) + (unless (symbol=? (split p) 'continue) + (loop (explode 0 p))) + (loop (explode 0 p))))) + +;; MAGNITUDE ;; + +;; (or/c number? pair?) -> number? +(define (magnitude p) + (match p + [(? number? n) n] + [(pair _ _ left right) + (+ (* 3 (magnitude left)) + (* 2 (magnitude right)))])) + +;; SOLUTION ;; + +(define part1 + (for/fold ([left (raw->pair (first input))] + #:result (magnitude left)) + ([right (rest input)]) + (define p (combine left (raw->pair right))) + (reduce p) + p)) + +(define part2 + (for*/fold ([sum 0]) + ([left input] + [right input]) + (define p (combine (raw->pair left) (raw->pair right))) + (reduce p) + (max sum (magnitude p)))) + +(show-solution part1 part2) \ No newline at end of file