diff options
Diffstat (limited to 'day6/main.go')
-rw-r--r-- | day6/main.go | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/day6/main.go b/day6/main.go new file mode 100644 index 0000000..6461c20 --- /dev/null +++ b/day6/main.go @@ -0,0 +1,196 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "slices" + "strings" +) + +func main() { + fmt.Println(part1(readData("example.txt"))) + fmt.Println(part1(readData("data.txt"))) + fmt.Println(part2(readData("example.txt"))) + fmt.Println(part2(readData("data.txt"))) +} + +func part1(tiles [][]byte, x, y int) (visited int) { + directions := [4][2]int{ + {0, -1}, + {1, 0}, + {0, 1}, + {-1, 0}, + } + + dir := 0 + dx := directions[dir][0] + dy := directions[dir][1] + + for { + if tiles[y][x] != 'X' { + tiles[y][x] = 'X' + visited++ + } + + if y+dy < 0 || y+dy >= len(tiles) { + return + } + + if x+dx < 0 || x+dx >= len(tiles[y+dy]) { + return + } + + if tiles[y+dy][x+dx] == '#' { + dir = (dir + 1) % 4 + dx = directions[dir][0] + dy = directions[dir][1] + } else { + x += dx + y += dy + } + } +} + +type State struct { + x, y int + dir int +} + +func (state *State) GetDirection() (dx, dy int) { + directions := [4][2]int{ + {0, -1}, + {1, 0}, + {0, 1}, + {-1, 0}, + } + dx = directions[state.dir][0] + dy = directions[state.dir][1] + return +} + +func (state *State) GetNextPosition() (x, y int) { + dx, dy := state.GetDirection() + x = state.x + dx + y = state.y + dy + return +} + +func (state *State) IsAboutToExit(tiles [][]byte) bool { + x, y := state.GetNextPosition() + if y < 0 || y >= len(tiles) { + return true + } + if x < 0 || x >= len(tiles[y]) { + return true + } + return false +} + +func (state *State) HasObstacleInFront(tiles [][]byte) bool { + x, y := state.GetNextPosition() + return tiles[y][x] == '#' +} + +func (state *State) Clone() State { + return State{ + state.x, state.y, state.dir, + } +} + +func (state *State) Rotate() { + state.dir = (state.dir + 1) % 4 +} + +func copyVisited(visited [][]byte) (visitedCopy [][]byte) { + visitedCopy = make([][]byte, len(visited)) + for i, sublist := range visited { + visitedCopy[i] = make([]byte, len(sublist)) + copy(visitedCopy[i], sublist) + } + return +} + +func canReachExit(tiles [][]byte, visited [][]byte, state State) bool { + for !state.IsAboutToExit(tiles) { + visitedBit := byte(1) << state.dir + if visited[state.y][state.x]&visitedBit != 0 { + return false + } + visited[state.y][state.x] |= visitedBit + + if state.HasObstacleInFront(tiles) { + state.Rotate() + continue + } + + nextX, nextY := state.GetNextPosition() + state.x = nextX + state.y = nextY + } + return true +} + +func part2(tiles [][]byte, startX, startY int) (positionsLooping int) { + state := State{startX, startY, 0} + + visited := make([][]byte, len(tiles)) + for i := range visited { + visited[i] = make([]byte, len(tiles[i])) + } + + for !state.IsAboutToExit(tiles) { + visitedBit := byte(1) << state.dir + if visited[state.y][state.x]&visitedBit != 0 { + panic("Already visited???") + } + visited[state.y][state.x] |= visitedBit + + if state.HasObstacleInFront(tiles) { + state.Rotate() + continue + } + + nextX, nextY := state.GetNextPosition() + if visited[nextY][nextX] == 0 { + tiles[nextY][nextX] = '#' + + stateCopy := state.Clone() + stateCopy.Rotate() + if !canReachExit(tiles, copyVisited(visited), stateCopy) { + positionsLooping++ + } + tiles[nextY][nextX] = '.' + } + + state.x = nextX + state.y = nextY + } + + return +} + +func readData(fileName string) (tiles [][]byte, startX, startY int) { + fp, err := os.Open(fileName) + if err != nil { + panic(err) + } + + scanner := bufio.NewScanner(fp) + + y := 0 + for scanner.Scan() { + line := []byte(strings.TrimSpace(scanner.Text())) + + x := slices.Index(line, '^') + if x != -1 { + startX = x + startY = y + } + + tiles = append(tiles, line) + y += 1 + } + + return +} |