This commit is contained in:
Jonathan Chan 2021-12-18 02:25:23 -08:00
parent 7406e631df
commit e831febf86
2 changed files with 309 additions and 0 deletions

100
input/18.txt Normal file
View File

@ -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]

209
src/18.rkt Normal file
View File

@ -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)