aoc24/day11/main.go

186 lines
3.4 KiB
Go
Raw Permalink Normal View History

2024-12-11 14:28:01 +00:00
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)
}