162 lines
3.0 KiB
Go
162 lines
3.0 KiB
Go
package day_06
|
|
|
|
import (
|
|
"strings"
|
|
)
|
|
|
|
type Direction int
|
|
|
|
const (
|
|
UP Direction = iota
|
|
RIGHT Direction = iota
|
|
DOWN Direction = iota
|
|
LEFT Direction = iota
|
|
)
|
|
|
|
const (
|
|
VISITED = 'X'
|
|
OCCUPIED = '#'
|
|
FREE = '.'
|
|
)
|
|
|
|
var toDirections = map[rune]Direction{
|
|
'^': UP,
|
|
'>': RIGHT,
|
|
'v': DOWN,
|
|
'<': LEFT,
|
|
}
|
|
|
|
var fromDirections = map[Direction]rune{
|
|
UP: '^',
|
|
RIGHT: '>',
|
|
DOWN: 'v',
|
|
LEFT: '<',
|
|
}
|
|
|
|
// task:https://adventofcode.com/2024/day/5
|
|
// short summary - count visited steps
|
|
func SolveBasic(input string) int {
|
|
grid := visitationGrid(input)
|
|
|
|
sum := 0
|
|
for _, row := range grid {
|
|
for _, value := range row {
|
|
if value == VISITED {
|
|
sum++
|
|
}
|
|
}
|
|
}
|
|
return sum
|
|
}
|
|
|
|
// task:https://adventofcode.com/2024/day/5#part2
|
|
// short summary - find all position that will create an infinite loop
|
|
func SolveComplex(input string) int {
|
|
grid := visitationGrid(input)
|
|
|
|
dirGrid := loadGrid(input)
|
|
startX, startY, startDir := findPlayer(dirGrid)
|
|
dirGrid[startY][startX] = FREE
|
|
|
|
positions := 0
|
|
|
|
for y, row := range grid {
|
|
for x, value := range row {
|
|
if value == VISITED && dirGrid[y][x] == FREE {
|
|
dirGrid[y][x] = OCCUPIED
|
|
|
|
curX := startX
|
|
curY := startY
|
|
curDir := startDir
|
|
|
|
for inGrid(dirGrid, curX, curY) {
|
|
if dirGrid[curY][curX] == fromDirections[curDir] {
|
|
// we visited a same point second time in the same direction
|
|
// which means we are in an infinite list
|
|
positions++
|
|
break
|
|
}
|
|
dirGrid[curY][curX] = fromDirections[curDir]
|
|
curX, curY, curDir = nextSpot(dirGrid, curX, curY, curDir)
|
|
|
|
}
|
|
dirGrid[y][x] = FREE
|
|
clearDirGrid(dirGrid)
|
|
}
|
|
}
|
|
}
|
|
return positions
|
|
}
|
|
|
|
func clearDirGrid(grid [][]rune) {
|
|
for y, row := range grid {
|
|
for x, value := range row {
|
|
if value != OCCUPIED {
|
|
grid[y][x] = FREE
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func nextSpot(grid [][]rune, x int, y int, dir Direction) (int, int, Direction) {
|
|
for {
|
|
nx, ny := calculateNext(x, y, dir)
|
|
if !inGrid(grid, nx, ny) {
|
|
return nx, ny, dir
|
|
} else if grid[ny][nx] != OCCUPIED {
|
|
return nx, ny, dir
|
|
} else {
|
|
dir = (dir + 1) % 4
|
|
}
|
|
}
|
|
}
|
|
|
|
func calculateNext(x int, y int, dir Direction) (int, int) {
|
|
switch dir {
|
|
case UP:
|
|
return x, y - 1
|
|
case RIGHT:
|
|
return x + 1, y
|
|
case DOWN:
|
|
return x, y + 1
|
|
case LEFT:
|
|
return x - 1, y
|
|
}
|
|
panic("unknown direction")
|
|
}
|
|
|
|
func inGrid(grid [][]rune, x int, y int) bool {
|
|
return x >= 0 && y >= 0 && x < len(grid[0]) && y < len(grid)
|
|
}
|
|
|
|
func findPlayer(grid [][]rune) (int, int, Direction) {
|
|
for y, row := range grid {
|
|
for x, value := range row {
|
|
if dir, present := toDirections[value]; present {
|
|
return x, y, dir
|
|
}
|
|
}
|
|
}
|
|
panic("Couldn't find player")
|
|
}
|
|
|
|
func loadGrid(input string) [][]rune {
|
|
substrings := strings.Split(input, "\n")
|
|
var grid [][]rune
|
|
for _, line := range substrings {
|
|
grid = append(grid, []rune(line))
|
|
}
|
|
return grid
|
|
}
|
|
|
|
func visitationGrid(input string) [][]rune {
|
|
grid := loadGrid(input)
|
|
x, y, dir := findPlayer(grid)
|
|
|
|
for inGrid(grid, x, y) {
|
|
grid[y][x] = VISITED
|
|
x, y, dir = nextSpot(grid, x, y, dir)
|
|
}
|
|
return grid
|
|
}
|