package main import ( "fmt" "regexp" "strconv" "strings" "git.mstar.dev/mstar/aoc24/util" "git.mstar.dev/mstar/goutils/other" "git.mstar.dev/mstar/goutils/sliceutils" ) type Machine struct { A, B, Price util.Vec2 } var buttonARegex = regexp.MustCompile(`Button A: X\+(\d+), Y\+(\d+)`) var buttonBRegex = regexp.MustCompile(`Button B: X\+(\d+), Y\+(\d+)`) var prizeRegex = regexp.MustCompile(`Prize: X=(\d+), Y=(\d+)`) func dataToGroups(data []byte) [][]string { bigGroups := strings.Split(string(data), "\n\n") return sliceutils.Map( sliceutils.Filter(bigGroups, func(t string) bool { return len(t) != 0 }), func(t string) []string { return sliceutils.Filter( strings.Split(t, "\n"), func(t string) bool { return len(t) != 0 }, ) }, ) } func groupsToMachines(groups [][]string) []Machine { return sliceutils.Map(groups, func(t []string) Machine { return groupToMachine(t[0], t[1], t[2]) }) } func groupToMachine(a, b, p string) Machine { aMatches := buttonARegex.FindStringSubmatch(a) vecA := util.Vec2{ X: int64(other.Must(strconv.Atoi(aMatches[1]))), Y: int64(other.Must(strconv.Atoi(aMatches[2]))), } bMatches := buttonBRegex.FindStringSubmatch(b) vecb := util.Vec2{ X: int64(other.Must(strconv.Atoi(bMatches[1]))), Y: int64(other.Must(strconv.Atoi(bMatches[2]))), } pMatches := prizeRegex.FindStringSubmatch(p) vecp := util.Vec2{ X: int64(other.Must(strconv.Atoi(pMatches[1]))), Y: int64(other.Must(strconv.Atoi(pMatches[2]))), } return Machine{vecA, vecb, vecp} } func totalCost(a, b uint64) uint64 { return a*3 + b } func (m *Machine) CalcLowest() (aCount, bCount int, found bool) { smallestTotal := totalCost(1000, 1000) smallestA := 1000 smallestB := 1000 for a := 100; a >= 1; a-- { for b := 100; b >= 1; b-- { if m.A.Mult(int64(a)).Add(m.B.Mult(int64(b))).Eq(m.Price) { if smallestTotal > uint64(a)*3+uint64(b) { smallestA = a smallestB = b smallestTotal = totalCost(uint64(a), uint64(b)) } } } } return smallestA, smallestB, smallestTotal < totalCost(1000, 1000) } func (m *Machine) CalcLowest2() (int64, bool) { truePrice := m.Price.Add(util.Vec2{X: 10000000000000, Y: 10000000000000}) // Determinant of the two buttons determinant := m.A.X*m.B.Y - m.A.Y*m.B.X if determinant == 0 { return 0, false } // Determinant of button B and true price numA := truePrice.X*m.B.Y - truePrice.Y*m.B.X // Determinant of button A and true price numB := truePrice.Y*m.A.X - truePrice.X*m.A.Y if numA%determinant != 0 || numB%determinant != 0 { return 0, false } a := numA / determinant b := numB / determinant if a >= 0 && b >= 0 { return a*3 + b, true } else { return 0, false } } func main() { groups := dataToGroups(util.LoadFileFromArgs()) machines := groupsToMachines(groups) var acc uint64 = 0 var maxAcc uint64 = 0 // fmt.Println(machines[0].CalcLowest()) for _, machine := range machines { if a, b, ok := machine.CalcLowest(); ok { // fmt.Printf("Machine %d is ok\n", i) acc += totalCost(uint64(a), uint64(b)) } // fmt.Println("lowest 1 done") if a, ok := machine.CalcLowest2(); ok { maxAcc += uint64(a) } // fmt.Println("lowest 2 done") } fmt.Printf("Task 1: %d\n", acc) fmt.Printf("Task 2: %d\n", maxAcc) }