day23, part2

This commit is contained in:
efim 2023-12-23 15:56:25 +00:00
parent 0c31596018
commit 2f6120fbd8
8 changed files with 571 additions and 10 deletions

View File

@ -2,24 +2,25 @@ package day23
import ( import (
"fmt" "fmt"
"log"
) )
// length of longest scenic route // length of longest scenic route
func Run() int { func Run() int {
fmt.Println("day 23") fmt.Println("day 23")
max := 0
filename := "day23/input" filename := "day23/input"
field := ReadField(filename) field := ReadField(filename)
finalPaths := RunDFSTingy(field) fmt.Println(field.SparseString())
// log.Println(finalPaths) // 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 return max
} }

View File

@ -118,6 +118,36 @@ func (f *Field) String() (result string) {
return 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) { func ReadField(filename string) (result Field) {
bytes, err := os.ReadFile(filename) bytes, err := os.ReadFile(filename)
if err != nil { if err != nil {

248
day23/graph.go Normal file
View File

@ -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
}

101
day23/graph_test.go Normal file
View File

@ -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)
}

62
day23/input.mmd Normal file
View File

@ -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

View File

@ -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 6,17 is where they join and the point which should have second entry
** allright, ugh. my new solution is memory hogging. ** allright, ugh. my new solution is memory hogging.
maybe i can draw the stuff and it will be several neat thingies 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

72
day23/willHelp.mmd Normal file
View File

@ -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

BIN
day23/willHelp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB