143 lines
2.6 KiB
Go
143 lines
2.6 KiB
Go
package day06
|
|
|
|
import (
|
|
"strings"
|
|
)
|
|
|
|
type Point struct {
|
|
x int
|
|
y int
|
|
direction int
|
|
}
|
|
|
|
const (
|
|
Up = 0
|
|
Right = 1
|
|
Down = 2
|
|
Left = 3
|
|
)
|
|
|
|
var rows, cols int
|
|
|
|
var moves = []Point{
|
|
{-1, 0, Up},
|
|
{0, 1, Up},
|
|
{1, 0, Up},
|
|
{0, -1, Up},
|
|
}
|
|
|
|
func Part1(input string) int {
|
|
grid, start, direction := ParseInput(input)
|
|
total := PredictPath(grid, start, direction)
|
|
return total
|
|
}
|
|
|
|
func Part2(input string) int {
|
|
grid, start, direction := ParseInput(input)
|
|
total := FindLoopingPositions(grid, start, direction)
|
|
return total
|
|
}
|
|
|
|
func ParseInput(input string) ([][]rune, Point, int) {
|
|
lines := strings.Split(strings.TrimSpace(input), "\n")
|
|
rows = len(lines)
|
|
cols = len(lines[0])
|
|
grid := make([][]rune, rows)
|
|
|
|
var start Point
|
|
var direction int
|
|
|
|
for i := 0; i < rows; i++ {
|
|
grid[i] = []rune(lines[i])
|
|
for j, char := range lines[i] {
|
|
if char == '^' {
|
|
start = Point{i, j, Up}
|
|
direction = Up
|
|
} else if char == '>' {
|
|
start = Point{i, j, Right}
|
|
direction = Right
|
|
} else if char == 'v' {
|
|
start = Point{i, j, Down}
|
|
direction = Down
|
|
} else if char == '<' {
|
|
start = Point{i, j, Left}
|
|
direction = Left
|
|
}
|
|
}
|
|
}
|
|
|
|
return grid, start, direction
|
|
}
|
|
|
|
func PredictPath(grid [][]rune, start Point, direction int) int {
|
|
visited := make(map[Point]bool)
|
|
current := start
|
|
|
|
visited[current] = true
|
|
|
|
// do while
|
|
for {
|
|
next := Point{current.x + moves[direction].x, current.y + moves[direction].y, Up}
|
|
|
|
if next.x < 0 || next.x >= rows || next.y < 0 || next.y >= cols {
|
|
break
|
|
}
|
|
|
|
if grid[next.x][next.y] == '#' {
|
|
direction = (direction + 1) % 4
|
|
} else {
|
|
current = next
|
|
visited[current] = true
|
|
}
|
|
}
|
|
|
|
return len(visited)
|
|
}
|
|
|
|
func FindLoopingPositions(grid [][]rune, start Point, direction int) int {
|
|
possiblePositions := 0
|
|
|
|
for i := 0; i < rows; i++ {
|
|
for j := 0; j < cols; j++ {
|
|
if grid[i][j] != '.' || (i == start.x && j == start.y) {
|
|
continue
|
|
}
|
|
|
|
grid[i][j] = '#'
|
|
if IsLooping(grid, start, direction) {
|
|
possiblePositions++
|
|
}
|
|
grid[i][j] = '.'
|
|
}
|
|
}
|
|
|
|
return possiblePositions
|
|
}
|
|
|
|
func IsLooping(grid [][]rune, start Point, direction int) bool {
|
|
visited := make(map[Point]int)
|
|
current := start
|
|
|
|
step := 0
|
|
for {
|
|
step++
|
|
next := Point{current.x + moves[direction].x, current.y + moves[direction].y, direction}
|
|
|
|
if next.x < 0 || next.x >= rows || next.y < 0 || next.y >= cols {
|
|
return false
|
|
}
|
|
|
|
if grid[next.x][next.y] == '#' {
|
|
direction = (direction + 1) % 4
|
|
} else {
|
|
current = next
|
|
|
|
if visitStep, ok := visited[current]; ok && step-visitStep > 4 {
|
|
return true
|
|
}
|
|
|
|
visited[current] = step
|
|
}
|
|
}
|
|
}
|