diff --git a/2020/day13/main.go b/2020/day13/main.go index eac4896..c148a63 100644 --- a/2020/day13/main.go +++ b/2020/day13/main.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/alexchao26/advent-of-code-go/mathutil" "github.com/alexchao26/advent-of-code-go/util" ) @@ -16,36 +17,63 @@ func main() { if part == 1 { ans := part1(util.ReadFile("./input.txt")) - util.CopyToClipboard(fmt.Sprintf("%v", ans)) fmt.Println("Output:", ans) } else { ans := part2(util.ReadFile("./input.txt")) - util.CopyToClipboard(fmt.Sprintf("%v", ans)) fmt.Println("Output:", ans) } } func part1(input string) int { - parsed := parseInput(input) - _ = parsed + estimate, busses := parseInput(input) - return 0 -} - -func part2(input string) int { - parsed := parseInput(input) - _ = parsed - - return 0 -} - -func parseInput(input string) []int { - var ans []int - - lines := strings.Split(input, "\n") - for _, l := range lines { - ans = append(ans, mathutil.StrToInt(l)) + var busID, waited int + for timeValue := estimate; busID == 0; timeValue++ { + for _, inter := range busses { + if timeValue%inter[1] == 0 { + busID = inter[1] + waited = timeValue - estimate + break + } + } } - return ans + return busID * waited +} + +// i didn't come up with this myself... generally speaking i understand it... +func part2(input string) int { + _, busses := parseInput(input) + + var timeValue int + runningProduct := 1 + for _, bus := range busses { + index, busID := bus[0], bus[1] + // this for loop adjusts the time until the constaint for this bus is met + // i.e. ensure (time + index) is divisible by the busID to ensure the bus arrives + for (timeValue+index)%busID != 0 { + // running product is used to increment because it will not affect + // the modulo of any of the previously scheduled busses, we've found + // the frequency to match them. + // e.g. if busID: 5 & index: 2, min timeValue is 3 b/c (3+2)%5 == 0 + // if the running product were 5, adding 5 means (8+2)%5 == 0 + // and (3 + 5x + 2) % 5 == 0 for any x + timeValue += runningProduct + } + runningProduct *= busID + } + + return timeValue +} + +// busses are [2]int{index, busID}, not the best way to parse stuff but it works +func parseInput(input string) (estimate int, busses [][2]int) { + lines := strings.Split(input, "\n") + estimate = mathutil.StrToInt(lines[0]) + for index, busID := range strings.Split(lines[1], ",") { + if busID != "x" { + busses = append(busses, [2]int{index, mathutil.StrToInt(busID)}) + } + } + return estimate, busses } diff --git a/2020/day13/main_test.go b/2020/day13/main_test.go index ee82d4e..b270d7b 100644 --- a/2020/day13/main_test.go +++ b/2020/day13/main_test.go @@ -1,18 +1,24 @@ package main -import "testing" +import ( + "testing" -var tests1 = []struct { - name string - want int - input string - // add extra args if needed -}{ - // {"actual", ACTUAL_ANSWER, util.ReadFile("input.txt")}, -} + "github.com/alexchao26/advent-of-code-go/util" +) -func TestPart1(t *testing.T) { - for _, tt := range tests1 { +var example = `939 +7,13,x,x,59,x,31,19` + +func Test_part1(t *testing.T) { + tests := []struct { + name string + input string + want int + }{ + {"example", example, 295}, + {"actual", util.ReadFile("input.txt"), 2092}, + } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := part1(tt.input); got != tt.want { t.Errorf("part1() = %v, want %v", got, tt.want) @@ -21,17 +27,16 @@ func TestPart1(t *testing.T) { } } -var tests2 = []struct { - name string - want int - input string - // add extra args if needed -}{ - // {"actual", ACTUAL_ANSWER, util.ReadFile("input.txt")}, -} - -func TestPart2(t *testing.T) { - for _, tt := range tests2 { +func Test_part2(t *testing.T) { + tests := []struct { + name string + input string + want int + }{ + {"example", example, 1068781}, + {"actual", util.ReadFile("input.txt"), 702970661767766}, + } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := part2(tt.input); got != tt.want { t.Errorf("part2() = %v, want %v", got, tt.want)