day23, example second

This commit is contained in:
efim 2023-12-23 12:00:48 +00:00
parent 7ebb6dee2c
commit 28cf35e0e4
4 changed files with 93 additions and 7 deletions

View File

@ -2,19 +2,21 @@ 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")
filename := "day23/input" filename := "day23/example"
field := ReadField(filename) field := ReadField(filename)
finalPaths := RunAllScenicPaths(field) finalPaths := RunDFSTingy(field)
log.Println(finalPaths)
max := 0 max := 0
for _, path := range finalPaths { for _, path := range finalPaths {
if path.visited.Cardinality() > max { if path.Visited.Cardinality() > max {
max = path.visited.Cardinality() max = path.Visited.Cardinality()
} }
} }
return max return max

View File

@ -27,6 +27,10 @@ type Field struct {
StartCol, EndCol int StartCol, EndCol int
} }
func (f *Field) EndCoord() Coord {
return Coord{Row: f.MaxRow, Col: f.EndCol}
}
func (f *Field) NeighborsPart2(c Coord) (neighbors []Coord) { func (f *Field) NeighborsPart2(c Coord) (neighbors []Coord) {
symb, exists := f.Cells[c] symb, exists := f.Cells[c]
if !exists { if !exists {

View File

@ -65,3 +65,8 @@ ok. but. if i'm entering the coord, and there are already paths to end.
then i need to presume that those are only possible paths to end from this point, then i need to presume that those are only possible paths to end from this point,
because all other paths should have been explored by now, because all other paths should have been explored by now,
i for my 'detour' determine whether it is consistent with any of already found paths to end. i for my 'detour' determine whether it is consistent with any of already found paths to end.
** NO. dfs doesn't mean i'll find shortest path first.
so if i'm in visited, it doesn't mean that stored is shorter and current is a detour.
but dfs should mean that all paths from this prefix have finished.
so, sure. there have to be all done?

View File

@ -27,19 +27,94 @@ func ExtendPath(p PathEnd, f Field) (nextPaths []PathEnd) {
return return
} }
// info on path from start to end
type PathInfo struct {
Visited mapset.Set[Coord]
}
func RunDFSTingy(f Field) []PathInfo {
initialPath := PathEnd{
end: Coord{Row: 0, Col: f.StartCol}, visited: mapset.NewSet[Coord](),
}
initialShared := make(map[Coord][]PathInfo)
return DFSScenicPaths(f, initialPath, initialShared)
}
func DFSScenicPaths(f Field, curPath PathEnd,
sharedMem map[Coord][]PathInfo) (pathsFromTheStartToEnd []PathInfo) {
curCoord := curPath.end
if curCoord == f.EndCoord() {
pathsFromTheStartToEnd = append(pathsFromTheStartToEnd, PathInfo{curPath.visited.Clone()})
log.Printf("got to end. visited %+v . will return %+v\n", curPath.visited, pathsFromTheStartToEnd)
// i guess return only from current to end?
// and on non terminal first time, return copy with self added?
return
}
// now for non final point
knownPaths, visitedBefore := sharedMem[curCoord]
// NOTE but this only if we haven't visited this coord before!
if !visitedBefore {
nextSteps := ExtendPath(curPath, f)
suffixesFromCurToEnd := make([]PathInfo, 0)
for _, nextPath := range nextSteps {
pathsToEndThrough := DFSScenicPaths(f, nextPath, sharedMem)
// i guess here deduct the prefix.
for _, path := range pathsToEndThrough {
// will contain this and further
suffix := PathInfo{
Visited: path.Visited.Difference(curPath.visited).Clone(),
}
suffixesFromCurToEnd = append(suffixesFromCurToEnd, suffix)
}
pathsFromTheStartToEnd = append(pathsFromTheStartToEnd, pathsToEndThrough...)
}
sharedMem[curCoord] = suffixesFromCurToEnd
return
} else {
// have visited this point before, due to dfs all possible paths to end should already be known
// so curPath.visited should contian a detour.
// need to figure out if this detour is compatible with any of the known paths to end
// from those create 'new' paths to end with that detour
// return those and add those to the shared mem
for _, knownPathToEnd := range knownPaths {
// those are all points through which this known path goes from current to end
// if our curPath
fromCurToEnd := knownPathToEnd.Visited
thisPrefix := curPath.visited
if thisPrefix.Intersect(fromCurToEnd).Cardinality() == 0 {
// then current prefix is compatible with this path.
fromCurPrefixToEnd := thisPrefix.Clone()
fromCurPrefixToEnd.Union(fromCurToEnd)
pathsFromTheStartToEnd = append(pathsFromTheStartToEnd, PathInfo{fromCurPrefixToEnd})
}
}
return
}
panic("should not be reachable")
}
// return paths that end on End // return paths that end on End
func RunAllScenicPaths(f Field) (result []PathEnd) { func RunAllScenicPaths(f Field) (result []PathEnd) {
pathsToFurther := []PathEnd{ pathsToFurther := []PathEnd{
{end: Coord{Row: 0, Col: f.StartCol}, visited: mapset.NewSet[Coord]()}, {end: Coord{Row: 0, Col: f.StartCol}, visited: mapset.NewSet[Coord]()},
} }
theEndCoord := Coord{Row: f.MaxRow, Col: f.EndCol}
for len(pathsToFurther) > 0 { for len(pathsToFurther) > 0 {
curCheckedPath := pathsToFurther[0] curCheckedPath := pathsToFurther[0]
pathsToFurther = pathsToFurther[1:] pathsToFurther = pathsToFurther[1:]
if curCheckedPath.end == theEndCoord { if curCheckedPath.end == f.EndCoord() {
result = append(result, curCheckedPath) result = append(result, curCheckedPath)
log.Printf("found end path of len %d . %+v", curCheckedPath.visited.Cardinality(), curCheckedPath) log.Printf("found end path of len %d . %+v", curCheckedPath.visited.Cardinality(), curCheckedPath)
continue continue