day 18 bad attempt

This commit is contained in:
RussellChamp committed 2021-12-29 21:54:04 -05:00
1 parent 586e137f05
commit 0b5bf004f7
4 files changed
+386 -1

No files matched your search

+283
View File
@@ -0,0 +1,283 @@
/* Day 18: Snailfish */
package main
import (
"AoC2021/utils/args"
"AoC2021/utils/log"
"AoC2021/utils/timer"
"bufio"
"fmt"
"os"
"strconv"
)
func check(e error) {
if e != nil {
log.Println(log.DEBUG, "Oh snap!")
panic(e)
}
}
func main() {
argMap := args.Parse(os.Args)
log.SetLogLevelFromArgs(argMap)
selectedPart, partSpecified := argMap["part"]
log.Println(log.NORMAL, "--- Day 18: Snailfish ---")
timer.Start()
if !partSpecified || selectedPart == "" || selectedPart == "1" {
part1()
timer.Tick()
log.Println(log.NORMAL)
}
if !partSpecified || selectedPart == "" || selectedPart == "2" {
part2()
timer.Tick()
log.Println(log.NORMAL)
}
}
func part1() {
log.Println(log.NORMAL, "* Part 1 *")
log.Println(log.NORMAL, " Goal: Add up all of the snailfish numbers from the homework assignment in the order they appear.")
log.Println(log.NORMAL, " Answer: What is the magnitude of the final sum?")
input, err := os.Open("./input.txt")
check(err)
defer input.Close()
scanner := bufio.NewScanner(input)
lines := 0
var s Snum
for scanner.Scan() {
line := scanner.Text()
if lines == 0 {
s = ParseSnumStr(line)
} else {
s = AddSnum(s, ParseSnumStr(line))
}
// fmt.Printf("SNum #%d: %s\n", lines+1, s.ToString())
lines++
if lines > 1 {
break
}
}
log.Printf(log.NORMAL, "Read %d lines from input\n", lines)
log.Printf(log.NORMAL, "The solution is: %s\n", s.ToString())
log.Printf(log.NORMAL, " with a magnitude of %d\n", s.CalcMagnitude())
}
func part2() {
log.Println(log.NORMAL, "* Part 2 *")
log.Println(log.NORMAL, " Goal: ")
log.Println(log.NORMAL, " Answer: ")
}
type Direction int
const (
LEFT Direction = 0
RIGHT Direction = 1
UP Direction = 2
)
// Snailfish number
// consists of a pair of numbers
// the "left" and "right" side can consist of EITHER a normal value or another pair
type Snum struct {
lVal int
rVal int
lPtr *Snum
rPtr *Snum
parentPtr *Snum
dir Direction
}
func ParseSnumStr(line string) Snum {
var s Snum
var sPtr = &s
log.Printf(log.DIAGNOSTIC, "Starting to parse snum line \"%s\"\n", line)
// start on idx 1 and skip the initial open bracket
for idx := 1; idx < len(line); idx++ {
switch line[idx] {
case '[':
if sPtr.dir == LEFT {
// create a new snum on the left side
sPtr.lPtr = &Snum{parentPtr: sPtr}
sPtr.dir = RIGHT
sPtr = sPtr.lPtr
} else {
sPtr.rPtr = &Snum{parentPtr: sPtr}
sPtr = sPtr.rPtr
}
case ']':
// go up a level
sPtr.dir = LEFT
sPtr = sPtr.parentPtr
case ',':
continue
default:
// if it's not a bracket or a comma then it must be a number
endIdx := idx + 1
for ; line[endIdx] >= '0' && line[endIdx] <= '9'; endIdx++ {
}
strVal := line[idx:endIdx]
iVal, err := strconv.Atoi(strVal)
check(err)
if sPtr.dir == LEFT {
sPtr.lVal = iVal
sPtr.dir = RIGHT
} else {
sPtr.rVal = iVal
}
idx = endIdx - 1
}
}
return s
}
func (s Snum) ToString() string {
str := "["
if s.lPtr != nil {
str += s.lPtr.ToString()
} else {
str += fmt.Sprintf("%d", s.lVal)
}
str += ","
if s.rPtr != nil {
str += s.rPtr.ToString()
} else {
str += fmt.Sprintf("%d", s.rVal)
}
str += "]"
return str
}
func AddSnum(s1, s2 Snum) Snum {
log.Printf(log.DEBUG, " %s\n+ %s\n", s1.ToString(), s2.ToString())
s := Snum{lPtr: &s1, rPtr: &s2}
s = s.Simplify()
log.Printf(log.DEBUG, "= %s\n", s.ToString())
return s
}
func (s1 Snum) Add(s2 Snum) Snum {
log.Printf(log.DEBUG, " %s\n+ %s\n", s1.ToString(), s2.ToString())
s := Snum{lPtr: &s1, rPtr: &s2}
s = s.Simplify()
log.Printf(log.DEBUG, "= %s\n", s.ToString())
return s
}
func (s Snum) Simplify() Snum {
madeAChange := true
for depth := 0; madeAChange; {
madeAChange = false
for sPtr := &s; sPtr != nil; {
switch {
case sPtr.ShouldExplode(depth):
ExplodeValue(sPtr)
madeAChange = true
sPtr = nil
// case sPtr.shouldSplit()
// travel the left side
case sPtr.dir == LEFT:
sPtr.dir = RIGHT
if sPtr.lPtr != nil {
sPtr = sPtr.lPtr
depth++
}
// travel the right side
case sPtr.dir == RIGHT:
sPtr.dir = UP
if sPtr.rPtr != nil {
sPtr = sPtr.rPtr
depth++
}
case sPtr.dir == UP:
sPtr = sPtr.parentPtr
depth--
}
}
}
// check to explode
// check to split
return s
}
func (s Snum) IsNormal() bool {
return s.lPtr == nil && s.rPtr == nil
}
func (s Snum) ShouldExplode(depth int) bool {
return s.IsNormal() && depth > 3
}
func ExplodeValue(at *Snum) {
log.Printf(log.DIAGNOSTIC, "Exploding the snum at %s\n", at.ToString())
if !at.IsNormal() {
panic("tried to explode a non-normal snum")
}
lVal, rVal := at.lVal, at.rVal
var sPtr *Snum
// explode left
log.Printf(log.NEVER, "Starting at %s\n", at.parentPtr.ToString())
for sPtr = at.parentPtr; sPtr.parentPtr != nil && sPtr.lPtr != nil; sPtr = sPtr.parentPtr {
log.Printf(log.NEVER, " traveled left to %s\n", sPtr.ToString())
}
if sPtr != nil {
log.Printf(log.NEVER, " added left %d to %d\n", lVal, sPtr.lVal)
sPtr.lVal += lVal
}
// explode right
for sPtr = at.parentPtr; sPtr.parentPtr != nil && sPtr.rPtr != nil; {
log.Printf(log.NEVER, " traveled right to %s\n", sPtr.ToString())
sPtr = sPtr.parentPtr
}
if sPtr != nil {
log.Printf(log.NEVER, " added right %d to %d\n", rVal, sPtr.rVal)
sPtr.rVal += rVal
}
// delete yourself
pPtr := at.parentPtr
if pPtr.lPtr == at {
pPtr.lPtr = nil
} else if pPtr.rPtr == at {
pPtr.rPtr = nil
}
}
func (s Snum) ShouldSplit() bool {
return s.lVal > 9 || s.rVal > 9
}
func (s Snum) CalcMagnitude() int {
lVal, rVal := s.lVal, s.rVal
if s.lPtr != nil {
lVal = s.lPtr.CalcMagnitude()
}
if s.rPtr != nil {
rVal = s.rPtr.CalcMagnitude()
}
return 3*lVal + 2*rVal
}