package main import ( "fmt" "strconv" "strings" "sync" "git.mstar.dev/mstar/aoc24/util" "git.mstar.dev/mstar/goutils/other" "git.mstar.dev/mstar/goutils/sliceutils" ) type Group struct { Target uint64 Elements []uint64 } func parseLine(line string) (group Group) { parts := strings.Split(line, ": ") if len(parts) != 2 { panic("Invalid line parts count") } group.Target = other.Must(strconv.ParseUint(parts[0], 10, 64)) group.Elements = []uint64{} for _, elem := range strings.Split(parts[1], " ") { if len(elem) == 0 { continue } group.Elements = append(group.Elements, other.Must(strconv.ParseUint(elem, 10, 64))) } return } func checkGroup1(group *Group) uint64 { // fmt.Printf("Checking group %v\n", group) if len(group.Elements) == 2 { if group.Elements[0]*group.Elements[1] == group.Target || group.Elements[0]+group.Elements[1] == group.Target { // fmt.Printf("Group %v suceeded\n", group) return 1 } return 0 } elemsMult := []uint64{group.Elements[0] * group.Elements[1]} elemsMult = append(elemsMult, group.Elements[2:]...) elemsAdd := []uint64{group.Elements[0] + group.Elements[1]} elemsAdd = append(elemsAdd, group.Elements[2:]...) return checkGroup1(&Group{group.Target, elemsAdd}) + checkGroup1(&Group{group.Target, elemsMult}) } func concatNrs(a, b uint64) uint64 { return other.Must(strconv.ParseUint(fmt.Sprintf("%d%d", a, b), 10, 64)) } func checkGroup2(group *Group) uint64 { // fmt.Printf("Checking group %v\n", group) if len(group.Elements) == 2 { if group.Elements[0]*group.Elements[1] == group.Target || group.Elements[0]+group.Elements[1] == group.Target || concatNrs(group.Elements[0], group.Elements[1]) == group.Target { // fmt.Printf("Group %v suceeded\n", group) return 1 } return 0 } elemsMult := []uint64{group.Elements[0] * group.Elements[1]} elemsMult = append(elemsMult, group.Elements[2:]...) elemsAdd := []uint64{group.Elements[0] + group.Elements[1]} elemsAdd = append(elemsAdd, group.Elements[2:]...) elemsConc := []uint64{concatNrs(group.Elements[0], group.Elements[1])} elemsConc = append(elemsConc, group.Elements[2:]...) return checkGroup2(&Group{group.Target, elemsAdd}) + checkGroup2(&Group{group.Target, elemsMult}) + checkGroup2(&Group{group.Target, elemsConc}) } func main() { inputLines := util.FileContentToNonEmptyLines(util.LoadFileFromArgs()) groups := sliceutils.Map(inputLines, func(t string) Group { return parseLine(t) }) // fmt.Printf("All groups: %v\n", groups) var acc1 uint64 = 0 addChan1 := make(chan uint64, 1) go func() { for val := range addChan1 { // fmt.Printf("Adding %d to acc\n", val) acc1 += val } }() wg1 := sync.WaitGroup{} for _, group := range groups { if checkGroup1(&group) != 0 { acc1 += group.Target // fmt.Printf("Group with target %d suceeded\n", group.Target) } // wg1.Add(1) // go func(group Group) { // if checkGroup1(&group) != 0 { // fmt.Printf("Group with target %d suceeded\n", group.Target) // addChan1 <- group.Target // } // wg1.Done() // }(group) } wg1.Wait() close(addChan1) fmt.Printf("Task 1: %d\n", acc1) var acc2 uint64 = 0 for _, group := range groups { if checkGroup2(&group) != 0 { acc2 += group.Target } } fmt.Printf("Task 2: %d\n", acc2) }