adventOfCode/internal/2022/day_09/in.go

236 lines
5.8 KiB
Go
Raw Normal View History

2022-12-06 21:10:52 +00:00
package day_09
2022-12-10 09:12:29 +00:00
import (
"fmt"
"strconv"
"strings"
)
type Day struct {
board [][]bool
curHead Position
curTail Position
// Part two extras
tails []Position
}
type Position struct {
row int
column int
}
2022-12-06 21:10:52 +00:00
func (d *Day) Part1(in string) string {
2022-12-10 09:12:29 +00:00
// Create initial board
initialSize := 2000
d.board = make([][]bool, initialSize)
for i := range d.board {
d.board[i] = make([]bool, initialSize)
}
// Initialize positions
d.curHead.row = initialSize / 2
d.curHead.column = initialSize / 2
d.curTail.row = initialSize / 2
d.curTail.column = initialSize / 2
d.board[initialSize/2][initialSize/2] = true
for _, val := range strings.Split(in, "\n") {
if val == "" {
continue
}
pos := val[0:1]
mov, _ := strconv.Atoi(val[2:])
//fmt.Printf("Moving for %d in %s\n", mov, pos)
for i := 0; i < mov; i++ {
d.Move(pos)
}
}
// Count positions
sum := 0
for _, val := range d.board {
for _, wasOn := range val {
if wasOn {
sum++
}
}
}
return fmt.Sprintf("%d", sum)
}
// Left or right or Up and Down
func (d *Day) Move(direction string) {
origHead := d.curHead
if direction == "L" {
d.curHead.column--
} else if direction == "R" {
d.curHead.column++
} else if direction == "U" {
d.curHead.row--
} else if direction == "D" {
d.curHead.row++
}
//fmt.Printf("Head: %s | Tail: %s\n", d.curHead, d.curTail)
// Check if tail should move
if d.isTailOnlyOneAway() || d.isDiagonally() || (d.curHead.row == d.curTail.row && d.curHead.column == d.curTail.column) {
// The Head is already on the way :)
} else {
d.curTail = origHead
// Update positions
d.board[d.curTail.row][d.curTail.column] = true
}
//fmt.Printf("Head: %s | Tail: %s\n", d.curHead, d.curTail)
}
func (d *Day) isTailOnlyOneAway() bool {
return (d.curHead.column == d.curTail.column && isOnlyOneAway(d.curHead.row, d.curTail.row)) ||
(d.curHead.row == d.curTail.row && isOnlyOneAway(d.curHead.column, d.curTail.column))
}
func isOnlyOneAway(one int, two int) bool {
//fmt.Printf("Comparing: %d %d %t %t\n", one, two, (one-1) == two, (one+1) == two)
return (one-1) == two || (one+1) == two
}
func (d *Day) isDiagonally() bool {
topRight := d.curHead.row-1 == d.curTail.row && d.curHead.column-1 == d.curTail.column
topLeft := d.curHead.row-1 == d.curTail.row && d.curHead.column+1 == d.curTail.column
bottomRight := d.curHead.row+1 == d.curTail.row && d.curHead.column-1 == d.curTail.column
bottomLeft := d.curHead.row+1 == d.curTail.row && d.curHead.column+1 == d.curTail.column
return topRight || topLeft || bottomLeft || bottomRight
2022-12-06 21:10:52 +00:00
}
func (d *Day) Part2(in string) string {
2022-12-10 09:12:29 +00:00
// Create initial board
initialSize := 2000
d.board = make([][]bool, initialSize)
for i := range d.board {
d.board[i] = make([]bool, initialSize)
}
// Initialize positions
d.curHead.row = initialSize / 2
d.curHead.column = initialSize / 2
d.tails = make([]Position, 10)
for i := 0; i < 10; i++ {
d.tails[i].row = initialSize / 2
d.tails[i].column = initialSize / 2
}
d.board[initialSize/2][initialSize/2] = true
for _, val := range strings.Split(in, "\n") {
if val == "" {
continue
}
pos := val[0:1]
mov, _ := strconv.Atoi(val[2:])
//fmt.Printf("Moving for %d in %s\n", mov, pos)
for i := 0; i < mov; i++ {
d.Move2(pos)
}
}
// Count positions
sum := 0
for _, val := range d.board {
for _, wasOn := range val {
if wasOn {
sum++
}
}
}
return fmt.Sprintf("%d", sum)
}
// Left or right or Up and Down
func (d *Day) Move2(direction string) {
//origHead := d.curHead
if direction == "L" {
d.curHead.column--
} else if direction == "R" {
d.curHead.column++
} else if direction == "U" {
d.curHead.row++
} else if direction == "D" {
d.curHead.row--
}
for i := 0; i < 9; i++ {
prevHead := d.curHead
if i != 0 {
prevHead = d.tails[i-1]
}
// Check if tail should moved
if d.isTailOnlyOneAway2(d.tails[i], prevHead) || d.isDiagonally2(d.tails[i], prevHead) || (prevHead.row == d.tails[i].row && prevHead.column == d.tails[i].column) {
// Not moving
} else {
// Up and Down
if direction == "U" || direction == "D" {
if d.tails[i].row < prevHead.row {
d.tails[i].row++
}
if d.tails[i].row > prevHead.row {
d.tails[i].row--
}
// left or right?
if d.tails[i].column < prevHead.column {
d.tails[i].column++
} else if d.tails[i].column > prevHead.column {
d.tails[i].column--
}
// Left and Right
} else if direction == "L" || direction == "R" {
if d.tails[i].column > prevHead.column {
d.tails[i].column--
}
if d.tails[i].column < prevHead.column {
d.tails[i].column++
}
// Up or down
if d.tails[i].row < prevHead.row {
d.tails[i].row++
} else if d.tails[i].row > prevHead.row {
d.tails[i].row--
}
}
}
if i == 8 {
d.board[d.tails[i].row][d.tails[i].column] = true
}
//fmt.Printf("%d: Head: %s | Tail: %s\n", i+1, prevHead, d.tails[i])
}
//fmt.Printf("Head: %s | Tail: %s\n", d.curHead, d.curTail)
}
func (d *Day) isTailOnlyOneAway2(tail Position, prevTail Position) bool {
return (prevTail.column == tail.column && isOnlyOneAway2(prevTail.row, tail.row)) ||
(prevTail.row == tail.row && isOnlyOneAway2(prevTail.column, tail.column))
}
func isOnlyOneAway2(one int, two int) bool {
//fmt.Printf("Comparing: %d %d %t %t\n", one, two, (one-1) == two, (one+1) == two)
return (one-1) == two || (one+1) == two
}
func (d *Day) isDiagonally2(tail Position, prevTail Position) bool {
topRight := prevTail.row-1 == tail.row && prevTail.column-1 == tail.column
topLeft := prevTail.row-1 == tail.row && prevTail.column+1 == tail.column
bottomRight := prevTail.row+1 == tail.row && prevTail.column-1 == tail.column
bottomLeft := prevTail.row+1 == tail.row && prevTail.column+1 == tail.column
return topRight || topLeft || bottomLeft || bottomRight
2022-12-06 21:10:52 +00:00
}