Compare commits
2 Commits
a498cc2acf
...
19b8711a83
| Author | SHA1 | Date | |
|---|---|---|---|
| 19b8711a83 | |||
| e5a179ab5a |
122
day13/clawmachine.go
Normal file
122
day13/clawmachine.go
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"math"
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
// data types
|
||||||
|
|
||||||
|
type Vec struct {
|
||||||
|
x uint32
|
||||||
|
y uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vec) Sub(other Vec) Vec {
|
||||||
|
return Vec{x: v.x - other.x, y: v.y - other.y}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vec) Mul(skalar uint32) Vec {
|
||||||
|
return Vec{x: v.x * skalar, y: v.y *skalar}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vec) VecDiv(other Vec) (float64, error) {
|
||||||
|
/* Returns an error if v and other do not lie on a staight line.
|
||||||
|
* It holds: v.VecDiv(other).Abs() = v.Abs() / other.Abs()
|
||||||
|
*/
|
||||||
|
cx := float64(v.x) / float64(other.x)
|
||||||
|
cy := float64(v.y) / float64(other.y)
|
||||||
|
|
||||||
|
if abs(cx - cy) > 10e-5 { return 0, errors.New("vectors do not lie in a straight line") }
|
||||||
|
|
||||||
|
return cx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vec) Abs() float64 {
|
||||||
|
return math.Sqrt(float64(v.x * v.x + v.y * v.y))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type ClawMachine struct {
|
||||||
|
buttonA Vec
|
||||||
|
buttonB Vec
|
||||||
|
price Vec
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cm ClawMachine) FindPath(max_presses_per_button uint32) ([2]uint32, error) {
|
||||||
|
/* Find all combinations of cm.buttonA and cm.buttonB that result in cm.price .
|
||||||
|
* => x1 * cm.buttonA + x2 * cm.buttonB = cm.price
|
||||||
|
* where x1, x2 are of type uint and x1,x2 <= max_presses_per_button
|
||||||
|
*
|
||||||
|
* Returns a list of all the [x1, x2] where the equation is solvable with the
|
||||||
|
* restrictions above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for i := range max_presses_per_button {
|
||||||
|
x1, err := cm.price.Sub( cm.buttonB.Mul(i + 1) ).VecDiv( cm.buttonA )
|
||||||
|
if err != nil || uint32(x1 - 10e-5) > max_presses_per_button { continue }
|
||||||
|
|
||||||
|
x2, err := cm.price.Sub( cm.buttonA.Mul(uint32(x1)) ).VecDiv( cm.buttonB )
|
||||||
|
|
||||||
|
if err == nil && i + 1 == uint32(x2) {
|
||||||
|
return [2]uint32{uint32(x1), uint32(x2)}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [2]uint32{0,0}, errors.New("no path found")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// general util
|
||||||
|
func check(e error) {
|
||||||
|
if e != nil { panic(e) }
|
||||||
|
}
|
||||||
|
|
||||||
|
func abs(n float64) float64 {
|
||||||
|
if n < 0 { return -n }
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// main loop
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
// read in file
|
||||||
|
dat, err := os.ReadFile("data.txt")
|
||||||
|
check(err)
|
||||||
|
dat_str := strings.TrimSpace(string(dat))
|
||||||
|
|
||||||
|
cms := make([]ClawMachine, 0)
|
||||||
|
pattern := regexp.MustCompile(`\d+`)
|
||||||
|
numbers := [6]uint32{}
|
||||||
|
for _, machine_str := range strings.Split(dat_str, "\n\n") {
|
||||||
|
// collect numbers as ints
|
||||||
|
for i, match := range pattern.FindAllString(machine_str, -1) {
|
||||||
|
numInt, err := strconv.Atoi(match)
|
||||||
|
check(err)
|
||||||
|
numbers[i] = uint32(numInt)
|
||||||
|
}
|
||||||
|
// construct ClawMachines
|
||||||
|
cms = append(cms, ClawMachine{
|
||||||
|
Vec{numbers[0],numbers[1]},
|
||||||
|
Vec{numbers[2], numbers[3]},
|
||||||
|
Vec{numbers[4],numbers[5]},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate cost
|
||||||
|
cost := 0
|
||||||
|
for _, cm := range cms {
|
||||||
|
path, err := cm.FindPath(100)
|
||||||
|
if err == nil {
|
||||||
|
cost += int(path[0]) * 3 + int(path[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println(cost)
|
||||||
|
}
|
||||||
1279
day13/data.txt
Normal file
1279
day13/data.txt
Normal file
File diff suppressed because it is too large
Load Diff
142
day13/hugeclawmachine.go
Normal file
142
day13/hugeclawmachine.go
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"math"
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
// data types
|
||||||
|
|
||||||
|
type Vec struct {
|
||||||
|
x float64
|
||||||
|
y float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vec) Add(other Vec) Vec {
|
||||||
|
return Vec{x: v.x + other.x, y: v.y + other.y}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vec) Sub(other Vec) Vec {
|
||||||
|
return Vec{x: v.x - other.x, y: v.y - other.y}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vec) Mul(skalar float64) Vec {
|
||||||
|
return Vec{x: v.x * skalar, y: v.y *skalar}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vec) VecDiv(other Vec) (float64, error) {
|
||||||
|
/* Returns an error if v and other do not lie on a staight line.
|
||||||
|
* It holds: v.VecDiv(other).Abs() = v.Abs() / other.Abs()
|
||||||
|
*/
|
||||||
|
cx := float64(v.x) / float64(other.x)
|
||||||
|
cy := float64(v.y) / float64(other.y)
|
||||||
|
|
||||||
|
if abs(cx - cy) > 10e-5 { return 0, errors.New("vectors do not lie in a straight line") }
|
||||||
|
|
||||||
|
return cx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vec) Abs() float64 {
|
||||||
|
return math.Sqrt(float64(v.x * v.x + v.y * v.y))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vec) IsNatural() bool {
|
||||||
|
intX := int(v.x + 10e-5)
|
||||||
|
intY := int(v.y + 10e-5)
|
||||||
|
|
||||||
|
return abs(float64(intX) - v.x) < 10e-5 && abs(float64(intY) - v.y) < 10e-5
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Matrix struct {
|
||||||
|
c0 Vec // left column
|
||||||
|
c1 Vec // right column
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Matrix) LinearTransform(v Vec) Vec {
|
||||||
|
return m.c0.Mul(v.x).Add( m.c1.Mul(v.y) )
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Matrix) Inverse() (Matrix, error) {
|
||||||
|
det := m.c0.x * m.c1.y - m.c0.y * m.c1.x
|
||||||
|
if det == 0 {
|
||||||
|
return Matrix{}, errors.New("Matrix is not invertable")
|
||||||
|
}
|
||||||
|
|
||||||
|
invDet := 1 / det
|
||||||
|
invMatrix := Matrix{
|
||||||
|
Vec{ m.c1.y, -m.c0.y}.Mul(invDet),
|
||||||
|
Vec{-m.c1.x, m.c0.x}.Mul(invDet),
|
||||||
|
}
|
||||||
|
|
||||||
|
return invMatrix, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClawMachine struct {
|
||||||
|
buttonA Vec
|
||||||
|
buttonB Vec
|
||||||
|
price Vec
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cm ClawMachine) GetTransform() (Matrix, error) {
|
||||||
|
return Matrix{cm.buttonA, cm.buttonB}.Inverse()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// general util
|
||||||
|
func check(e error) {
|
||||||
|
if e != nil { panic(e) }
|
||||||
|
}
|
||||||
|
|
||||||
|
func abs(n float64) float64 {
|
||||||
|
if n < 0 { return -n }
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// main loop
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
// read in file
|
||||||
|
dat, err := os.ReadFile("data.txt")
|
||||||
|
check(err)
|
||||||
|
dat_str := strings.TrimSpace(string(dat))
|
||||||
|
|
||||||
|
cms := make([]ClawMachine, 0)
|
||||||
|
pattern := regexp.MustCompile(`\d+`)
|
||||||
|
numbers := [6]float64{}
|
||||||
|
for _, machine_str := range strings.Split(dat_str, "\n\n") {
|
||||||
|
// collect numbers as ints
|
||||||
|
for i, match := range pattern.FindAllString(machine_str, -1) {
|
||||||
|
numInt, err := strconv.Atoi(match)
|
||||||
|
check(err)
|
||||||
|
numbers[i] = float64(numInt)
|
||||||
|
}
|
||||||
|
// construct ClawMachines
|
||||||
|
cms = append(cms, ClawMachine{
|
||||||
|
Vec{numbers[0], numbers[1]},
|
||||||
|
Vec{numbers[2], numbers[3]},
|
||||||
|
Vec{numbers[4] + 10000000000000, numbers[5] + 10000000000000},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate cost
|
||||||
|
cost := 0
|
||||||
|
for _, cm := range cms {
|
||||||
|
inv, err := cm.GetTransform()
|
||||||
|
check(err)
|
||||||
|
price_trans := inv.LinearTransform(cm.price)
|
||||||
|
|
||||||
|
if price_trans.IsNatural() {
|
||||||
|
cost += int(price_trans.x + 10e-5) * 3 + int(price_trans.y + 10e-5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println(cost)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user