From 81adaec4b945aa0bf966ceb17a3bc262b34b3472 Mon Sep 17 00:00:00 2001 From: alexchao26 Date: Tue, 15 Dec 2020 23:58:43 -0500 Subject: [PATCH] 2017-day13: frequency calculation --- 2017/day13/main.go | 85 +++++++++++++++++++++++++++++++++++++++++ 2017/day13/main_test.go | 51 +++++++++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 2017/day13/main.go create mode 100644 2017/day13/main_test.go diff --git a/2017/day13/main.go b/2017/day13/main.go new file mode 100644 index 0000000..6ae9e8a --- /dev/null +++ b/2017/day13/main.go @@ -0,0 +1,85 @@ +package main + +import ( + "flag" + "fmt" + "math" + "strings" + + "github.com/alexchao26/advent-of-code-go/util" +) + +func main() { + var part int + flag.IntVar(&part, "part", 1, "part 1 or 2") + flag.Parse() + fmt.Println("Running part", part) + + var ans int + if part == 1 { + ans = part1(util.ReadFile("./input.txt")) + } else { + ans = part2(util.ReadFile("./input.txt")) + } + fmt.Println("Output:", ans) +} + +func part1(input string) int { + freqs := parseFrequencies(input) + + var severity int + for _, freq := range freqs { + // depthIndex is also equivalent to the number of picoseconds that have + // elapsed when we reach a particular depth of the firewall + depthIndex := freq[0] + + // frequency to zero index is how many picoseconds it takes the scanner + // to return to the zero index position + frequencyToZeroIndex := (freq[1] - 1) * 2 + + // if frequency is evenly divisible by the time elapsed, then we're + // "caught" by this scanner, add to severity + if depthIndex%frequencyToZeroIndex == 0 { + severity += depthIndex * freq[1] + } + } + + return severity +} + +func part2(input string) int { + freqs := parseFrequencies(input) + + // same logic to part 1, but add a delay to the time elapsed and return which + // delay leads to not getting caught by a scanner + for delay := 0; delay < math.MaxInt32; delay++ { + var gotCaught bool + for _, freq := range freqs { + depthIndex := freq[0] + frequencyToZeroIndex := (freq[1] - 1) * 2 + // add delay to the time depthIndex, as it takes longer to get there + if (depthIndex+delay)%frequencyToZeroIndex == 0 { + gotCaught = true + } + } + if !gotCaught { + return delay + } + } + + panic("loop ended, increase limit?") +} + +func parseFrequencies(input string) [][2]int { + lines := strings.Split(input, "\n") + var freqs [][2]int // depth, range + for _, l := range lines { + // depth is equivalent to the index in the firewall + // range can be used to calculate the frequency in which a scanner + // returns to index zero + var depth, rng int + fmt.Sscanf(l, "%d: %d", &depth, &rng) + freqs = append(freqs, [2]int{depth, rng}) + } + return freqs +} diff --git a/2017/day13/main_test.go b/2017/day13/main_test.go new file mode 100644 index 0000000..87886de --- /dev/null +++ b/2017/day13/main_test.go @@ -0,0 +1,51 @@ +package main + +import ( + "testing" + "time" + + "github.com/alexchao26/advent-of-code-go/util" +) + +var example = `0: 3 +1: 2 +4: 4 +6: 4` + +func Test_part1(t *testing.T) { + tests := []struct { + name string + input string + want int + }{ + {"example", example, 24}, + {"actual", util.ReadFile("input.txt"), 2508}, + } + 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) + } + }) + } +} + +func Test_part2(t *testing.T) { + tests := []struct { + name string + input string + want int + }{ + {"example", example, 10}, + {"actual", util.ReadFile("input.txt"), 3913186}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + startTime := time.Now() + if got := part2(tt.input); got != tt.want { + t.Errorf("part2() = %v, want %v", got, tt.want) + } + t.Logf("Runtime for %s: %v", tt.name, time.Since(startTime)) + }) + } +}