171 lines
3.8 KiB
Go
171 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
)
|
|
|
|
type Position struct {
|
|
X, Y int
|
|
}
|
|
|
|
var (
|
|
Up = Position{-1, 0}
|
|
Down = Position{1, 0}
|
|
Left = Position{0, -1}
|
|
Right = Position{0, 1}
|
|
)
|
|
|
|
func main() {
|
|
file, err := os.Open("./input.txt")
|
|
if err != nil {
|
|
log.Fatalf("failed to open file: %s\n", err)
|
|
}
|
|
defer file.Close()
|
|
s := bufio.NewScanner(file)
|
|
|
|
var board [][]rune
|
|
|
|
var coveredPositions map[Position]bool
|
|
var guardCurrentPosition Position
|
|
var guardCurrentDirection Position
|
|
|
|
coveredPositions = make(map[Position]bool)
|
|
i := 0
|
|
for s.Scan() {
|
|
var boardLine []rune
|
|
j := 0
|
|
for _, char := range s.Text() {
|
|
boardLine = append(boardLine, char)
|
|
if char == '^' {
|
|
guardCurrentDirection = Up
|
|
}
|
|
if char == '>' {
|
|
guardCurrentDirection = Right
|
|
}
|
|
if char == 'v' {
|
|
guardCurrentDirection = Down
|
|
}
|
|
if char == '<' {
|
|
guardCurrentDirection = Left
|
|
}
|
|
|
|
if char == '#' || char == '.' {
|
|
j++
|
|
continue
|
|
}
|
|
currentPos := Position{i, j}
|
|
guardCurrentPosition = currentPos
|
|
coveredPositions[currentPos] = true
|
|
j++
|
|
}
|
|
board = append(board, boardLine)
|
|
i++
|
|
}
|
|
|
|
solvePart1(board, &coveredPositions, guardCurrentPosition, guardCurrentDirection)
|
|
fmt.Println("result part1:", len(coveredPositions))
|
|
|
|
result2 := 0
|
|
for pos := range coveredPositions {
|
|
if checkBlockWorks(board, pos, guardCurrentPosition, guardCurrentDirection) {
|
|
result2++
|
|
}
|
|
}
|
|
fmt.Println("result part2:", result2)
|
|
}
|
|
|
|
func solvePart1(board [][]rune, coveredPositions *map[Position]bool, guardCurrentPosition Position, guardCurrentDirection Position) {
|
|
for {
|
|
next, err := getNextByDirection(board, guardCurrentPosition, guardCurrentDirection)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if next == '#' || next == 'O' {
|
|
if guardCurrentDirection == Up {
|
|
guardCurrentDirection = Right
|
|
continue
|
|
}
|
|
if guardCurrentDirection == Right {
|
|
guardCurrentDirection = Down
|
|
continue
|
|
}
|
|
if guardCurrentDirection == Down {
|
|
guardCurrentDirection = Left
|
|
continue
|
|
}
|
|
if guardCurrentDirection == Left {
|
|
guardCurrentDirection = Up
|
|
continue
|
|
}
|
|
}
|
|
guardCurrentPosition.X += guardCurrentDirection.X
|
|
guardCurrentPosition.Y += guardCurrentDirection.Y
|
|
(*coveredPositions)[Position{guardCurrentPosition.X, guardCurrentPosition.Y}] = true
|
|
}
|
|
}
|
|
|
|
func checkBlockWorks(board [][]rune, blockPos Position, guardCurrentPosition Position, guardCurrentDirection Position) bool {
|
|
localPos := Position{guardCurrentPosition.X, guardCurrentPosition.Y}
|
|
localDirection := Position{guardCurrentDirection.X, guardCurrentDirection.Y}
|
|
|
|
// this is the starting point
|
|
if (localPos.X == blockPos.X) && (localPos.Y == blockPos.Y) {
|
|
return false
|
|
}
|
|
|
|
var coveredPositions map[Position]int
|
|
coveredPositions = make(map[Position]int)
|
|
|
|
coveredPositions[localPos] = 1
|
|
|
|
for {
|
|
if coveredPositions[Position{localPos.X, localPos.Y}] == 10 {
|
|
return true
|
|
}
|
|
|
|
next, err := getNextByDirection(board, localPos, localDirection)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
nextIsObstacle := (localPos.X+localDirection.X == blockPos.X) && (localPos.Y+localDirection.Y == blockPos.Y)
|
|
|
|
if next == '#' || nextIsObstacle {
|
|
if localDirection == Up {
|
|
localDirection = Right
|
|
continue
|
|
}
|
|
if localDirection == Right {
|
|
localDirection = Down
|
|
continue
|
|
}
|
|
if localDirection == Down {
|
|
localDirection = Left
|
|
continue
|
|
}
|
|
if localDirection == Left {
|
|
localDirection = Up
|
|
continue
|
|
}
|
|
}
|
|
|
|
localPos.X += localDirection.X
|
|
localPos.Y += localDirection.Y
|
|
|
|
coveredPositions[Position{localPos.X, localPos.Y}]++
|
|
}
|
|
}
|
|
|
|
func getNextByDirection(board [][]rune, pos Position, dir Position) (rune, error) {
|
|
newX := pos.X + dir.X
|
|
newY := pos.Y + dir.Y
|
|
|
|
if newX < 0 || newX >= len(board) || newY < 0 || newY >= len(board[0]) {
|
|
return 0, fmt.Errorf("position out of bounds: (%d, %d)", newX, newY)
|
|
}
|
|
|
|
return board[newX][newY], nil
|
|
}
|