diff --git a/2021/day18/main.go b/2021/day18/main.go index 098fe46..4b394d8 100644 --- a/2021/day18/main.go +++ b/2021/day18/main.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "math" h "git.bullercodeworks.com/brian/adventofcode/helpers" ) @@ -11,25 +12,34 @@ func main() { var build *SNum for i := range inp { - wrk, _ := ParseSNum(inp[i]) + wrk := ParseSNum(inp[i]) if build == nil { build = wrk } else { build = build.add(wrk) } } - fmt.Println(build) - v := build.needsExplode(0) - fmt.Println("Needs Explode:", v) - v.explode() - fmt.Println(build) + fmt.Println() + fmt.Println("# Part 1") + fmt.Println("Magnitude:", build.magnitude()) + fmt.Println() + fmt.Println("# Part 2") + highest := h.MIN_INT + for i := 0; i < len(inp)-1; i++ { + for j := i + 1; j < len(inp); j++ { + w1 := ParseSNum(inp[i]).add(ParseSNum(inp[j])) + w2 := ParseSNum(inp[j]).add(ParseSNum(inp[i])) - /* - full := inp[0] - for i := 1; i < len(inp); i++ { - full = fmt.Sprintf("[%s,%s]", full, inp[i]) + m1, m2 := w1.magnitude(), w2.magnitude() + if m1 >= m2 && m1 > highest { + highest = m1 + } else if m2 > highest { + highest = m2 + } } - */ + } + fmt.Println("Highest magnitude from 2:", highest) + //3225 is too low } type SNum struct { @@ -38,16 +48,21 @@ type SNum struct { value int } +func ParseSNum(inp string) *SNum { + s, _ := rParseSNum(inp) + return s +} + // ParseSNum returns an SNum and what's left of inp // after it was produced -func ParseSNum(inp string) (*SNum, string) { +func rParseSNum(inp string) (*SNum, string) { // inp should always start with either a number or a '[' var rest string s := SNum{} if inp[0] == '[' { s.regular = false - s.left, rest = ParseSNum(inp[1:]) - s.right, rest = ParseSNum(rest[1:]) + s.left, rest = rParseSNum(inp[1:]) + s.right, rest = rParseSNum(rest[1:]) s.left.parent = &s s.right.parent = &s return &s, rest[1:] @@ -66,13 +81,21 @@ func ParseSNum(inp string) (*SNum, string) { return &s, rest } +// When exploding or splitting, we need to find the leftmost pair that matches the condition func (s *SNum) needsExplode(depth int) *SNum { - if depth == 4 && !s.regular { - return s - } if s.regular { return nil } + if depth >= 4 { + if !s.left.regular { + return s.left.needsExplode(depth + 1) + } else if !s.right.regular { + return s.right.needsExplode(depth + 1) + } else { + return s + } + } + if tst := s.left.needsExplode(depth + 1); tst != nil { return tst } else if tst := s.right.needsExplode(depth + 1); tst != nil { @@ -85,34 +108,69 @@ func (s *SNum) explode() { if s.parent == nil { return } - s.parent.addToRegularRightOf(s.right.value, s) s.parent.addToRegularLeftOf(s.left.value, s) + s.parent.addToRegularRightOf(s.right.value, s) + // Replace s with a regular number that just equals 0 + s.regular, s.value = true, 0 + s.right, s.left = nil, nil +} + +func (s *SNum) needsSplit() *SNum { + if s == nil || (s.regular && s.value >= 10) { + return s + } + if tst := s.left.needsSplit(); tst != nil { + return tst + } else if tst := s.right.needsSplit(); tst != nil { + return tst + } + return nil +} + +func (s *SNum) split() { + if s.parent == nil { + return + } + l := int(math.Floor(float64(s.value) / 2)) + r := int(math.Ceil(float64(s.value) / 2)) + n := SNum{ + parent: s.parent, + left: &SNum{ + regular: true, + value: int(l), + }, + right: &SNum{ + regular: true, + value: int(r), + }, + } + n.left.parent = &n + n.right.parent = &n + if s.parent.left == s { + s.parent.left = &n + } else if s.parent.right == s { + s.parent.right = &n + } } func (s *SNum) addToRegularLeftOf(v int, c *SNum) { - if s.right.regular { - s.right.value += v - } else { - if s.right != nil && s.right == c { - r := s.left.findRightmostRegular() - if r != nil { - r.value += v - } - } else if s.left != nil && s.left == c { - s.parent.addToRegularLeftOf(v, s) - } + if s == nil || v == 0 { + return + } + if s.right != nil && s.right == c { + s.left.addToRightmostRegular(v) + } else if s.left != nil && s.left == c { + s.parent.addToRegularLeftOf(v, s) } } func (s *SNum) addToRegularRightOf(v int, c *SNum) { - if s.left.regular { - s.left.value += v - } else if s.left != nil && s.left == c { - l := s.right.findLeftmostRegular() - if l != nil { - l.value += v - } - } else if s.right != nil && s.right == c { + if s == nil || v == 0 { + return + } + if s.left == c { + s.right.addToLeftmostRegular(v) + } else if s.right == c { s.parent.addToRegularRightOf(v, s) } } @@ -121,24 +179,49 @@ func (s *SNum) contains(n *SNum) bool { return s == n || s.left.contains(n) || s.right.contains(n) } -func (s *SNum) findRightmostRegular() *SNum { +func (s *SNum) addToRightmostRegular(v int) { if s.regular { - return s + s.value += v + } else if s.right != nil { + s.right.addToRightmostRegular(v) } - return s.right.findRightmostRegular() } -func (s *SNum) findLeftmostRegular() *SNum { +func (s *SNum) addToLeftmostRegular(v int) { if s.regular { - return s + s.value += v + } else if s.left != nil { + s.left.addToLeftmostRegular(v) } - return s.left.findLeftmostRegular() } func (s *SNum) add(n *SNum) *SNum { - return &SNum{ + wrk := SNum{ left: s, right: n, } + s.parent = &wrk + n.parent = &wrk + + changed := true + for changed { + changed = false + if v := wrk.needsExplode(0); v != nil { + v.explode() + changed = true + } else if v := wrk.needsSplit(); v != nil { + v.split() + changed = true + } + } + + return &wrk +} + +func (s *SNum) magnitude() int { + if s.regular { + return s.value + } + return s.left.magnitude()*3 + s.right.magnitude()*2 } func (s SNum) String() string { diff --git a/2021/day18/testinput2 b/2021/day18/testinput2 new file mode 100644 index 0000000..61b0df6 --- /dev/null +++ b/2021/day18/testinput2 @@ -0,0 +1,2 @@ +[[[[4,3],4],4],[7,[[8,4],9]]] +[1,1] diff --git a/2021/day18/testinput3 b/2021/day18/testinput3 new file mode 100644 index 0000000..1368dc4 --- /dev/null +++ b/2021/day18/testinput3 @@ -0,0 +1,10 @@ +[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]] +[[[5,[2,8]],4],[5,[[9,9],0]]] +[6,[[[6,2],[5,6]],[[7,6],[4,7]]]] +[[[6,[0,7]],[0,9]],[4,[9,[9,0]]]] +[[[7,[6,4]],[3,[1,3]]],[[[5,5],1],9]] +[[6,[[7,3],[3,2]]],[[[3,8],[5,7]],4]] +[[[[5,4],[7,7]],8],[[8,3],8]] +[[9,3],[[9,9],[6,[4,9]]]] +[[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]] +[[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]