Day 11 done
Stupid hash function
This commit is contained in:
parent
b8612bd234
commit
8aee17b4d2
7 changed files with 314 additions and 8 deletions
79
day11/fixedNoTree.go
Normal file
79
day11/fixedNoTree.go
Normal file
|
@ -0,0 +1,79 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"git.mstar.dev/mstar/goutils/other"
|
||||
// "github.com/patrickmn/go-cache"
|
||||
)
|
||||
|
||||
// var valCache = cache.New(time.Minute, time.Minute*2)
|
||||
var valCacheMap = map[uint64]uint64{}
|
||||
var mLock sync.RWMutex
|
||||
|
||||
func hash(val uint64, iter, maxIter int) uint64 {
|
||||
h := fnv.New64a()
|
||||
|
||||
_, err := h.Write([]byte(fmt.Sprintf("%d.%d.%d", val, iter, maxIter)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return h.Sum64()
|
||||
}
|
||||
|
||||
func fromCache(val uint64, iteration, maxIter int) (uint64, bool) {
|
||||
mLock.RLock()
|
||||
pv, ok := valCacheMap[hash(val, iteration, maxIter)]
|
||||
mLock.RUnlock()
|
||||
// v, ok := valCache.Get(strconv.FormatUint(hash(val, iteration, maxIter), 10))
|
||||
// if !ok {
|
||||
// return 0, false
|
||||
// }
|
||||
// pv, ok := v.(uint64)
|
||||
return pv, ok
|
||||
}
|
||||
|
||||
func intoCache(val uint64, iteration, maxIter int, result uint64) {
|
||||
mLock.Lock()
|
||||
valCacheMap[hash(val, iteration, maxIter)] = result
|
||||
mLock.Unlock()
|
||||
// valCache.Set(strconv.FormatUint(hash(val, iteration, maxIter), 10), result, -1)
|
||||
}
|
||||
|
||||
func Advance(val uint64, iteration int, maxIter int) (out uint64) {
|
||||
cacheVal, ok := fromCache(val, iteration, maxIter)
|
||||
if ok {
|
||||
return cacheVal
|
||||
}
|
||||
defer func() {
|
||||
if _, ok := fromCache(val, iteration, maxIter); !ok {
|
||||
intoCache(val, iteration, maxIter, out)
|
||||
}
|
||||
}()
|
||||
// fmt.Printf("Iteration %d with val %d\n", iteration, val)
|
||||
if iteration == maxIter {
|
||||
// fmt.Println("1")
|
||||
out = 1
|
||||
return
|
||||
}
|
||||
if val == 0 {
|
||||
// fmt.Println("0")
|
||||
out = Advance(1, iteration+1, maxIter)
|
||||
return
|
||||
}
|
||||
if len(strconv.FormatUint(val, 10))%2 == 0 {
|
||||
// fmt.Println("Split")
|
||||
str := strconv.FormatUint(val, 10)
|
||||
// fmt.Println("format")
|
||||
left := other.Must(strconv.ParseUint(string([]rune(str)[:len(str)/2]), 10, 64))
|
||||
right := other.Must(strconv.ParseUint(string([]rune(str)[len(str)/2:]), 10, 64))
|
||||
// fmt.Printf("l: %d, r: %d\n", left, right)
|
||||
out = Advance(left, iteration+1, maxIter) + Advance(right, iteration+1, maxIter)
|
||||
return
|
||||
}
|
||||
out = Advance(val*2024, iteration+1, maxIter)
|
||||
return out
|
||||
}
|
1
day11/input
Normal file
1
day11/input
Normal file
|
@ -0,0 +1 @@
|
|||
28 4 3179 96938 0 6617406 490 816207
|
185
day11/main.go
Normal file
185
day11/main.go
Normal file
|
@ -0,0 +1,185 @@
|
|||
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)
|
||||
}
|
48
day11/noTreeApproach.go.disabled
Normal file
48
day11/noTreeApproach.go.disabled
Normal file
|
@ -0,0 +1,48 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"git.mstar.dev/mstar/goutils/other"
|
||||
"github.com/Skarlso/cache"
|
||||
)
|
||||
|
||||
var stoneCache = cache.New[uint64]()
|
||||
|
||||
// Doesn't work, the cache thing can't handle recursion
|
||||
func AdvanceBroken(val uint64, iteration int, maxIter int) cache.Cacheable[uint64] {
|
||||
return func() uint64 {
|
||||
fmt.Printf("Iteration %d with val %d\n", iteration, val)
|
||||
if iteration == maxIter {
|
||||
fmt.Println("1")
|
||||
return 1
|
||||
}
|
||||
if val == 0 {
|
||||
fmt.Println("0")
|
||||
return stoneCache.WithCache(
|
||||
AdvanceBroken(1, iteration+1, maxIter),
|
||||
[]any{1, iteration + 1, maxIter},
|
||||
)
|
||||
}
|
||||
if len(strconv.FormatUint(val, 10))%2 == 0 {
|
||||
fmt.Println("Split")
|
||||
str := strconv.FormatUint(val, 10)
|
||||
fmt.Println("format")
|
||||
left := other.Must(strconv.ParseUint(string([]rune(str)[:len(str)/2]), 10, 64))
|
||||
right := other.Must(strconv.ParseUint(string([]rune(str)[len(str)/2:]), 10, 64))
|
||||
fmt.Printf("l: %d, r: %d\n", left, right)
|
||||
return stoneCache.WithCache(
|
||||
AdvanceBroken(left, iteration+1, maxIter),
|
||||
[]any{left, iteration + 1, maxIter},
|
||||
) + stoneCache.WithCache(
|
||||
AdvanceBroken(right, iteration+1, maxIter),
|
||||
[]any{right, iteration + 1, maxIter},
|
||||
)
|
||||
}
|
||||
return stoneCache.WithCache(
|
||||
AdvanceBroken(val*2024, iteration+1, maxIter),
|
||||
[]any{val * 2024, iteration + 1, maxIter},
|
||||
)
|
||||
}
|
||||
}
|
1
day11/sample
Normal file
1
day11/sample
Normal file
|
@ -0,0 +1 @@
|
|||
125 17
|
2
go.mod
2
go.mod
|
@ -3,5 +3,3 @@ module git.mstar.dev/mstar/aoc24
|
|||
go 1.23.3
|
||||
|
||||
require git.mstar.dev/mstar/goutils v1.5.4
|
||||
|
||||
require github.com/BooleanCat/go-functional/v2 v2.3.0 // indirect
|
||||
|
|
6
go.sum
6
go.sum
|
@ -1,8 +1,2 @@
|
|||
git.mstar.dev/mstar/goutils v1.5.3 h1:Wqa8H8EWnc9IJmzsi6qeVqwYHPvWiDhG/b9WtZr0Nos=
|
||||
git.mstar.dev/mstar/goutils v1.5.3/go.mod h1:juxY0eZEMnA95fedRp2LVXvUBgEjz66nE8SEdGKcxMA=
|
||||
git.mstar.dev/mstar/goutils v1.5.4 h1:l/4oQe/fBk9zyXplQkGXbmQndnm0aRdHuy4wgQfNrFo=
|
||||
git.mstar.dev/mstar/goutils v1.5.4/go.mod h1:juxY0eZEMnA95fedRp2LVXvUBgEjz66nE8SEdGKcxMA=
|
||||
github.com/BooleanCat/go-functional/v2 v2.3.0 h1:mwVrUa4MSKQNs/N4EPy0fadRLyzP+eoc0NbnzWHEzLM=
|
||||
github.com/BooleanCat/go-functional/v2 v2.3.0/go.mod h1:IpUUAXAc9CiWDb+YDXkJyyUhtOVqDtyICDRg/de1IaQ=
|
||||
gitlab.com/mstarongitlab/goutils v1.5.1 h1:UlQL90DctJ7QbfJ5NOPheMK3PdFt6sBIjXR3fJpd3Ms=
|
||||
gitlab.com/mstarongitlab/goutils v1.5.1/go.mod h1:f71xLeTv05GHiRHKkgDRXfxOPRkjXNteXqLZyg02xhs=
|
||||
|
|
Loading…
Reference in a new issue