Day 9: Part 1 and 2
Signed-off-by: James Griffin <james@unsupervised.ca>
This commit is contained in:
10
main.go
10
main.go
@@ -3,7 +3,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/thatguygriff/aoc2020/eight"
|
||||
"github.com/thatguygriff/aoc2020/nine"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -36,6 +36,10 @@ func main() {
|
||||
// fmt.Println(seven.PartTwo())
|
||||
|
||||
// Day 8
|
||||
fmt.Println(eight.PartOne())
|
||||
fmt.Println(eight.PartTwo())
|
||||
// fmt.Println(eight.PartOne())
|
||||
// fmt.Println(eight.PartTwo())
|
||||
|
||||
// Day 9
|
||||
fmt.Println(nine.PartOne())
|
||||
fmt.Println(nine.PartTwo())
|
||||
}
|
||||
|
135
nine/day_nine.go
Normal file
135
nine/day_nine.go
Normal file
@@ -0,0 +1,135 @@
|
||||
package nine
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type xmas struct {
|
||||
preamble int
|
||||
values []int
|
||||
}
|
||||
|
||||
func newXmas(filename string, preamble int) (*xmas, error) {
|
||||
x := &xmas{}
|
||||
if err := x.load(filename, preamble); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return x, nil
|
||||
}
|
||||
|
||||
func (x *xmas) load(filename string, preamble int) error {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
v, err := strconv.Atoi(scanner.Text())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
x.values = append(x.values, v)
|
||||
}
|
||||
|
||||
x.preamble = preamble
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *xmas) detectVulnerability() (int, error) {
|
||||
index := x.preamble
|
||||
|
||||
if index > len(x.values) {
|
||||
return 0, fmt.Errorf("Preamble is larger than the range of inputs")
|
||||
}
|
||||
|
||||
var match bool
|
||||
|
||||
for index < len(x.values) {
|
||||
searchable := x.values[index-x.preamble : index]
|
||||
match = false
|
||||
|
||||
for i := 0; i < len(searchable); i++ {
|
||||
for j := i + 1; j < len(searchable); j++ {
|
||||
if searchable[i] == searchable[j] {
|
||||
continue
|
||||
}
|
||||
|
||||
if searchable[i]+searchable[j] == x.values[index] {
|
||||
match = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !match {
|
||||
return x.values[index], nil
|
||||
}
|
||||
index++
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("Did not find a vulnerable value")
|
||||
}
|
||||
|
||||
func (x *xmas) computeWeakness() (int, error) {
|
||||
v, err := x.detectVulnerability()
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
for i := 0; i < len(x.values); i++ {
|
||||
sum := x.values[i]
|
||||
min := x.values[i]
|
||||
max := x.values[i]
|
||||
|
||||
if x.values[i] == v {
|
||||
return 0, fmt.Errorf("Did not find encryption weakness before %d", v)
|
||||
}
|
||||
|
||||
for j := i + 1; j < len(x.values); j++ {
|
||||
sum += x.values[j]
|
||||
if x.values[j] < min {
|
||||
min = x.values[j]
|
||||
}
|
||||
|
||||
if x.values[j] > max {
|
||||
max = x.values[j]
|
||||
}
|
||||
|
||||
// We found the contiguous range of values!
|
||||
if sum == v {
|
||||
return min + max, nil
|
||||
}
|
||||
|
||||
// This means that the contiguous run starting at i was a bust
|
||||
if sum > v {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// PartOne Find the first vulnerable number in the xmas chain
|
||||
func PartOne() string {
|
||||
x, _ := newXmas("nine/input.txt", 25)
|
||||
|
||||
v, _ := x.detectVulnerability()
|
||||
|
||||
return fmt.Sprintf("The first vulnerable value in the XMAS input is %d", v)
|
||||
}
|
||||
|
||||
// PartTwo Find the encryption weaknes in the xmas chain
|
||||
func PartTwo() string {
|
||||
x, _ := newXmas("nine/input.txt", 25)
|
||||
|
||||
w, _ := x.computeWeakness()
|
||||
|
||||
return fmt.Sprintf("The encryption weakness in the XMAS input is %d", w)
|
||||
}
|
45
nine/day_nine_test.go
Normal file
45
nine/day_nine_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package nine
|
||||
|
||||
import "testing"
|
||||
|
||||
func Test_program_load(t *testing.T) {
|
||||
x := xmas{}
|
||||
err := x.load("sample.txt", 5)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if len(x.values) != 20 {
|
||||
t.Logf("Expected 20 values, Got %d values", len(x.values))
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func Test_weakness_detection(t *testing.T) {
|
||||
x, err := newXmas("sample.txt", 5)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
v, err := x.detectVulnerability()
|
||||
if err != nil || v != 127 {
|
||||
t.Logf("Expected vulnerability of 127, Got vulnerability %d", v)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func Test_weakness_compute(t *testing.T) {
|
||||
x, err := newXmas("sample.txt", 5)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
e, err := x.computeWeakness()
|
||||
if err != nil || e != 62 {
|
||||
t.Logf("Expected weaknes 62, Got weakness %d", e)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
1000
nine/input.txt
Normal file
1000
nine/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
20
nine/sample.txt
Normal file
20
nine/sample.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
35
|
||||
20
|
||||
15
|
||||
25
|
||||
47
|
||||
40
|
||||
62
|
||||
55
|
||||
65
|
||||
95
|
||||
102
|
||||
117
|
||||
150
|
||||
182
|
||||
127
|
||||
219
|
||||
299
|
||||
277
|
||||
309
|
||||
576
|
Reference in New Issue
Block a user