Skip to content

Commit

Permalink
day 16 part 1 solution, wip part 2
Browse files Browse the repository at this point in the history
  • Loading branch information
aleche28 committed Dec 16, 2024
1 parent 8166e48 commit 0477362
Show file tree
Hide file tree
Showing 5 changed files with 263 additions and 174 deletions.
Binary file added solutions/alessio/day16/aoc16
Binary file not shown.
236 changes: 107 additions & 129 deletions solutions/alessio/day16/day16.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,105 +35,28 @@ func findStartAndEndPos(grid []string, rows int, cols int) (Pos, Pos) {
return start, end
}

func printGrid(grid []string, rows int, cols int, currPos Pos) {
for r := 0; r < rows; r++ {
for c := 0; c < cols; c++ {
if r == currPos.r && c == currPos.c {
fmt.Print("@")
} else {
fmt.Printf("%c", grid[r][c])
}
}
fmt.Println()
}
fmt.Println()
}

func nextDirs(curr Pos) []Pos {
func turnDirs(curr Pos) []Pos {
left := Pos{-curr.c, curr.r}
right := Pos{curr.c, -curr.r}
return []Pos{left, right}
}

var dirs []Pos = []Pos{{0, 1}, {0, -1}, {1, 0}, {-1, 0}} // E, W, S, N

func checkInBounds(pos Pos, rows int, cols int) bool {
return pos.r >= 0 && pos.r < rows && pos.c >= 0 && pos.c < cols
}

type PosDir struct {
pos, dir Pos
}

func getDirSym(dir Pos) byte {
if dir == dirs[0] {
return '>'
} else if dir == dirs[1] {
return '<'
} else if dir == dirs[2] {
return 'v'
} else {
return '^'
}
}

func printPath(grid []string, path []PosDir) {
pathmap := make(map[Pos]Pos)
for _, p := range path {
if _, exists := pathmap[p.pos]; exists {
fmt.Println("path is not unique")
}
pathmap[p.pos] = p.dir
}
rows, cols := len(grid), len(grid[0])
for r := 0; r < rows; r++ {
for c := 0; c < cols; c++ {
if dir, exists := pathmap[Pos{r, c}]; exists {
fmt.Printf("%c", getDirSym(dir))
} else {
fmt.Printf("%c", grid[r][c])
}
}
fmt.Println()
}
fmt.Println()
}
func isIntersection(grid []string, pos Pos) bool {
e := grid[pos.r+dirs[0].r][pos.c+dirs[0].c]
w := grid[pos.r+dirs[1].r][pos.c+dirs[1].c]
s := grid[pos.r+dirs[2].r][pos.c+dirs[2].c]
n := grid[pos.r+dirs[3].r][pos.c+dirs[3].c]

func findPathRec(grid []string, currPos Pos, currDir Pos, currScore int, currMin *int, visited *map[Pos]bool, path []PosDir) {
if grid[currPos.r][currPos.c] == '#' {
return
}
if grid[currPos.r][currPos.c] == 'E' { // reached end of path
if currScore < *currMin {
fmt.Printf("path with score %d\n", currScore)
// printPath(grid, path)
*currMin = currScore
}
return
}
(*visited)[currPos] = true
// go along currDir
nextPos := Pos{currPos.r + currDir.r, currPos.c + currDir.c}
if !(*visited)[nextPos] && currScore+1 < *currMin {
findPathRec(grid, nextPos, currDir, currScore+1, currMin, visited, append(path, PosDir{currPos, currDir}))
}
// turn clockwise and counter-clockwise
for _, dir := range nextDirs(currDir) {
nextPos = Pos{currPos.r + dir.r, currPos.c + dir.c}
if !(*visited)[nextPos] && currScore+1001 < *currMin {
findPathRec(grid, nextPos, dir, currScore+1001, currMin, visited, append(path, PosDir{currPos, dir}))
}
if (n != '#' || s != '#') && (e != '#' || w != '#') {
return true
}
(*visited)[currPos] = false // backtrack
}

func isIntersection(grid []string, pos Pos, currDir Pos) bool {
for _, dir := range nextDirs(currDir) {
next := Pos{pos.r + dir.r, pos.c + dir.c}
if grid[next.r][next.c] == '.' {
return true
}
}
return false
}

Expand All @@ -151,68 +74,123 @@ func printMazeWithNodes(grid []string, rows int, cols int, graph *graph.Graph[Po
fmt.Println()
}

func buildGraphRec(grid []string, currPos Pos, currDir Pos, lastNode Pos, currWeight int, graph *graph.Graph[Pos]) {
if grid[currPos.r][currPos.c] == '#' {
return
func addGraphEdgesIter(grid []string, start Pos, graph *graph.Graph[Pos]) {
queue := []PosDir{{start, dirs[0]}}
visited := make(map[PosDir]bool)

if grid[start.r-1][start.c] != '#' {
queue = append(queue, PosDir{start, dirs[3]})
}

visited := false
if isIntersection(grid, currPos, currDir) {
visited = graph.HasNode(currPos)
if !visited {
graph.AddNode(currPos)
}
if currPos != lastNode {
graph.AddEdge(lastNode, currPos, currWeight)
}
if grid[currPos.r][currPos.c] == 'E' {
return
if grid[start.r+1][start.c] != '#' {
queue = append(queue, PosDir{start, dirs[2]})
}

for len(queue) > 0 {
curr := queue[0]
queue = queue[1:]
if visited[curr] {
continue
}
if !visited || grid[currPos.r][currPos.c] == 'S' { // if already visited, no sense recurring on it.
// restart counting from this node
// turn clockwise and counter-clockwise
for _, dir := range nextDirs(currDir) {
nextPos := Pos{currPos.r + dir.r, currPos.c + dir.c}
// lastNode = currPos and weight = 1001 (restart counting from this node)
buildGraphRec(grid, nextPos, dir, currPos, 1001, graph)
visited[curr] = true
nextPos := Pos{curr.pos.r + curr.dir.r, curr.pos.c + curr.dir.c}
dist := 0
for grid[nextPos.r][nextPos.c] != '#' {
dist++
if isIntersection(grid, nextPos) || grid[nextPos.r][nextPos.c] == 'E' {
if !graph.HasEdge(curr.pos, nextPos) {
graph.AddEdge(curr.pos, nextPos, dist, curr.dir)
}
for _, dir := range turnDirs(curr.dir) {
if !visited[PosDir{nextPos, dir}] {
queue = append(queue, PosDir{nextPos, dir})
}
}
queue = append(queue, PosDir{nextPos, curr.dir})
break
}
nextPos.r += curr.dir.r
nextPos.c += curr.dir.c
}
}

// go along currDir
nextPos := Pos{currPos.r + currDir.r, currPos.c + currDir.c}
buildGraphRec(grid, nextPos, currDir, lastNode, currWeight+1, graph)
}

func getGraph(grid []string, rows int, cols int) *graph.Graph[Pos] {
func addGraphNodes(g *graph.Graph[Pos], grid []string, rows int, cols int) {
for r := 1; r < rows-1; r++ {
for c := 1; c < cols-1; c++ {
if grid[r][c] != '#' && (isIntersection(grid, Pos{r, c}) || grid[r][c] == 'E' || grid[r][c] == 'S') {
g.AddNode(Pos{r, c})
}
}
}
}
func getGraph(grid []string, rows int, cols int) (*graph.Graph[Pos], Pos, Pos) {
g := graph.Graph[Pos]{}
g.Init(rows*cols, rows*cols)
start, end := findStartAndEndPos(grid, rows, cols)
g.AddNode(start)
g.AddNode(end)
buildGraphRec(grid, start, dirs[0], start, 0, &g)
return &g
addGraphNodes(&g, grid, rows, cols)
addGraphEdgesIter(grid, start, &g)
return &g, start, end
}

func solve1(grid []string) {
rows, cols := len(grid), len(grid[0])
g := getGraph(grid, rows, cols)
printMazeWithNodes(grid, rows, cols, g)
// fmt.Println(g.Nodes)

fmt.Println(g.AdjList)
// currPos, endPos := findStartAndEndPos(grid, rows, cols)
// fmt.Println(currPos, endPos)
// currDir := dirs[0] // start facing east
g, start, end := getGraph(grid, rows, cols)
// printMazeWithNodes(grid, rows, cols, g)
fmt.Println(g.ShortestPath(start, end, dirs[0]))
}

// currMin := math.MaxInt
// visited := make(map[Pos]bool)
// findPathRec(grid, currPos, currDir, 0, &currMin, &visited, []PosDir{})
// fmt.Println(currMin)
func abs(x int) int {
if x >= 0 {
return x
}
return -x
}

func getDir(from Pos, to Pos) Pos {
diffR := to.r - from.r
diffC := to.c - from.c
if diffR == 0 {
dirC := diffC / abs(diffC)
return Pos{0, dirC}
} else if diffC == 0 {
dirR := diffR / abs(diffR)
return Pos{dirR, 0}
} else {
fmt.Println("wtf")
return Pos{0, 0}
}
}

func solve2(origGrid []string) {
func solve2(grid []string) {
rows, cols := len(grid), len(grid[0])
g, start, end := getGraph(grid, rows, cols)
edges := g.GetFullPathsEdges(start, end, dirs[0])

tiles := map[Pos]bool{}
for _, e := range edges {
dir := getDir(e.From, e.To.Val)
curr := Pos{e.From.r, e.From.c}
for curr.r != e.To.Val.r || curr.c != e.To.Val.c {
tiles[curr] = true
curr.r += dir.r
curr.c += dir.c
}
tiles[curr] = true
}

// for r := 0; r < rows; r++ {
// for c := 0; c < cols; c++ {
// if tiles[Pos{r, c}] {
// fmt.Print("O")
// } else {
// fmt.Printf("%c", grid[r][c])
// }
// }
// fmt.Println()
// }
// fmt.Println()
fmt.Println(len(tiles))
}

func part1(grid []string) {
Expand All @@ -224,7 +202,7 @@ func part2(grid []string) {
}

func main() {
data, err := os.ReadFile("./input16.txt")
data, err := os.ReadFile("./input16_def.txt")
check(err)
dataStr := strings.ReplaceAll(string(data), "\r\n", "\n")
lines := strings.Split(strings.Trim(dataStr, "\n"), "\n")
Expand Down
Loading

0 comments on commit 0477362

Please sign in to comment.