package main import ( "fmt" "strconv" "strings" "git.mstar.dev/mstar/aoc24/util" "git.mstar.dev/mstar/goutils/other" "git.mstar.dev/mstar/goutils/sliceutils" ) type TreeNode struct { Left, Right *TreeNode Value uint64 IsLeaf bool } func lineToNumbers(line string) []uint64 { return sliceutils.Map( strings.Split(line, " "), func(t string) uint64 { return other.Must(strconv.ParseUint(t, 10, 64)) }, ) } func numbersIntoTree(numbers []uint64) *TreeNode { switch len(numbers) { case 1: return &TreeNode{ Left: &TreeNode{ Left: nil, Right: nil, Value: numbers[0], IsLeaf: true, }, Right: nil, Value: 0, IsLeaf: false, } case 2: return &TreeNode{ Left: &TreeNode{ Left: nil, Right: nil, Value: numbers[0], IsLeaf: true, }, Right: &TreeNode{ Left: nil, Right: nil, Value: numbers[1], IsLeaf: true, }, Value: 0, IsLeaf: false, } default: l, r := splitListIntoTwo(numbers) return &TreeNode{ Left: numbersIntoTree(l), Right: numbersIntoTree(r), Value: 0, IsLeaf: false, } } } func splitListIntoTwo[S ~[]T, T any](s S) (S, S) { middle := len(s) / 2 left := S{} right := S{} for i, v := range s { if i < middle { left = append(left, v) } else { right = append(right, v) } } return left, right } func (n *TreeNode) Advance() { if n.IsLeaf { // 1. 0 -> 1 // 2. len("num") % 2 == 0 -> num[len("num")/2:], num[:len("num")/2] // 2424 -> 24, 24; 435892 -> 435, 892 // 3. x -> x * 2024 switch { case n.Value == 0: n.Value = 1 case len(strconv.FormatUint(n.Value, 10))%2 == 0: str := strconv.FormatUint(n.Value, 10) left := string([]rune(str)[:len(str)/2]) right := string([]rune(str)[len(str)/2:]) n.IsLeaf = false n.Left = &TreeNode{ Left: nil, Right: nil, Value: other.Must(strconv.ParseUint(left, 10, 64)), IsLeaf: true, } n.Right = &TreeNode{ Left: nil, Right: nil, Value: other.Must(strconv.ParseUint(right, 10, 64)), IsLeaf: true, } default: n.Value *= 2024 } } else { if n.Left != nil { n.Left.Advance() } if n.Right != nil { n.Right.Advance() } } } func (n *TreeNode) String() string { if n.IsLeaf { return fmt.Sprint(n.Value) } else { if n.Right != nil { return fmt.Sprintf("%s %s", n.Left, n.Right) } else { return fmt.Sprint(n.Left) } } } func (n *TreeNode) Count() uint64 { if n.IsLeaf { return 1 } else { if n.Right != nil { return n.Left.Count() + n.Right.Count() } else { return n.Left.Count() } } } func main() { nums := lineToNumbers(strings.TrimSpace(string(util.LoadFileFromArgs()))) tree := numbersIntoTree(nums) // fmt.Printf("%#v\n", tree.Right) for range 25 { tree.Advance() } fmt.Printf("Task 1: %d\n", tree.Count()) var accCheck uint64 = 0 for _, num := range nums { accCheck += Advance(num, 0, 25) } fmt.Printf("Check 1: %d\n", accCheck) // for range 50 { // tree.Advance() // } // fmt.Printf("Task 2: %d\n", tree.Count()) // resetCache() var acc uint64 = 0 for _, num := range nums { acc += Advance(num, 0, 75) } // addChan := make(chan uint64, 1) // wg := sync.WaitGroup{} // go func() { // for v := range addChan { // acc += v // } // }() // for _, num := range nums { // wg.Add(1) // go func() { // addChan <- Advance(num, 0, 75) // wg.Done() // }() // } // wg.Wait() // close(addChan) fmt.Printf("Task 2: %d\n", acc) }