day23, part1
This commit is contained in:
parent
c3acf211c3
commit
44de1377ca
|
@ -0,0 +1,22 @@
|
||||||
|
package day23
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// length of longest scenic route
|
||||||
|
func Run() int {
|
||||||
|
fmt.Println("day 23")
|
||||||
|
filename := "day23/example"
|
||||||
|
field := ReadField(filename)
|
||||||
|
finalPaths := RunAllScenicPaths(field)
|
||||||
|
|
||||||
|
max := 0
|
||||||
|
for _, path := range finalPaths {
|
||||||
|
if path.visited.Cardinality() > max {
|
||||||
|
max = path.visited.Cardinality()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
#.#####################
|
||||||
|
#.......#########...###
|
||||||
|
#######.#########.#.###
|
||||||
|
###.....#.>.>.###.#.###
|
||||||
|
###v#####.#v#.###.#.###
|
||||||
|
###.>...#.#.#.....#...#
|
||||||
|
###v###.#.#.#########.#
|
||||||
|
###...#.#.#.......#...#
|
||||||
|
#####.#.#.#######.#.###
|
||||||
|
#.....#.#.#.......#...#
|
||||||
|
#.#####.#.#.#########v#
|
||||||
|
#.#...#...#...###...>.#
|
||||||
|
#.#.#v#######v###.###v#
|
||||||
|
#...#.>.#...>.>.#.###.#
|
||||||
|
#####v#.#.###v#.#.###.#
|
||||||
|
#.....#...#...#.#.#...#
|
||||||
|
#.#########.###.#.#.###
|
||||||
|
#...###...#...#...#.###
|
||||||
|
###.###.#.###v#####v###
|
||||||
|
#...#...#.#.>.>.#.>.###
|
||||||
|
#.###.###.#.###.#.#v###
|
||||||
|
#.....###...###...#...#
|
||||||
|
#####################.#
|
|
@ -0,0 +1,112 @@
|
||||||
|
package day23
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Coord struct {
|
||||||
|
Row, Col int
|
||||||
|
}
|
||||||
|
|
||||||
|
type CellType rune
|
||||||
|
|
||||||
|
const (
|
||||||
|
Path CellType = '.'
|
||||||
|
Tree CellType = '#'
|
||||||
|
SlideDown CellType = 'v'
|
||||||
|
SlideUp CellType = '^'
|
||||||
|
SlideLeft CellType = '<'
|
||||||
|
SlideRight CellType = '>'
|
||||||
|
)
|
||||||
|
|
||||||
|
type Field struct {
|
||||||
|
MaxRow, MaxCol int
|
||||||
|
Cells map[Coord]CellType
|
||||||
|
StartCol, EndCol int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Field) Neighbors(c Coord) (neighbors []Coord) {
|
||||||
|
symb, exists := f.Cells[c]
|
||||||
|
if !exists {
|
||||||
|
panic(fmt.Sprintf("coord %+v not found in field", c))
|
||||||
|
}
|
||||||
|
|
||||||
|
var coords []Coord
|
||||||
|
switch symb {
|
||||||
|
case Path:
|
||||||
|
coords = []Coord{
|
||||||
|
{Row: c.Row + 1, Col: c.Col},
|
||||||
|
{Row: c.Row - 1, Col: c.Col},
|
||||||
|
{Row: c.Row, Col: c.Col + 1},
|
||||||
|
{Row: c.Row, Col: c.Col - 1},
|
||||||
|
}
|
||||||
|
case Tree:
|
||||||
|
panic(fmt.Sprintf("attempting to get neighbors of a tree at %+v", c))
|
||||||
|
case SlideDown:
|
||||||
|
coords = []Coord{{Row: c.Row + 1, Col: c.Col}}
|
||||||
|
case SlideUp:
|
||||||
|
coords = []Coord{{Row: c.Row - 1, Col: c.Col}}
|
||||||
|
case SlideLeft:
|
||||||
|
coords = []Coord{{Row: c.Row, Col: c.Col - 1}}
|
||||||
|
case SlideRight:
|
||||||
|
coords = []Coord{{Row: c.Row, Col: c.Col + 1}}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, coord := range coords {
|
||||||
|
neighborSymb, found := f.Cells[coord]
|
||||||
|
if !found || neighborSymb == Tree {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
neighbors = append(neighbors, coord)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Field) String() (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}]
|
||||||
|
result += string(symb)
|
||||||
|
}
|
||||||
|
result += "\n"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadField(filename string) (result Field) {
|
||||||
|
bytes, err := os.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
lines := strings.Split(strings.TrimSpace(string(bytes)), "\n")
|
||||||
|
result.MaxRow = len(lines) - 1
|
||||||
|
result.MaxCol = len(lines[0]) - 1
|
||||||
|
rows := make(map[Coord]CellType)
|
||||||
|
|
||||||
|
for rowNum, row := range lines {
|
||||||
|
for colNum, symb := range row {
|
||||||
|
rows[Coord{Row: rowNum, Col: colNum}] = CellType(symb)
|
||||||
|
if rowNum == 0 && symb == rune(Path) {
|
||||||
|
result.StartCol = colNum
|
||||||
|
}
|
||||||
|
if rowNum == result.MaxRow && symb == rune(Path) {
|
||||||
|
result.EndCol = colNum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.Cells = rows
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package day23
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestReadField(t *testing.T) {
|
||||||
|
filename := "example"
|
||||||
|
field := ReadField(filename)
|
||||||
|
t.Log(field.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStartNeighbors(t *testing.T) {
|
||||||
|
filename := "example"
|
||||||
|
field := ReadField(filename)
|
||||||
|
startNeighbors := field.Neighbors(Coord{Row: 0, Col: field.StartCol})
|
||||||
|
t.Log(startNeighbors)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5,3
|
||||||
|
func TestForkNeighbors(t *testing.T) {
|
||||||
|
filename := "example"
|
||||||
|
field := ReadField(filename)
|
||||||
|
startNeighbors := field.Neighbors(Coord{Row: 5, Col: 3})
|
||||||
|
t.Log(startNeighbors)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSlideNeighbors(t *testing.T) {
|
||||||
|
filename := "example"
|
||||||
|
field := ReadField(filename)
|
||||||
|
startNeighbors := field.Neighbors(Coord{Row: 6, Col: 3})
|
||||||
|
t.Log(startNeighbors)
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package day23
|
||||||
|
|
||||||
|
import (
|
||||||
|
mapset "github.com/deckarep/golang-set/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PathEnd struct {
|
||||||
|
end Coord
|
||||||
|
visited mapset.Set[Coord]
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExtendPath(p PathEnd, f Field) (nextPaths []PathEnd) {
|
||||||
|
endPointNeighbors := f.Neighbors(p.end)
|
||||||
|
for _, potentialNewEnd := range endPointNeighbors {
|
||||||
|
if !p.visited.Contains(potentialNewEnd) {
|
||||||
|
nextVisited := p.visited.Clone()
|
||||||
|
nextVisited.Add(p.end)
|
||||||
|
nextPaths = append(nextPaths, PathEnd{
|
||||||
|
end: potentialNewEnd,
|
||||||
|
visited: nextVisited,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
result = append(result, curCheckedPath)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
nextSteps := ExtendPath(curCheckedPath, f)
|
||||||
|
|
||||||
|
// log.Printf("for %+v next steps %+v\n", curCheckedPath, pathsToFurther)
|
||||||
|
// log.Printf("remaining paths to check len is %d", len(pathsToFurther))
|
||||||
|
// log.Println(pathsToFurther)
|
||||||
|
|
||||||
|
if len(nextSteps) > 0 {
|
||||||
|
pathsToFurther = append(pathsToFurther, nextSteps...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package day23
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestRunAllPaths(t *testing.T) {
|
||||||
|
filename := "example"
|
||||||
|
field := ReadField(filename)
|
||||||
|
finalPaths := RunAllScenicPaths(field)
|
||||||
|
t.Log(finalPaths)
|
||||||
|
|
||||||
|
max := 0
|
||||||
|
for _, path := range finalPaths {
|
||||||
|
if path.visited.Cardinality() > max {
|
||||||
|
max = path.visited.Cardinality()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Logf("max path len is %d", max)
|
||||||
|
|
||||||
|
}
|
6
main.go
6
main.go
|
@ -4,15 +4,15 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"sunshine.industries/aoc2023/day22"
|
"sunshine.industries/aoc2023/day23"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
log.Print("> starting run:")
|
log.Print("> starting run:")
|
||||||
|
|
||||||
result := day22.Run()
|
result := day23.Run()
|
||||||
log.Printf("\n\nday22 result: %d\n****\n", result)
|
log.Printf("\n\nday23 result: %d\n****\n", result)
|
||||||
endTime := time.Now()
|
endTime := time.Now()
|
||||||
diff := endTime.Sub(startTime)
|
diff := endTime.Sub(startTime)
|
||||||
log.Printf("execution took %s", diff.String())
|
log.Printf("execution took %s", diff.String())
|
||||||
|
|
Loading…
Reference in New Issue