day23, part2
This commit is contained in:
parent
0c31596018
commit
2f6120fbd8
|
@ -2,24 +2,25 @@ package day23
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// length of longest scenic route
|
||||
func Run() int {
|
||||
fmt.Println("day 23")
|
||||
max := 0
|
||||
filename := "day23/input"
|
||||
field := ReadField(filename)
|
||||
finalPaths := RunDFSTingy(field)
|
||||
// log.Println(finalPaths)
|
||||
fmt.Println(field.SparseString())
|
||||
// finalPaths := RunDFSTingy(field)
|
||||
// // log.Println(finalPaths)
|
||||
|
||||
// for _, path := range finalPaths {
|
||||
// if path.Visited.Cardinality() > max {
|
||||
// log.Println("one path len is ", path.Visited.Cardinality())
|
||||
// max = path.Visited.Cardinality()
|
||||
// }
|
||||
// }
|
||||
|
||||
max := 0
|
||||
for _, path := range finalPaths {
|
||||
if path.Visited.Cardinality() > max {
|
||||
log.Println("one path len is ", path.Visited.Cardinality())
|
||||
max = path.Visited.Cardinality()
|
||||
}
|
||||
}
|
||||
return max
|
||||
}
|
||||
|
||||
|
|
|
@ -118,6 +118,36 @@ func (f *Field) String() (result string) {
|
|||
return
|
||||
}
|
||||
|
||||
func (f *Field) SparseString() (result string) {
|
||||
result += "\n"
|
||||
for row := 0; row <= f.MaxRow; row++ {
|
||||
for col := 0; col <= f.MaxCol; col++ {
|
||||
if row == 0 && col == f.StartCol {
|
||||
result += "S"
|
||||
continue
|
||||
}
|
||||
if row == f.MaxRow && col == f.EndCol {
|
||||
result += "E"
|
||||
continue
|
||||
}
|
||||
|
||||
symb := f.Cells[Coord{Row: row, Col: col}]
|
||||
if symb != Tree {
|
||||
neighbors := f.NeighborsPart2(Coord{Row: row, Col: col})
|
||||
if len(neighbors) > 2 {
|
||||
result += "o"
|
||||
} else {
|
||||
result += "."
|
||||
}
|
||||
} else {
|
||||
result += " "
|
||||
}
|
||||
}
|
||||
result += "\n"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ReadField(filename string) (result Field) {
|
||||
bytes, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,248 @@
|
|||
package day23
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"slices"
|
||||
|
||||
mapset "github.com/deckarep/golang-set/v2"
|
||||
)
|
||||
|
||||
type Node struct {
|
||||
index int
|
||||
c Coord
|
||||
name string
|
||||
}
|
||||
func (n Node)Name() string {
|
||||
var r string
|
||||
if n.index < 25 {
|
||||
num := 'A' + n.index
|
||||
r = string(rune(num))
|
||||
} else {
|
||||
num := 'a' + n.index - 25
|
||||
r = string(rune(num))
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
type Graph struct {
|
||||
nodes map[Coord]Node
|
||||
nodesByIndex []Node
|
||||
edges [][]int // from, to, length. excluding from, including to
|
||||
}
|
||||
|
||||
func MaxDist(from, to Node) (result int) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func PrintFieldWithGraph(g Graph, f Field) (result string) {
|
||||
result += "\n"
|
||||
for row := 0; row <= f.MaxRow; row++ {
|
||||
for col := 0; col <= f.MaxCol; col++ {
|
||||
symb := f.Cells[Coord{Row: row, Col: col}]
|
||||
if symb != Tree {
|
||||
coord := Coord{Row: row, Col: col}
|
||||
node, exists := g.nodes[coord]
|
||||
if exists {
|
||||
result += fmt.Sprint(node.Name())
|
||||
} else {
|
||||
result += "."
|
||||
}
|
||||
} else {
|
||||
result += " "
|
||||
}
|
||||
}
|
||||
result += "\n"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CreateGraph(f Field) (g Graph) {
|
||||
startCoord := Coord{Row: 0, Col: f.StartCol}
|
||||
// directly below start
|
||||
initialPath := PathEnd{
|
||||
end: Coord{Row: 1, Col: f.StartCol}, visited: mapset.NewSet[Coord](),
|
||||
}
|
||||
|
||||
g = Graph{
|
||||
nodes: map[Coord]Node{
|
||||
startCoord: Node{
|
||||
index: 0,
|
||||
c: startCoord,
|
||||
name: "A",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const presumedNodeCount = 36
|
||||
g.edges = make([][]int, presumedNodeCount)
|
||||
for i := 0; i < presumedNodeCount; i++ {
|
||||
g.edges[i] = make([]int, presumedNodeCount)
|
||||
}
|
||||
|
||||
recursiveGraphStep(f, initialPath, &g, startCoord, 1, mapset.NewSet[Coord]())
|
||||
g.edges[0][0] = 0
|
||||
|
||||
g.nodesByIndex = make([]Node, len(g.nodes))
|
||||
for _, node := range g.nodes {
|
||||
g.nodesByIndex[node.index] = node
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (g *Graph)Neighbors(node Node) (nodes []Node) {
|
||||
index := node.index
|
||||
for toIndex, len := range g.edges[index] {
|
||||
if len > 0 {
|
||||
nodes = append(nodes, g.nodesByIndex[toIndex])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var maxSoFar int = -1
|
||||
func CheckMaxSoFar(maybe int) {
|
||||
if maybe > maxSoFar {
|
||||
maxSoFar = maybe
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Graph) DFSLenOnGraph(atNode Node, visited mapset.Set[int],
|
||||
toNode Node, lenSoFar int) int {
|
||||
|
||||
if atNode == toNode {
|
||||
CheckMaxSoFar(lenSoFar)
|
||||
return lenSoFar
|
||||
}
|
||||
log.Printf("at %+v to %+v cur dist is %d.\t\t|max so far %d| \n", atNode, toNode, lenSoFar, maxSoFar)
|
||||
|
||||
neighbors := g.Neighbors(atNode)
|
||||
toVisit := slices.DeleteFunc(neighbors, func(n Node) bool {
|
||||
return visited.Contains(n.index)
|
||||
})
|
||||
|
||||
if len(toVisit) == 0 {
|
||||
return -1
|
||||
}
|
||||
max := -1
|
||||
|
||||
for _, nextNode := range toVisit {
|
||||
newVisited := visited.Clone()
|
||||
newVisited.Add(atNode.index)
|
||||
dist := g.edges[atNode.index][nextNode.index]
|
||||
maxFromNext := g.DFSLenOnGraph(nextNode, newVisited, toNode, lenSoFar + dist)
|
||||
if maxFromNext > max {
|
||||
max = maxFromNext
|
||||
}
|
||||
}
|
||||
|
||||
return max
|
||||
}
|
||||
|
||||
// run dfs, remembering from which remembers from which node we go, which path already traversed
|
||||
func recursiveGraphStep(f Field, p PathEnd, g *Graph, goingFrom Coord, goingLen int, visitedPathPoints mapset.Set[Coord]) {
|
||||
// log.Printf("entering coord %+v. from %+v with len %d\n", p.end, goingFrom, goingLen)
|
||||
|
||||
// if visitedPathPoints.Contains(p.end) {
|
||||
// return
|
||||
// }
|
||||
|
||||
neighbors := f.NeighborsPart2(p.end)
|
||||
|
||||
isCrossRoad := len(neighbors) > 2
|
||||
if isCrossRoad {
|
||||
log.Println("this should be crossroad ", p.end)
|
||||
}
|
||||
isStart := p.end == Coord{Row: 0, Col: f.StartCol}
|
||||
isEnd := p.end == f.EndCoord()
|
||||
if isEnd {
|
||||
log.Println("this should be end ", p.end)
|
||||
}
|
||||
|
||||
isNode := isCrossRoad || isStart || isEnd
|
||||
|
||||
continuedPaths := ExtendPath(p, f)
|
||||
|
||||
if !isNode {
|
||||
// just recurse into next paths, from same node, with increased len
|
||||
visitedPathPoints.Add(p.end)
|
||||
for _, nextStep := range continuedPaths {
|
||||
recursiveGraphStep(f, nextStep, g, goingFrom, goingLen+1, visitedPathPoints)
|
||||
}
|
||||
} else {
|
||||
node, known := g.nodes[p.end]
|
||||
// check if known, if not known - create
|
||||
if !known {
|
||||
node = Node{
|
||||
c: p.end,
|
||||
index: len(g.nodes),
|
||||
}
|
||||
node.name = node.Name()
|
||||
g.nodes[p.end] = node
|
||||
log.Printf("creating node %s %+v\n", node.Name(), node)
|
||||
}
|
||||
from := g.nodes[goingFrom]
|
||||
log.Printf("from %s to %s\n", from.Name(), node.Name())
|
||||
// and add vertices to currently traversed
|
||||
if g.edges[node.index][from.index] == 0 {
|
||||
g.edges[node.index][from.index] = goingLen
|
||||
g.edges[from.index][node.index] = goingLen
|
||||
} else {
|
||||
knownEdge := g.edges[node.index][from.index]
|
||||
if goingLen > knownEdge {
|
||||
g.edges[node.index][from.index] = goingLen
|
||||
g.edges[from.index][node.index] = goingLen
|
||||
}
|
||||
}
|
||||
// NOTE ah, it's possible to have two edges between i and j
|
||||
// but, i only need the longest one
|
||||
// log.Printf("adding edges between %d & %d of len %d\n", node.index, from.index, goingLen)
|
||||
|
||||
// continue with new 'from' and len of 1
|
||||
if !known {
|
||||
for _, nextStep := range continuedPaths {
|
||||
log.Printf("from %s should recurse to %+v", node.Name(), nextStep)
|
||||
recursiveGraphStep(f, nextStep, g, p.end, 1, visitedPathPoints)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func GraphToMermaid(g Graph) (result string) {
|
||||
result += "\nflowchart LR\n"
|
||||
lines := mapset.NewSet[string]()
|
||||
for _, node := range g.nodes {
|
||||
for to, len := range g.edges[node.index] {
|
||||
var toNode Node
|
||||
for _, other := range g.nodes {
|
||||
if other.index == to {
|
||||
toNode = other
|
||||
}
|
||||
}
|
||||
if len > 0 {
|
||||
var fromName, toName string
|
||||
if node.index < toNode.index {
|
||||
fromName = node.Name()
|
||||
toName = toNode.Name()
|
||||
} else {
|
||||
fromName = toNode.Name()
|
||||
toName = node.Name()
|
||||
}
|
||||
line := fmt.Sprintf("\t%s---|length %d|%s\n", fromName, len, toName)
|
||||
lines.Add(line)
|
||||
}
|
||||
}
|
||||
// result += fmt.Sprintf("%s--|%d|%s\n", a ...any)
|
||||
}
|
||||
|
||||
for line := range lines.Iter() {
|
||||
result += line
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
package day23
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
mapset "github.com/deckarep/golang-set/v2"
|
||||
)
|
||||
|
||||
func TestGraphCreate(t *testing.T) {
|
||||
filename := "example2"
|
||||
field := ReadField(filename)
|
||||
|
||||
fmt.Println(field.SparseString())
|
||||
|
||||
graph := CreateGraph(field)
|
||||
t.Log(graph)
|
||||
}
|
||||
|
||||
func TestPrintGraph(t *testing.T) {
|
||||
filename := "example2"
|
||||
field := ReadField(filename)
|
||||
|
||||
fmt.Println(field.SparseString())
|
||||
|
||||
graph := CreateGraph(field)
|
||||
t.Log(PrintFieldWithGraph(graph, field))
|
||||
t.Logf(">>>\n %+v\n", graph)
|
||||
|
||||
}
|
||||
|
||||
func TestPrintGraphInput(t *testing.T) {
|
||||
filename := "input"
|
||||
field := ReadField(filename)
|
||||
|
||||
fmt.Println(field.SparseString())
|
||||
|
||||
graph := CreateGraph(field)
|
||||
t.Log(PrintFieldWithGraph(graph, field))
|
||||
t.Logf(">>>\n %+v\n", graph)
|
||||
|
||||
}
|
||||
|
||||
func TestPrintMermaidGraphInput(t *testing.T) {
|
||||
filename := "input"
|
||||
field := ReadField(filename)
|
||||
|
||||
fmt.Println(field.SparseString())
|
||||
|
||||
graph := CreateGraph(field)
|
||||
mmdContent := GraphToMermaid(graph)
|
||||
t.Log(mmdContent)
|
||||
|
||||
fileBorder, err := os.Create(filename + ".mmd")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := fileBorder.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
fileBorder.WriteString(mmdContent)
|
||||
}
|
||||
|
||||
func TestGraphMaxBetweenExample(t *testing.T) {
|
||||
filename := "example"
|
||||
field := ReadField(filename)
|
||||
graph := CreateGraph(field)
|
||||
|
||||
t.Log(PrintFieldWithGraph(graph, field))
|
||||
|
||||
|
||||
from := graph.nodes[Coord{Row: 0, Col: field.StartCol}]
|
||||
to := graph.nodes[field.EndCoord()]
|
||||
|
||||
dist := graph.DFSLenOnGraph(from, mapset.NewSet[int](), to, 0)
|
||||
|
||||
t.Log(graph)
|
||||
t.Logf("please dist %d", dist)
|
||||
|
||||
}
|
||||
|
||||
func TestGraphMaxBetweenInput(t *testing.T) {
|
||||
filename := "input"
|
||||
field := ReadField(filename)
|
||||
|
||||
graph := CreateGraph(field)
|
||||
|
||||
t.Log(PrintFieldWithGraph(graph, field))
|
||||
from := graph.nodes[Coord{Row: 0, Col: field.StartCol}]
|
||||
to := graph.nodes[field.EndCoord()]
|
||||
|
||||
dist := graph.DFSLenOnGraph(from, mapset.NewSet[int](), to, 0)
|
||||
|
||||
t.Log(graph)
|
||||
t.Logf("please dist %d", dist)
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
flowchart LR
|
||||
M---|length 166|N
|
||||
d---|length 62|h
|
||||
H---|length 190|I
|
||||
f---|length 136|h
|
||||
j---|length 94|k
|
||||
B---|length 152|L
|
||||
I---|length 40|J
|
||||
W---|length 56|X
|
||||
E---|length 214|F
|
||||
C---|length 60|K
|
||||
V---|length 142|b
|
||||
a---|length 110|b
|
||||
I---|length 138|P
|
||||
J---|length 184|K
|
||||
Y---|length 146|a
|
||||
c---|length 190|d
|
||||
Q---|length 114|T
|
||||
J---|length 240|O
|
||||
C---|length 184|D
|
||||
L---|length 172|M
|
||||
Q---|length 140|R
|
||||
Y---|length 464|k
|
||||
O---|length 76|V
|
||||
N---|length 102|O
|
||||
K---|length 152|L
|
||||
U---|length 80|c
|
||||
V---|length 72|W
|
||||
b---|length 202|j
|
||||
A---|length 39|B
|
||||
W---|length 236|a
|
||||
P---|length 166|Q
|
||||
e---|length 174|f
|
||||
G---|length 186|R
|
||||
T---|length 258|d
|
||||
X---|length 142|Y
|
||||
b---|length 128|c
|
||||
F---|length 378|G
|
||||
S---|length 108|T
|
||||
N---|length 62|W
|
||||
U---|length 110|V
|
||||
a---|length 138|k
|
||||
S---|length 234|e
|
||||
d---|length 108|e
|
||||
H---|length 166|Q
|
||||
O---|length 158|P
|
||||
M---|length 360|X
|
||||
h---|length 184|i
|
||||
B---|length 244|C
|
||||
D---|length 96|J
|
||||
D---|length 154|E
|
||||
R---|length 118|S
|
||||
E---|length 146|I
|
||||
P---|length 128|U
|
||||
T---|length 268|U
|
||||
i---|length 198|j
|
||||
G---|length 144|H
|
||||
F---|length 102|H
|
||||
f---|length 77|g
|
||||
K---|length 266|N
|
||||
c---|length 64|i
|
|
@ -76,3 +76,50 @@ so 4,10 and 3,11 should be visited separately.
|
|||
6,17 is where they join and the point which should have second entry
|
||||
** allright, ugh. my new solution is memory hogging.
|
||||
maybe i can draw the stuff and it will be several neat thingies
|
||||
* maybe new approach?
|
||||
make a graph. with vertices of Start, End and Crossroads.
|
||||
yes.
|
||||
let's create a graph representation.
|
||||
** so, from A to AG
|
||||
i think i can do this manually now
|
||||
** distances are
|
||||
39
|
||||
244
|
||||
184
|
||||
154
|
||||
214
|
||||
378
|
||||
144
|
||||
190
|
||||
40
|
||||
184
|
||||
152
|
||||
172
|
||||
166
|
||||
102
|
||||
158
|
||||
166
|
||||
140
|
||||
118
|
||||
108
|
||||
268
|
||||
110
|
||||
72
|
||||
56
|
||||
142
|
||||
146
|
||||
110
|
||||
128
|
||||
190
|
||||
108
|
||||
174
|
||||
77
|
||||
1
|
||||
** again?
|
||||
no, let's write code.
|
||||
** didn't count all the way
|
||||
2023/12/23 15:55:55 at {index:30 c:{Row:125 Col:137} name:f} to {index:31 c:{Row:140 Col:139} name:g} cur dist is 3997. |max so far 6406|
|
||||
signal: interrupt
|
||||
FAIL sunshine.industries/aoc2023/day23 380.499s
|
||||
|
||||
tried more or less stable value, and interrupted
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
flowchart LR
|
||||
L---|length 152|K
|
||||
L---|length 172|M
|
||||
U---|length 268|T
|
||||
U---|length 110|V
|
||||
W---|length 72|V
|
||||
W---|length 56|X
|
||||
a---|length 146|Y
|
||||
a---|length 110|b
|
||||
f---|length 174|e
|
||||
f---|length 77|g
|
||||
f---|length 136|h
|
||||
H---|length 144|G
|
||||
H---|length 190|I
|
||||
T---|length 108|S
|
||||
T---|length 268|U
|
||||
M---|length 172|L
|
||||
M---|length 166|N
|
||||
F---|length 214|E
|
||||
F---|length 378|G
|
||||
I---|length 190|H
|
||||
I---|length 40|J
|
||||
A---|length 2|A
|
||||
A---|length 39|B
|
||||
Q---|length 166|P
|
||||
Q---|length 140|R
|
||||
Y---|length 142|X
|
||||
Y---|length 146|a
|
||||
d---|length 190|c
|
||||
d---|length 108|e
|
||||
e---|length 108|d
|
||||
e---|length 174|f
|
||||
h---|length 136|f
|
||||
h---|length 184|i
|
||||
J---|length 40|I
|
||||
J---|length 184|K
|
||||
N---|length 166|M
|
||||
N---|length 102|O
|
||||
X---|length 56|W
|
||||
X---|length 142|Y
|
||||
j---|length 198|i
|
||||
j---|length 94|k
|
||||
B---|length 39|A
|
||||
B---|length 244|C
|
||||
G---|length 378|F
|
||||
G---|length 144|H
|
||||
P---|length 158|O
|
||||
P---|length 166|Q
|
||||
D---|length 184|C
|
||||
D---|length 154|E
|
||||
E---|length 154|D
|
||||
E---|length 214|F
|
||||
K---|length 184|J
|
||||
K---|length 152|L
|
||||
O---|length 102|N
|
||||
O---|length 158|P
|
||||
R---|length 140|Q
|
||||
R---|length 118|S
|
||||
S---|length 118|R
|
||||
S---|length 108|T
|
||||
V---|length 110|U
|
||||
V---|length 72|W
|
||||
c---|length 128|b
|
||||
c---|length 190|d
|
||||
C---|length 244|B
|
||||
C---|length 184|D
|
||||
k---|length 94|j
|
||||
i---|length 184|h
|
||||
i---|length 198|j
|
||||
g---|length 77|f
|
||||
b---|length 110|a
|
||||
b---|length 128|c
|
Binary file not shown.
After Width: | Height: | Size: 203 KiB |
Loading…
Reference in New Issue