partial d15
This commit is contained in:
parent
6a046fdb1c
commit
99242d53d7
6 changed files with 227 additions and 0 deletions
44
d15/common.go
Normal file
44
d15/common.go
Normal file
|
@ -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
|
||||
}
|
51
d15/d15_test.go
Normal file
51
d15/d15_test.go
Normal file
|
@ -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`)
|
||||
|
||||
}
|
58
d15/dijkstra.go
Normal file
58
d15/dijkstra.go
Normal file
|
@ -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]
|
||||
}
|
7
d15/dijkstra_test.go
Normal file
7
d15/dijkstra_test.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package d15
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestDijkstra(t *testing.T) {
|
||||
|
||||
}
|
6
d15/p1.go
Normal file
6
d15/p1.go
Normal file
|
@ -0,0 +1,6 @@
|
|||
package d15
|
||||
|
||||
func P1(in string) int {
|
||||
weights, neighbors := weightNeighbors(in)
|
||||
return dijkstra(0, node(len(weights)-1), weights, neighbors)
|
||||
}
|
61
d15/p2.go
Normal file
61
d15/p2.go
Normal file
|
@ -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)
|
||||
}
|
Loading…
Reference in a new issue