154 lines
2.6 KiB
Go
154 lines
2.6 KiB
Go
package day9
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
)
|
|
|
|
type Point struct {
|
|
x int
|
|
y int
|
|
}
|
|
|
|
func makeSnake(length int) []*Point {
|
|
snake := []*Point{}
|
|
|
|
for i := 0; i < length; i++ {
|
|
snake = append(snake, &Point{0, 0})
|
|
}
|
|
|
|
return snake
|
|
}
|
|
|
|
func move(direction rune, point *Point) {
|
|
switch direction {
|
|
case 'U':
|
|
point.y -= 1
|
|
case 'R':
|
|
point.x += 1
|
|
case 'D':
|
|
point.y += 1
|
|
case 'L':
|
|
point.x -= 1
|
|
default:
|
|
fmt.Println("PANIC! Bad direction", string(direction))
|
|
}
|
|
}
|
|
|
|
func abs(x int) int {
|
|
if x >= 0 {
|
|
return x
|
|
} else {
|
|
return -x
|
|
}
|
|
}
|
|
|
|
func areTouching(head *Point, tail *Point) bool {
|
|
return abs(head.x-tail.x) <= 1 && abs(head.y-tail.y) <= 1
|
|
}
|
|
|
|
func updateTail(head *Point, tail *Point) {
|
|
if areTouching(head, tail) {
|
|
return
|
|
}
|
|
|
|
if head.x == tail.x {
|
|
if head.y <= tail.y-2 {
|
|
tail.y -= 1
|
|
return
|
|
}
|
|
|
|
if head.y >= tail.y+2 {
|
|
tail.y += 1
|
|
return
|
|
}
|
|
}
|
|
|
|
if head.y == tail.y {
|
|
if head.x <= tail.x-2 {
|
|
tail.x -= 1
|
|
return
|
|
}
|
|
if head.x >= tail.x+2 {
|
|
tail.x += 1
|
|
return
|
|
}
|
|
}
|
|
|
|
proposedTails := []Point{
|
|
{tail.x - 1, tail.y - 1},
|
|
{tail.x - 1, tail.y + 1},
|
|
{tail.x + 1, tail.y - 1},
|
|
{tail.x + 1, tail.y + 1}}
|
|
|
|
for _, proposed := range proposedTails {
|
|
if areTouching(head, &proposed) {
|
|
tail.x = proposed.x
|
|
tail.y = proposed.y
|
|
return
|
|
}
|
|
}
|
|
|
|
fmt.Println("PANIC, couldn't figure out next step for", *head, "and", *tail)
|
|
}
|
|
|
|
func contains(array *[]Point, point Point) bool {
|
|
for _, val := range *array {
|
|
if val == point {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func runMove(direction rune, amount int, snake []*Point, visitedPoints *[]Point) {
|
|
for i := 0; i < amount; i++ {
|
|
move(direction, snake[0])
|
|
for t := 1; t < len(snake); t++ {
|
|
updateTail(snake[t-1], snake[t])
|
|
}
|
|
lastPoint := snake[len(snake)-1]
|
|
if !contains(visitedPoints, *lastPoint) {
|
|
*visitedPoints = append(*visitedPoints, *lastPoint)
|
|
}
|
|
}
|
|
}
|
|
|
|
func Run(filename string, lengthStr string) {
|
|
file, err := os.Open(filename)
|
|
if err != nil {
|
|
fmt.Println("Error opening file:", err)
|
|
return
|
|
}
|
|
|
|
snakeLength, err := strconv.Atoi(lengthStr)
|
|
if err != nil {
|
|
fmt.Println("Error parsing snake length:", err)
|
|
return
|
|
}
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
scanner.Split(bufio.ScanLines)
|
|
|
|
snake := makeSnake(snakeLength)
|
|
visitedPoints := []Point{}
|
|
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
|
|
amount, err := strconv.Atoi(line[2:])
|
|
if err != nil {
|
|
fmt.Println("Could not parse argument", line)
|
|
return
|
|
}
|
|
|
|
runMove(rune(line[0]), amount, snake, &visitedPoints)
|
|
}
|
|
|
|
fmt.Println("The tail visited", len(visitedPoints), "points")
|
|
|
|
file.Close()
|
|
}
|