Started day 25 puzzle
parent
915c7fee37
commit
11d1b155d3
@ -0,0 +1,190 @@
|
||||
package day25
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"gitea.paas.celticinfo.fr/oabrivard/aoc2023/utils"
|
||||
)
|
||||
|
||||
type Graph map[string]map[string]bool
|
||||
type Edge struct {
|
||||
left string
|
||||
right string
|
||||
}
|
||||
|
||||
func buildGraph(lines []string) Graph {
|
||||
graph := map[string]map[string]bool{}
|
||||
|
||||
for _, line := range lines {
|
||||
parts := strings.Split(line, ":")
|
||||
|
||||
src := parts[0]
|
||||
if _, found := graph[src]; !found {
|
||||
graph[src] = map[string]bool{}
|
||||
}
|
||||
links := graph[src]
|
||||
|
||||
dests := strings.Fields(strings.TrimSpace(parts[1]))
|
||||
for _, dst := range dests {
|
||||
links[dst] = true
|
||||
|
||||
if _, found := graph[dst]; !found {
|
||||
graph[dst] = map[string]bool{}
|
||||
}
|
||||
reverseLink := graph[dst]
|
||||
reverseLink[src] = true
|
||||
}
|
||||
}
|
||||
|
||||
return graph
|
||||
}
|
||||
|
||||
func printGraph(graph Graph) {
|
||||
for k1, v1 := range graph {
|
||||
fmt.Print(k1, ": ")
|
||||
for k2 := range v1 {
|
||||
fmt.Print(k2, " ")
|
||||
}
|
||||
fmt.Println("")
|
||||
}
|
||||
}
|
||||
|
||||
func countComponents(graph Graph) int {
|
||||
visited := map[string]bool{}
|
||||
count := 0
|
||||
|
||||
for node := range graph {
|
||||
if !visited[node] {
|
||||
count++
|
||||
queue := utils.NewQueue[string]()
|
||||
queue.Enqueue(node)
|
||||
|
||||
for queue.HasElement() {
|
||||
curNode := queue.Dequeue()
|
||||
visited[curNode] = true
|
||||
|
||||
for linkedNode := range graph[curNode] {
|
||||
if !visited[linkedNode] {
|
||||
queue.Enqueue(linkedNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func buildVerticesLists(graph Graph) []map[string]bool {
|
||||
visited := map[string]bool{}
|
||||
result := []map[string]bool{}
|
||||
currSubgraph := 0
|
||||
|
||||
for node := range graph {
|
||||
if !visited[node] {
|
||||
result = append(result, map[string]bool{})
|
||||
result[currSubgraph][node] = true
|
||||
|
||||
queue := utils.NewQueue[string]()
|
||||
queue.Enqueue(node)
|
||||
|
||||
for queue.HasElement() {
|
||||
curNode := queue.Dequeue()
|
||||
visited[curNode] = true
|
||||
result[currSubgraph][curNode] = true
|
||||
|
||||
for linkedNode := range graph[curNode] {
|
||||
if !visited[linkedNode] {
|
||||
queue.Enqueue(linkedNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
currSubgraph++
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func buildEdgeList(graph Graph) []Edge {
|
||||
edges := map[Edge]bool{}
|
||||
|
||||
for node, connectedNodes := range graph {
|
||||
for connectedNode := range connectedNodes {
|
||||
_, found1 := edges[Edge{node, connectedNode}]
|
||||
_, found2 := edges[Edge{connectedNode, node}]
|
||||
|
||||
if !found1 && !found2 {
|
||||
edges[Edge{node, connectedNode}] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result := []Edge{}
|
||||
for e := range edges {
|
||||
result = append(result, e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func findEdgesToDelete(graph Graph, edges []Edge) (bool, *Edge, *Edge, *Edge) {
|
||||
for i := 0; i < len(edges); i++ {
|
||||
for j := i + 1; j < len(edges); j++ {
|
||||
for k := j + 1; k < len(edges); k++ {
|
||||
// Delete edges i, j and k from graph
|
||||
delete(graph[edges[i].left], edges[i].right)
|
||||
delete(graph[edges[i].right], edges[i].left)
|
||||
delete(graph[edges[j].left], edges[j].right)
|
||||
delete(graph[edges[j].right], edges[j].left)
|
||||
delete(graph[edges[k].left], edges[k].right)
|
||||
delete(graph[edges[k].right], edges[k].left)
|
||||
|
||||
// count components
|
||||
count := countComponents(graph)
|
||||
|
||||
// restore Graph
|
||||
graph[edges[i].left][edges[i].right] = true
|
||||
graph[edges[i].right][edges[i].left] = true
|
||||
graph[edges[j].left][edges[j].right] = true
|
||||
graph[edges[j].right][edges[j].left] = true
|
||||
graph[edges[k].left][edges[k].right] = true
|
||||
graph[edges[k].right][edges[k].left] = true
|
||||
|
||||
if count == 2 {
|
||||
return true, &edges[i], &edges[j], &edges[k]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil, nil, nil
|
||||
}
|
||||
|
||||
func Part1(lines []string) int {
|
||||
graph := buildGraph(lines)
|
||||
printGraph(graph)
|
||||
edges := buildEdgeList(graph)
|
||||
fmt.Println(edges)
|
||||
success, edge1, edge2, edge3 := findEdgesToDelete(graph, edges)
|
||||
|
||||
if !success {
|
||||
return 0
|
||||
}
|
||||
|
||||
fmt.Println(*edge1)
|
||||
fmt.Println(*edge2)
|
||||
fmt.Println(*edge3)
|
||||
|
||||
delete(graph[edge1.left], edge1.right)
|
||||
delete(graph[edge1.right], edge1.left)
|
||||
delete(graph[edge2.left], edge2.right)
|
||||
delete(graph[edge2.right], edge2.left)
|
||||
delete(graph[edge3.left], edge3.right)
|
||||
delete(graph[edge3.right], edge3.left)
|
||||
|
||||
result := buildVerticesLists(graph)
|
||||
|
||||
fmt.Println(result[0])
|
||||
fmt.Println(result[1])
|
||||
|
||||
return len(result[0]) * len(result[1])
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package day25
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gitea.paas.celticinfo.fr/oabrivard/aoc2023/utils"
|
||||
)
|
||||
|
||||
func TestPart1(t *testing.T) {
|
||||
lines := []string{
|
||||
"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",
|
||||
}
|
||||
|
||||
result := Part1(lines)
|
||||
|
||||
if result != 54 {
|
||||
t.Fatalf("expected 54, got %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPart1WithInput(t *testing.T) {
|
||||
lines := utils.ReadLines("input.txt")
|
||||
|
||||
result := Part1(lines)
|
||||
|
||||
if result != 2402 {
|
||||
t.Fatalf("expected 2402, got %d", result)
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue