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 (
"fmt"
"log"
)
// length of longest scenic route
func Run() int {
fmt.Println("day 23")
filename := "day23/input"
filename := "day23/example"
field := ReadField(filename)
finalPaths := RunAllScenicPaths(field)
finalPaths := RunDFSTingy(field)
log.Println(finalPaths)
max := 0
for _, path := range finalPaths {
if path.visited.Cardinality() > max {
max = path.visited.Cardinality()
if path.Visited.Cardinality() > max {
max = path.Visited.Cardinality()
}
}
return max

View File

@ -27,6 +27,10 @@ type Field struct {
StartCol, EndCol int
}
func (f *Field) EndCoord() Coord {
return Coord{Row: f.MaxRow, Col: f.EndCol}
}
func (f *Field) NeighborsPart2(c Coord) (neighbors []Coord) {
symb, exists := f.Cells[c]
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,
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.
** 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
}
// 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
func RunAllScenicPaths(f Field) (result []PathEnd) {
pathsToFurther := []PathEnd{
{end: Coord{Row: 0, Col: f.StartCol}, visited: mapset.NewSet[Coord]()},
}
theEndCoord := Coord{Row: f.MaxRow, Col: f.EndCol}
for len(pathsToFurther) > 0 {
curCheckedPath := pathsToFurther[0]
pathsToFurther = pathsToFurther[1:]
if curCheckedPath.end == theEndCoord {
if curCheckedPath.end == f.EndCoord() {
result = append(result, curCheckedPath)
log.Printf("found end path of len %d . %+v", curCheckedPath.visited.Cardinality(), curCheckedPath)
continue