Day 13 done
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
This commit is contained in:
parent
81f693cb52
commit
99fdb9371a
4 changed files with 1440 additions and 0 deletions
1280
day13/input
Normal file
1280
day13/input
Normal file
File diff suppressed because it is too large
Load diff
128
day13/main.go
Normal file
128
day13/main.go
Normal file
|
@ -0,0 +1,128 @@
|
|||
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)
|
||||
}
|
15
day13/sample
Normal file
15
day13/sample
Normal file
|
@ -0,0 +1,15 @@
|
|||
Button A: X+94, Y+34
|
||||
Button B: X+22, Y+67
|
||||
Prize: X=8400, Y=5400
|
||||
|
||||
Button A: X+26, Y+66
|
||||
Button B: X+67, Y+21
|
||||
Prize: X=12748, Y=12176
|
||||
|
||||
Button A: X+17, Y+86
|
||||
Button B: X+84, Y+37
|
||||
Prize: X=7870, Y=6450
|
||||
|
||||
Button A: X+69, Y+23
|
||||
Button B: X+27, Y+71
|
||||
Prize: X=18641, Y=10279
|
17
util/vec.go
Normal file
17
util/vec.go
Normal file
|
@ -0,0 +1,17 @@
|
|||
package util
|
||||
|
||||
type Vec2 struct {
|
||||
X, Y int64
|
||||
}
|
||||
|
||||
func (v Vec2) Mult(by int64) Vec2 {
|
||||
return Vec2{v.X * by, v.Y * by}
|
||||
}
|
||||
|
||||
func (v Vec2) Add(a Vec2) Vec2 {
|
||||
return Vec2{v.X + a.X, v.Y + a.Y}
|
||||
}
|
||||
|
||||
func (v Vec2) Eq(a Vec2) bool {
|
||||
return v.X == a.X && v.Y == a.Y
|
||||
}
|
Loading…
Reference in a new issue