day23, example second
This commit is contained in:
parent
7ebb6dee2c
commit
28cf35e0e4
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue