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