Skip to content

Commit 21947fe

Browse files
committed
1407 with part 2
1 parent daf5859 commit 21947fe

File tree

1 file changed

+181
-0
lines changed

1 file changed

+181
-0
lines changed

6/main_2.go

+181
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"strings"
7+
)
8+
9+
var dirCoords = map[string][]int{
10+
"^": []int{-1, 0},
11+
"v": []int{1, 0},
12+
">": []int{0, 1},
13+
"<": []int{0, -1},
14+
}
15+
16+
var nextDirs = map[string]string{
17+
"^": ">",
18+
"v": "<",
19+
">": "v",
20+
"<": "^",
21+
}
22+
23+
func copyGrid(grid [][]string) [][]string {
24+
c := [][]string{}
25+
for i := range len(grid) {
26+
row := []string{}
27+
for j := range len(grid[0]) {
28+
row = append(row, grid[i][j])
29+
}
30+
c = append(c, row)
31+
}
32+
return c
33+
}
34+
35+
func emptyVisited(n int) [][]map[string]bool {
36+
out := make([][]map[string]bool, n) // create the outer slice with space for 'rows' inner slices
37+
for i := range n {
38+
out[i] = make([]map[string]bool, n) // create each inner slice with 'cols' elements
39+
for j := range n {
40+
out[i][j] = make(map[string]bool)
41+
}
42+
}
43+
return out
44+
}
45+
46+
func copyVisited(visited [][][]string) [][][]string {
47+
// Create a new slice with the same length as the original
48+
copied := make([][][]string, len(visited))
49+
50+
for i, subArray := range visited {
51+
// Create a new slice for each 2D sub-array
52+
copied[i] = make([][]string, len(subArray))
53+
54+
for j, innerArray := range subArray {
55+
// Create a new slice for each 1D inner-array
56+
copied[i][j] = make([]string, len(innerArray))
57+
58+
// Copy the strings from the original inner-array
59+
copy(copied[i][j], innerArray)
60+
}
61+
}
62+
63+
return copied
64+
}
65+
66+
// updates grid in place by moving the arrow one step, updates visited in place with position at start of step
67+
// returns r, c, bool where bool indicates out of bounds if were to take a step, ie you are on the very edge
68+
func step(r, c int, gridPtr *[][]string, visited *[][]map[string]bool) (int, int, bool) {
69+
grid := *gridPtr
70+
curDir := grid[r][c]
71+
// update visited
72+
(*visited)[r][c][curDir] = true
73+
dirCoord := dirCoords[curDir]
74+
nextR, nextC := r+dirCoord[0], c+dirCoord[1]
75+
nextInBound := nextR >= 0 && nextR < len(grid) && nextC >= 0 && nextC < len(grid[0])
76+
if !nextInBound {
77+
return r, c, true
78+
}
79+
// check for turn
80+
if grid[nextR][nextC] == "#" {
81+
// stay in place and turn
82+
turnedDir := nextDirs[curDir]
83+
grid[r][c] = turnedDir
84+
// since turned have to check if next step out of bounds
85+
dirCoord = dirCoords[turnedDir]
86+
nextR, nextC = r+dirCoord[0], c+dirCoord[1]
87+
nextInBound = nextR >= 0 && nextR < len(grid) && nextC >= 0 && nextC < len(grid[0])
88+
if !nextInBound {
89+
return r, c, true
90+
}
91+
return r, c, false
92+
}
93+
// step in current direction
94+
grid[r][c] = "."
95+
grid[nextR][nextC] = curDir
96+
97+
return nextR, nextC, false
98+
}
99+
100+
// takes in a grid with a start location. traverses the grid till it exits or get in a loop.
101+
// returns true if has a loop
102+
func traverse(r, c int, origGrid [][]string) (hasLoop bool) {
103+
grid := copyGrid(origGrid)
104+
visited := emptyVisited(len(origGrid))
105+
for {
106+
done := false
107+
r, c, done = step(r, c, &grid, &visited)
108+
if done {
109+
return false
110+
}
111+
112+
curDir := grid[r][c]
113+
looped := visited[r][c][curDir]
114+
if looped {
115+
return true
116+
}
117+
}
118+
//r >= 0 && r < len(grid) && c >= 0 && c < len(grid[0])
119+
}
120+
121+
func part2() {
122+
raw, _ := os.ReadFile("input.txt")
123+
//raw, _ := os.ReadFile("test.txt")
124+
data := string(raw)
125+
126+
grid := [][]string{}
127+
for _, row := range strings.Split(data, "\n") {
128+
grid = append(grid, strings.Split(row, ""))
129+
}
130+
131+
startR := -1
132+
startC := -1
133+
for i := range len(grid) {
134+
for j := range len(grid[0]) {
135+
// find start
136+
if grid[i][j] == "^" {
137+
startR = i
138+
startC = j
139+
break
140+
}
141+
}
142+
}
143+
144+
count := 0
145+
// visited doesn't matter, we don't check it here
146+
visited := emptyVisited(len(grid))
147+
gridCopy := copyGrid(grid)
148+
r := startR
149+
c := startC
150+
for {
151+
done := false
152+
r, c, done = step(r, c, &gridCopy, &visited)
153+
if done {
154+
fmt.Println(count)
155+
return
156+
}
157+
158+
// imagine there is an obstacle in front of us
159+
withObstacle := copyGrid(gridCopy)
160+
curDir := withObstacle[r][c]
161+
// place obstacle, we know one can exist there since done is false
162+
dirCoord := dirCoords[curDir]
163+
obstacleR, obstacleC := r+dirCoord[0], c+dirCoord[1]
164+
nextInBound := obstacleR >= 0 && obstacleR < len(grid) && obstacleC >= 0 && obstacleC < len(grid[0])
165+
if !nextInBound {
166+
fmt.Println(count)
167+
return
168+
}
169+
withObstacle[obstacleR][obstacleC] = "#"
170+
171+
hasLoop := traverse(r, c, withObstacle)
172+
if hasLoop {
173+
count += 1
174+
}
175+
}
176+
}
177+
178+
func main() {
179+
//part1()
180+
part2()
181+
}

0 commit comments

Comments
 (0)