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) }