2024 Day 15 Complete!
This commit is contained in:
229
2024/day15/main.go
Normal file
229
2024/day15/main.go
Normal file
@@ -0,0 +1,229 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
||||
)
|
||||
|
||||
func main() {
|
||||
inp := h.StdinToStringSlice()
|
||||
part1(inp)
|
||||
fmt.Println()
|
||||
part2(inp)
|
||||
}
|
||||
|
||||
func part1(inp []string) {
|
||||
fmt.Println("# Part 1")
|
||||
m, dirs := parseInput(inp)
|
||||
for i := range dirs {
|
||||
bot, _ := m.FindFirst('@')
|
||||
move(m, bot, dirs[i])
|
||||
}
|
||||
crates := m.FindAll('O')
|
||||
var total int
|
||||
for i := range crates {
|
||||
add := (crates[i].Y*100 + crates[i].X)
|
||||
total = total + add
|
||||
}
|
||||
fmt.Println("GPS Sum:", total)
|
||||
}
|
||||
|
||||
func part2(inp []string) {
|
||||
fmt.Println("# Part 2")
|
||||
m, dirs := parseInput2(inp)
|
||||
for i := range dirs {
|
||||
bot, _ := m.FindFirst('@')
|
||||
move(m, bot, dirs[i])
|
||||
}
|
||||
crates := m.FindAll('[')
|
||||
var total int
|
||||
for i := range crates {
|
||||
add := (crates[i].Y*100 + crates[i].X)
|
||||
total = total + add
|
||||
}
|
||||
fmt.Println("GPS Sum:", total)
|
||||
}
|
||||
|
||||
func move(m h.CoordByteMap, orig h.Coordinate, dir byte) bool {
|
||||
if !canMove(m, orig, dir) {
|
||||
return false
|
||||
}
|
||||
oB := m.Get(orig)
|
||||
if dir == '^' || dir == 'v' {
|
||||
switch oB {
|
||||
case ']':
|
||||
return moveCrate(m, orig.West(), dir)
|
||||
case '[':
|
||||
return moveCrate(m, orig, dir)
|
||||
}
|
||||
}
|
||||
var moveTo h.Coordinate
|
||||
switch dir {
|
||||
case '^':
|
||||
moveTo = orig.North()
|
||||
case '>':
|
||||
moveTo = orig.East()
|
||||
case 'v':
|
||||
moveTo = orig.South()
|
||||
case '<':
|
||||
moveTo = orig.West()
|
||||
}
|
||||
dest := m.Get(moveTo)
|
||||
if dest == '#' {
|
||||
// A wall, can't move
|
||||
return false
|
||||
} else if dest != '.' {
|
||||
// Not a wall, but not empty, can we push it?
|
||||
if !move(m, moveTo, dir) {
|
||||
return false
|
||||
}
|
||||
// Fall through
|
||||
}
|
||||
m.Put(moveTo, oB)
|
||||
m.Put(orig, '.')
|
||||
return true
|
||||
}
|
||||
|
||||
func moveCrate(m h.CoordByteMap, orig h.Coordinate, dir byte) bool {
|
||||
if !canMoveCrate(m, orig, dir) {
|
||||
return false
|
||||
}
|
||||
var moveTo h.Coordinate
|
||||
switch dir {
|
||||
case '^':
|
||||
moveTo = orig.North()
|
||||
case 'v':
|
||||
moveTo = orig.South()
|
||||
}
|
||||
destW, destE := m.Get(moveTo), m.Get(moveTo.East())
|
||||
if destW == '#' || destE == '#' {
|
||||
// A wall, can't move
|
||||
return false
|
||||
} else {
|
||||
if destW != '.' && !move(m, moveTo, dir) {
|
||||
return false
|
||||
}
|
||||
// Check other half of crate
|
||||
if (destE != '.' && destE != ']') && !move(m, moveTo.East(), dir) {
|
||||
return false
|
||||
}
|
||||
// Fall through
|
||||
}
|
||||
m.Put(moveTo, '[')
|
||||
m.Put(moveTo.East(), ']')
|
||||
m.Put(orig, '.')
|
||||
m.Put(orig.East(), '.')
|
||||
return true
|
||||
}
|
||||
|
||||
func canMove(m h.CoordByteMap, orig h.Coordinate, dir byte) bool {
|
||||
oB := m.Get(orig)
|
||||
if dir == '^' || dir == 'v' {
|
||||
switch oB {
|
||||
case ']':
|
||||
return canMoveCrate(m, orig.West(), dir)
|
||||
case '[':
|
||||
return canMoveCrate(m, orig, dir)
|
||||
}
|
||||
}
|
||||
var moveTo h.Coordinate
|
||||
switch dir {
|
||||
case '^':
|
||||
moveTo = orig.North()
|
||||
case '>':
|
||||
moveTo = orig.East()
|
||||
case 'v':
|
||||
moveTo = orig.South()
|
||||
case '<':
|
||||
moveTo = orig.West()
|
||||
}
|
||||
dest := m.Get(moveTo)
|
||||
if dest == '#' {
|
||||
// A wall, can't move
|
||||
return false
|
||||
} else if dest != '.' {
|
||||
// Not a wall, but not empty, can we push it?
|
||||
if !canMove(m, moveTo, dir) {
|
||||
return false
|
||||
}
|
||||
// Fall through
|
||||
}
|
||||
// can move
|
||||
return true
|
||||
}
|
||||
|
||||
func canMoveCrate(m h.CoordByteMap, orig h.Coordinate, dir byte) bool {
|
||||
var moveTo h.Coordinate
|
||||
switch dir {
|
||||
case '^':
|
||||
moveTo = orig.North()
|
||||
case 'v':
|
||||
moveTo = orig.South()
|
||||
}
|
||||
destW, destE := m.Get(moveTo), m.Get(moveTo.East())
|
||||
|
||||
if destW == '#' || destE == '#' {
|
||||
// A wall, can't move
|
||||
return false
|
||||
} else {
|
||||
if destW != '.' && !canMove(m, moveTo, dir) {
|
||||
return false
|
||||
}
|
||||
// Check other half of crate
|
||||
if destE != '.' && !canMove(m, moveTo.East(), dir) {
|
||||
return false
|
||||
}
|
||||
// Fall through
|
||||
}
|
||||
// can move
|
||||
return true
|
||||
}
|
||||
|
||||
func parseInput(inp []string) (h.CoordByteMap, []byte) {
|
||||
var m h.CoordByteMap
|
||||
var dirs []byte
|
||||
var inDirs bool
|
||||
for i := range inp {
|
||||
if inDirs {
|
||||
dirs = append(dirs, []byte(inp[i])...)
|
||||
} else {
|
||||
if inp[i] == "" {
|
||||
m = h.StringSliceToCoordByteMap(inp[:i])
|
||||
inDirs = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return m, dirs
|
||||
}
|
||||
|
||||
func parseInput2(inp []string) (h.CoordByteMap, []byte) {
|
||||
// First modify the input
|
||||
var m h.CoordByteMap
|
||||
var newMap []string
|
||||
var inDirs bool
|
||||
var dirs []byte
|
||||
for i := range inp {
|
||||
if inDirs {
|
||||
dirs = append(dirs, []byte(inp[i])...)
|
||||
} else {
|
||||
if inp[i] == "" {
|
||||
m = h.StringSliceToCoordByteMap(newMap)
|
||||
inDirs = true
|
||||
}
|
||||
var newLine []byte
|
||||
for j := range inp[i] {
|
||||
switch inp[i][j] {
|
||||
case 'O':
|
||||
newLine = append(newLine, []byte{'[', ']'}...)
|
||||
case '@':
|
||||
newLine = append(newLine, []byte{'@', '.'}...)
|
||||
default:
|
||||
newLine = append(newLine, []byte{inp[i][j], inp[i][j]}...)
|
||||
}
|
||||
}
|
||||
newMap = append(newMap, string(newLine))
|
||||
}
|
||||
}
|
||||
return m, dirs
|
||||
}
|
||||
Reference in New Issue
Block a user