aoc24/day15/main.go

195 lines
4.2 KiB
Go
Raw Normal View History

2024-12-16 16:43:57 +00:00
package main
import (
"fmt"
"strings"
"git.mstar.dev/mstar/aoc24/util"
)
type Area struct {
a [][]rune
}
func parseLinesToMap(lines []string) Area {
out := [][]rune{}
for _, line := range lines {
out = append(out, []rune(strings.TrimSpace(line)))
}
return Area{out}
}
func parseInput(in []byte) (Area, []rune) {
tmp := strings.Split(string(in), "\n\n")
return parseLinesToMap(strings.Split(tmp[0], "\n")), []rune(tmp[1])
}
func (area *Area) applyAction(action rune) {
botX := -1
botY := -1
outer:
for iy, line := range area.a {
for ix, char := range line {
if char == '@' {
botX = ix
botY = iy
break outer
}
}
}
area.move(util.Vec2{X: int64(botX), Y: int64(botY)}, action)
}
func (area *Area) move(from util.Vec2, action rune) bool {
switch action {
case '<':
return area.moveLeft(from)
case '>':
return area.moveRight(from)
case 'v':
return area.moveDown(from)
case '^':
return area.moveUp(from)
default:
return false
}
}
func (area *Area) moveLeft(from util.Vec2) bool {
target := area.a[from.Y][from.X-1]
switch target {
case '#':
return false
case '.':
area.a[from.Y][from.X-1] = area.a[from.Y][from.X]
area.a[from.Y][from.X] = '.'
return true
default:
return area.moveLeft(from.Add(util.Vec2{X: -1, Y: 0})) && area.moveLeft(from)
}
}
func (area *Area) moveRight(from util.Vec2) bool {
target := area.a[from.Y][from.X+1]
switch target {
case '#':
// fmt.Println("Wall")
return false
case '.':
// fmt.Println("moving right")
area.a[from.Y][from.X+1] = area.a[from.Y][from.X]
area.a[from.Y][from.X] = '.'
return true
default:
return area.moveRight(from.Add(util.Vec2{X: 1, Y: 0})) && area.moveRight(from)
}
}
func (area *Area) moveUp(from util.Vec2) bool {
target := area.a[from.Y-1][from.X]
switch target {
case '#':
return false
case '.':
area.a[from.Y-1][from.X] = area.a[from.Y][from.X]
area.a[from.Y][from.X] = '.'
return true
case '[':
return area.moveUp(from.Add(util.Vec2{X: 0, Y: -1})) &&
area.moveUp(from.Add(util.Vec2{X: 1, Y: -1})) &&
area.moveUp(from) &&
area.moveUp(from.Add(util.Vec2{X: 1, Y: 0}))
case ']':
return area.moveUp(from.Add(util.Vec2{X: 0, Y: -1})) &&
area.moveUp(from.Add(util.Vec2{X: -1, Y: -1})) &&
area.moveUp(from) &&
area.moveUp(from.Add(util.Vec2{X: -1, Y: 0}))
default:
return area.moveUp(from.Add(util.Vec2{X: 0, Y: -1})) && area.moveUp(from)
}
}
func (area *Area) moveDown(from util.Vec2) bool {
target := area.a[from.Y+1][from.X]
switch target {
case '#':
return false
case '.':
area.a[from.Y+1][from.X] = area.a[from.Y][from.X]
area.a[from.Y][from.X] = '.'
return true
case '[':
return area.moveUp(from.Add(util.Vec2{X: 0, Y: 1})) &&
area.moveUp(from.Add(util.Vec2{X: 1, Y: 1})) &&
area.moveUp(from) &&
area.moveUp(from.Add(util.Vec2{X: 1, Y: 0}))
case ']':
return area.moveUp(from.Add(util.Vec2{X: 0, Y: 1})) &&
area.moveUp(from.Add(util.Vec2{X: -1, Y: 1})) &&
area.moveUp(from) &&
area.moveUp(from.Add(util.Vec2{X: -1, Y: 0}))
default:
return area.moveDown(from.Add(util.Vec2{X: 0, Y: 1})) && area.moveDown(from)
}
}
func (area *Area) visualise() string {
builder := strings.Builder{}
for _, line := range area.a {
builder.WriteString(string(line))
builder.WriteRune('\n')
}
return builder.String()
}
func (area *Area) calcPosScore() int {
score := 0
for iy, line := range area.a {
for ix, char := range line {
if char == 'O' || char == '[' {
score += calcPosVal(ix, iy)
}
}
}
return score
}
func Widen(in string) string {
return strings.ReplaceAll(
strings.ReplaceAll(
strings.ReplaceAll(strings.ReplaceAll(in, ".", ".."), "@", "@."),
"#",
"##",
),
"O",
"[]",
)
}
func calcPosVal(x, y int) int {
return x + y*100
}
func main() {
rawInput := util.LoadFileFromArgs()
area, inputs := parseInput(rawInput)
// fmt.Println(area.visualise())
for _, action := range inputs {
// fmt.Println(string(action))
area.applyAction(action)
// fmt.Println(area.visualise())
}
fmt.Printf("Task 1: %d\n", area.calcPosScore())
wArea, _ := parseInput([]byte(Widen(string(rawInput))))
fmt.Println(wArea.visualise())
for _, action := range inputs {
wArea.applyAction(action)
fmt.Println(wArea.visualise())
}
fmt.Printf("Task 2: %d\n", wArea.calcPosScore())
}