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
 | |
| }
 |