Add day 13 solution. This one is super ugly.
This commit is contained in:
parent
2804abb674
commit
3983164a45
122
2020/day13.go
Normal file
122
2020/day13.go
Normal file
|
@ -0,0 +1,122 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"math/big"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.annabunch.es/annabunches/adventofcode/2020/lib/fileutils"
|
||||
)
|
||||
|
||||
//
|
||||
// Begin code borrowed from https://golang.hotexamples.com/examples/math.big/Int/GCD/golang-int-gcd-method-examples.html
|
||||
//
|
||||
func crt(a, n []*big.Int) (*big.Int, error) {
|
||||
one := new(big.Int).SetInt64(1)
|
||||
p := new(big.Int).Set(n[0])
|
||||
for _, n1 := range n[1:] {
|
||||
p.Mul(p, n1)
|
||||
}
|
||||
var x, q, s, z big.Int
|
||||
for i, n1 := range n {
|
||||
q.Div(p, n1)
|
||||
z.GCD(nil, &s, n1, &q)
|
||||
if z.Cmp(one) != 0 {
|
||||
return nil, fmt.Errorf("%d not coprime", n1)
|
||||
}
|
||||
x.Add(&x, s.Mul(a[i], s.Mul(&s, &q)))
|
||||
}
|
||||
return x.Mod(&x, p), nil
|
||||
}
|
||||
|
||||
//
|
||||
// End borrowed code
|
||||
//
|
||||
|
||||
func parseInput(input []string) (int, []int) {
|
||||
earliest, err := strconv.Atoi(input[0])
|
||||
if err != nil {
|
||||
log.Panicf(err.Error())
|
||||
}
|
||||
|
||||
busList := make([]int, 0)
|
||||
for _, value := range strings.Split(input[1], ",") {
|
||||
if value == "x" {
|
||||
busList = append(busList, -1)
|
||||
continue
|
||||
}
|
||||
x, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
log.Panicf(err.Error())
|
||||
}
|
||||
busList = append(busList, x)
|
||||
}
|
||||
|
||||
return earliest, busList
|
||||
}
|
||||
|
||||
func findBus(busList []int, earliest int) (int, int) {
|
||||
bestBus := -1
|
||||
bestTime := -1
|
||||
|
||||
for _, bus := range busList {
|
||||
if bus == -1 {
|
||||
continue
|
||||
}
|
||||
time := int(math.Ceil(float64(earliest)/float64(bus))) * bus
|
||||
if bestBus == -1 || time < bestTime {
|
||||
bestBus = bus
|
||||
bestTime = time
|
||||
}
|
||||
}
|
||||
|
||||
return bestBus, bestTime
|
||||
}
|
||||
|
||||
// This uses the Chinese Remainder Theorem to calculate the answer.
|
||||
// I don't actually understand the underlying logic, I just found this
|
||||
// while looking around for modulus-related algorithms.
|
||||
func findTimestampWithCRT(busList []int) *big.Int {
|
||||
bigBusList := make([]*big.Int, 0)
|
||||
offsetList := make([]*big.Int, 0)
|
||||
|
||||
for i, bus := range busList {
|
||||
if bus == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
bigBus := big.NewInt(int64(bus))
|
||||
bigBusList = append(bigBusList, bigBus)
|
||||
|
||||
offset := big.NewInt(int64(i))
|
||||
offset.Sub(bigBus, offset)
|
||||
offsetList = append(offsetList, offset)
|
||||
}
|
||||
|
||||
fmt.Println(offsetList)
|
||||
fmt.Println(bigBusList)
|
||||
value, err := crt(offsetList, bigBusList)
|
||||
if err != nil {
|
||||
log.Panicf(err.Error())
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func main() {
|
||||
step := os.Args[1]
|
||||
values := fileutils.InputParserStrings(os.Args[2])
|
||||
|
||||
earliest, busList := parseInput(values)
|
||||
|
||||
switch step {
|
||||
case "1":
|
||||
busId, departureTime := findBus(busList, earliest)
|
||||
fmt.Println(busId * (departureTime - earliest))
|
||||
case "2":
|
||||
fmt.Println(findTimestampWithCRT(busList))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user