99fdb9371a
I think I'm slowly reaching my limit Solution for part two (which would also work for part 1) made me realise that I should probably (re-)read those math books and learn the basics again
128 lines
3.2 KiB
Go
128 lines
3.2 KiB
Go
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)
|
|
}
|