mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-05-18 19:13:27 +02:00
2017-day24: recursive backtrack again, bubble up longest bridge and highest sum
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/alexchao26/advent-of-code-go/util"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var part int
|
||||
flag.IntVar(&part, "part", 1, "part 1 or 2")
|
||||
flag.Parse()
|
||||
fmt.Println("Running part", part)
|
||||
|
||||
ans := magneticMoat(util.ReadFile("./input.txt"), part)
|
||||
fmt.Println("Output:", ans)
|
||||
}
|
||||
|
||||
func magneticMoat(input string, part int) int {
|
||||
edges := getEdges(input)
|
||||
|
||||
// start the bridge with a zero
|
||||
bridge := [][2]int{
|
||||
{0, 0},
|
||||
}
|
||||
|
||||
usedEdges := map[[2]int]bool{}
|
||||
for _, edge := range edges {
|
||||
usedEdges[edge] = false
|
||||
}
|
||||
|
||||
bestStrength, longestBridge := backtrackBridge(bridge, usedEdges)
|
||||
if part == 1 {
|
||||
return bestStrength
|
||||
}
|
||||
return calcStrengthOfBridge(longestBridge)
|
||||
}
|
||||
|
||||
// backtracking algo that returns strongest bridge
|
||||
func backtrackBridge(bridge [][2]int, usedEdges map[[2]int]bool) (bestStrength int, longestBridge [][2]int) {
|
||||
lastVal := bridge[len(bridge)-1][1]
|
||||
for edge, isUsed := range usedEdges {
|
||||
// skip edges that are marked as used
|
||||
if !isUsed {
|
||||
clonedEdge := edge
|
||||
// swap the edge vals if the first doesn't match
|
||||
if clonedEdge[0] != lastVal {
|
||||
clonedEdge[0], clonedEdge[1] = clonedEdge[1], clonedEdge[0]
|
||||
}
|
||||
// if match is found, add it to bridge, mark as used
|
||||
// add to strength, recurse
|
||||
if clonedEdge[0] == lastVal {
|
||||
bridge = append(bridge, clonedEdge)
|
||||
usedEdges[edge] = true
|
||||
strength := clonedEdge[0] + clonedEdge[1]
|
||||
|
||||
// recurse and bestStrength and longestLength
|
||||
subStrength, subLongestBridge := backtrackBridge(bridge, usedEdges)
|
||||
|
||||
strength += subStrength
|
||||
|
||||
// if current bridge is longest (or wins tiebreak) set the longestBridge
|
||||
if len(bridge) > len(longestBridge) ||
|
||||
(len(bridge) == len(longestBridge) &&
|
||||
calcStrengthOfBridge(bridge) > calcStrengthOfBridge(longestBridge)) {
|
||||
// use this hacky append to create a copy of the bridge slice
|
||||
// otherwise appends could modify the underlying array
|
||||
longestBridge = append([][2]int{}, bridge...)
|
||||
}
|
||||
// also check if a recursive call had the longest bridge, update longest
|
||||
if len(subLongestBridge) > len(longestBridge) ||
|
||||
(len(subLongestBridge) == len(longestBridge) &&
|
||||
calcStrengthOfBridge(subLongestBridge) > calcStrengthOfBridge(longestBridge)) {
|
||||
longestBridge = append([][2]int{}, subLongestBridge...)
|
||||
}
|
||||
|
||||
// backtrack
|
||||
usedEdges[edge] = false
|
||||
bridge = bridge[:len(bridge)-1]
|
||||
if strength > bestStrength {
|
||||
bestStrength = strength
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bestStrength, longestBridge
|
||||
}
|
||||
|
||||
func calcStrengthOfBridge(bridge [][2]int) int {
|
||||
var sum int
|
||||
for _, edge := range bridge {
|
||||
sum += edge[0] + edge[1]
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
func getEdges(input string) (edges [][2]int) {
|
||||
for _, line := range strings.Split(input, "\n") {
|
||||
var pair [2]int
|
||||
fmt.Sscanf(line, "%d/%d", &pair[0], &pair[1])
|
||||
edges = append(edges, pair)
|
||||
}
|
||||
return edges
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/alexchao26/advent-of-code-go/util"
|
||||
)
|
||||
|
||||
var example = `0/2
|
||||
2/2
|
||||
2/3
|
||||
3/4
|
||||
3/5
|
||||
0/1
|
||||
10/1
|
||||
9/10`
|
||||
|
||||
func Test_magneticMoat(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
part int
|
||||
want int
|
||||
}{
|
||||
{"example_part1", example, 1, 31},
|
||||
{"actual_part1", util.ReadFile("input.txt"), 1, 1868},
|
||||
{"example_part2", example, 2, 19},
|
||||
{"actual_part2", util.ReadFile("input.txt"), 2, 1841},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := magneticMoat(tt.input, tt.part); got != tt.want {
|
||||
t.Errorf("magneticMoat() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user