diff --git a/d15/common.go b/d15/common.go new file mode 100644 index 0000000..2bacdab --- /dev/null +++ b/d15/common.go @@ -0,0 +1,44 @@ +package d15 + +import ( + "strconv" + "strings" +) + +func weightNeighbors(in string) (weights, neighbors) { + weights := make(weights) + neighbors := make(neighbors) + lines := strings.Split(strings.TrimSpace(in), "\n") + height := len(lines) + width := len(lines[0]) + for y, line := range lines { + for x, weight := range strings.Split(line, "") { + weight, _ := strconv.Atoi(weight) + weights[node(x+y*height)] = weight + } + } + maxX := width + maxY := height + for height >= 0 { + width = maxX + for width >= 0 { + current := node(width + height*maxY) + if height > 0 { + neighbors[current] = append(neighbors[current], node(width+(height-1)*maxY)) + } + if height < maxY { + neighbors[current] = append(neighbors[current], node(width+(height+1)*maxY)) + } + if width > 0 { + neighbors[current] = append(neighbors[current], node(width+height*maxY-1)) + } + if width < maxX { + neighbors[current] = append(neighbors[current], node(width+height*maxY+1)) + + } + width-- + } + height-- + } + return weights, neighbors +} diff --git a/d15/d15_test.go b/d15/d15_test.go new file mode 100644 index 0000000..fca2df7 --- /dev/null +++ b/d15/d15_test.go @@ -0,0 +1,51 @@ +package d15 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestP1(t *testing.T) { + result := P1(`1163751742 +1381373672 +2136511328 +3694931569 +7463417111 +1319128137 +1359912421 +3125421639 +1293138521 +2311944581`) + + assert.EqualValues(t, 40, result) +} + +func TestP2(t *testing.T) { + result := P2(`1163751742 +1381373672 +2136511328 +3694931569 +7463417111 +1319128137 +1359912421 +3125421639 +1293138521 +2311944581`) + + assert.EqualValues(t, 315, result) +} + +func BenchmarkP2(t *testing.B) { + P2(`1163751742 +1381373672 +2136511328 +3694931569 +7463417111 +1319128137 +1359912421 +3125421639 +1293138521 +2311944581`) + +} diff --git a/d15/dijkstra.go b/d15/dijkstra.go new file mode 100644 index 0000000..b350c68 --- /dev/null +++ b/d15/dijkstra.go @@ -0,0 +1,58 @@ +package d15 + +import ( + "math" + + "golang.org/x/exp/maps" +) + +type node int + +type weights map[node]int + +type neighbors map[node][]node + +func minDistance(unvisited weights, distances weights) node { + var min node + var minDistance = math.MaxInt64 + for current := range unvisited { + if distances[current] < minDistance { + min = current + minDistance = distances[current] + } + } + + return min +} + +func assignMap[M ~map[K]V, K comparable, V any](m M, v V) M { + n := make(M, len(m)) + for k := range m { + n[k] = v + } + return n + +} + +func dijkstra(start node, end node, weights weights, neighbors neighbors) int { + distances := assignMap(weights, math.MaxInt64) + unvisited := maps.Clone(weights) + + distances[start] = 0 + + for len(unvisited) != 0 { + current := minDistance(unvisited, distances) + + delete(unvisited, current) + + for _, neighbor := range neighbors[current] { + oldDistance := distances[neighbor] + newDistance := weights[neighbor] + distances[current] + if newDistance < oldDistance { + distances[neighbor] = newDistance + } + } + } + + return distances[end] +} diff --git a/d15/dijkstra_test.go b/d15/dijkstra_test.go new file mode 100644 index 0000000..b97b868 --- /dev/null +++ b/d15/dijkstra_test.go @@ -0,0 +1,7 @@ +package d15 + +import "testing" + +func TestDijkstra(t *testing.T) { + +} diff --git a/d15/p1.go b/d15/p1.go new file mode 100644 index 0000000..04ac9e9 --- /dev/null +++ b/d15/p1.go @@ -0,0 +1,6 @@ +package d15 + +func P1(in string) int { + weights, neighbors := weightNeighbors(in) + return dijkstra(0, node(len(weights)-1), weights, neighbors) +} diff --git a/d15/p2.go b/d15/p2.go new file mode 100644 index 0000000..727f150 --- /dev/null +++ b/d15/p2.go @@ -0,0 +1,61 @@ +package d15 + +import ( + "fmt" + "strconv" + "strings" +) + +func expand(in [][]int) [][]int { + height := len(in) + width := len(in[0]) + + expanded := make([][]int, height*5) + + for y := range expanded { + expanded[y] = make([]int, width*5) + } + + for y, line := range in { + for x, num := range line { + for i := 0; i < 5; i++ { + for j := 0; j < 5; j++ { + expanded[y+(height*i)][x+(width*j)] = (num + i + j) % 9 + } + } + } + } + + return expanded +} + +func expandMap(in string) string { + lines := make([][]int, 0) + for _, line := range strings.Split(strings.TrimSpace(in), "\n") { + nums := make([]int, 0) + for _, weight := range strings.Split(line, "") { + weight, _ := strconv.Atoi(weight) + nums = append(nums, weight) + } + lines = append(lines, nums) + } + + expanded := expand(lines) + + newMap := "" + + for _, line := range expanded { + for _, num := range line { + newMap = newMap + fmt.Sprint(num) + } + + newMap += "\n" + } + + return newMap +} + +func P2(in string) int { + weights, neighbors := weightNeighbors(expandMap(in)) + return dijkstra(0, node(len(weights)-1), weights, neighbors) +}