diff --git a/day23/aLongWalk.go b/day23/aLongWalk.go index 37e44af..310ee8b 100644 --- a/day23/aLongWalk.go +++ b/day23/aLongWalk.go @@ -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 diff --git a/day23/field.go b/day23/field.go index 45adf50..8d841d7 100644 --- a/day23/field.go +++ b/day23/field.go @@ -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 { diff --git a/day23/notes.org b/day23/notes.org index d5e569f..d19a051 100644 --- a/day23/notes.org +++ b/day23/notes.org @@ -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? diff --git a/day23/paths.go b/day23/paths.go index 7920b2a..6ab7a19 100644 --- a/day23/paths.go +++ b/day23/paths.go @@ -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