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