From 070c03e6631e961dbcd9ce521df4c65ab94d467f Mon Sep 17 00:00:00 2001 From: Abel Tay <15604207+abeltay@users.noreply.github.com> Date: Wed, 27 Dec 2023 22:51:05 +0800 Subject: [PATCH] Day 25: Snowverload --- 25/main.go | 163 +++++++++++++++++++++++++++++++++++++++++++ 25/main_test.go | 19 +++++ 25/testdata/test.txt | 13 ++++ 3 files changed, 195 insertions(+) create mode 100644 25/main.go create mode 100644 25/main_test.go create mode 100644 25/testdata/test.txt diff --git a/25/main.go b/25/main.go new file mode 100644 index 0000000..d89f603 --- /dev/null +++ b/25/main.go @@ -0,0 +1,163 @@ +package main + +import ( + "math/rand" + "sort" + "strings" + + "github.com/abeltay/advent-of-code-2023/utilities" +) + +func parseInput(filename string) [][]bool { + in := utilities.ParseFile(filename) + + all := make(map[string]bool) + for _, row := range in { + s := strings.Split(row, ": ") + all[s[0]] = true + for _, v := range strings.Split(s[1], " ") { + all[v] = true + } + } + names := make([]string, 0, len(all)) + for k := range all { + names = append(names, k) + } + sort.Strings(names) + connections := make([][]bool, len(names)) + for i := range names { + connections[i] = make([]bool, len(names)) + } + for _, row := range in { + s := strings.Split(row, ": ") + from := sort.SearchStrings(names, s[0]) + for _, v := range strings.Split(s[1], " ") { + to := sort.SearchStrings(names, v) + connections[from][to] = true + connections[to][from] = true + } + } + return connections +} + +type node struct { + num int + parent *node +} + +func bfs(connections [][]bool, breaks []connect, from, to int) *node { + visited := make([]bool, len(connections)) + visited[from] = true + queue := []node{{num: from}} + for len(queue) > 0 { + last := queue[0] + queue = queue[1:] + if last.num == to { + return &last + } + for i := range connections[last.num] { + if !connections[last.num][i] || visited[i] { + continue + } + var broken bool + for _, v := range breaks { + if v.from == last.num && v.to == i { + broken = true + } + } + if broken { + continue + } + visited[i] = true + queue = append(queue, node{num: i, parent: &last}) + } + } + return nil +} + +type connect struct { + from int + to int +} + +func connectedAfter3Breaks(connections [][]bool, from, to int) []connect { + var breaks []connect + for i := 0; i < 3; i++ { + path := bfs(connections, breaks, from, to) + from := path.num + next := path.parent + for next != nil { + breaks = append(breaks, connect{from, next.num}) + breaks = append(breaks, connect{next.num, from}) + from = next.num + next = next.parent + } + } + path := bfs(connections, breaks, from, to) + if path != nil { + return nil + } + return breaks +} + +func findSize(connections [][]bool, breaks []connect, from int) int { + visited := make([]bool, len(connections)) + visited[from] = true + queue := []node{{num: from}} + for len(queue) > 0 { + last := queue[0] + queue = queue[1:] + for i := range connections[last.num] { + if !connections[last.num][i] || visited[i] { + continue + } + var broken bool + for _, v := range breaks { + if v.from == last.num && v.to == i { + broken = true + break + } + } + if broken { + continue + } + visited[i] = true + queue = append(queue, node{num: i, parent: &last}) + } + } + var count int + for _, v := range visited { + if v { + count++ + } + } + return count +} + +func part1(filename string) int { + connected := parseInput(filename) + sameGroup := []int{0} + source := 0 + r := rand.New(rand.NewSource(99)) + var breaks []connect + for { + n := int(r.Int31n(int32(len(connected)))) + var exists bool + for _, v := range sameGroup { + if v == n { + exists = true + break + } + } + if exists { + continue + } + breaks = connectedAfter3Breaks(connected, source, n) + if breaks != nil { + break + } + sameGroup = append(sameGroup, n) + } + size := findSize(connected, breaks, 0) + return size * (len(connected) - size) +} diff --git a/25/main_test.go b/25/main_test.go new file mode 100644 index 0000000..45d1995 --- /dev/null +++ b/25/main_test.go @@ -0,0 +1,19 @@ +package main + +import ( + "fmt" + "testing" +) + +func TestParts(t *testing.T) { + testFile := "testdata/test.txt" + got := part1(testFile) + want := 54 + if got != want { + t.Fatalf("got %v want %v", got, want) + } + + fmt.Println("Running input.txt") + actualFile := "testdata/input.txt" + fmt.Println("Answer for part 1:", part1(actualFile)) +} diff --git a/25/testdata/test.txt b/25/testdata/test.txt new file mode 100644 index 0000000..bbfda0b --- /dev/null +++ b/25/testdata/test.txt @@ -0,0 +1,13 @@ +jqt: rhn xhk nvd +rsh: frs pzl lsr +xhk: hfx +cmg: qnr nvd lhk bvb +rhn: xhk bvb hfx +bvb: xhk hfx +pzl: lsr hfx nvd +qnr: nvd +ntq: jqt hfx bvb xhk +nvd: lhk +lsr: lhk +rzs: qnr cmg lsr rsh +frs: qnr lhk lsr