185 lines
3.4 KiB
Go
185 lines
3.4 KiB
Go
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)
|
|
}
|