Files

224 lines
6.4 KiB
Go
Raw Permalink Normal View History

2024-12-15 20:54:35 +01:00
package main
import ( "os"; "fmt"; "strings" )
// ----------------------------------------
type Direction uint8
const (
Up Direction = iota
Down Direction = iota
Left Direction = iota
Right Direction = iota
)
func NewDirections(str string) []Direction {
direct := make([]Direction, 0, len(str))
for _, char := range []byte(str) {
switch {
case char == '<': direct = append(direct, Left)
case char == '>': direct = append(direct, Right)
case char == '^': direct = append(direct, Up)
case char == 'v': direct = append(direct, Down)
default:
}
}
return direct
}
// ----------------------------------------
type Field struct {
robot [2]int
field [][]byte
}
func NewField(str string) *Field {
field := make([][]byte, 0)
var robot [2]int
for y, line := range strings.Split(str, "\n") {
for x, char := range []byte(line) {
if char == '@' { robot = [...]int{x, y} }
}
field = append(field, []byte(line))
}
return &Field{robot: robot, field: field}
}
func (f *Field) StepUp() {
switch {
// blocked
case f.field[f.robot[1] - 1][f.robot[0]] == '#':
return
// free to move
case f.field[f.robot[1] - 1][f.robot[0]] == '.':
f.field[f.robot[1] - 1][f.robot[0]] = '@'
f.field[f.robot[1]][f.robot[0]] = '.'
f.robot[1]--
return
// infront of box
default:
loop := true
for i := 2 ; loop; i++ {
switch {
case f.field[f.robot[1] - i][f.robot[0]] == '#': return
case f.field[f.robot[1] - i][f.robot[0]] == 'O': continue
case f.field[f.robot[1] - i][f.robot[0]] == '.':
// shift boxes
f.field[f.robot[1] - i][f.robot[0]] = 'O'
loop = false
}
}
// continue shifting boxes
f.field[f.robot[1] - 1][f.robot[0]] = '@'
f.field[f.robot[1]][f.robot[0]] = '.'
f.robot[1]--
return
}
}
func (f *Field) StepDown() {
switch {
// blocked
case f.field[f.robot[1] + 1][f.robot[0]] == '#':
return
// free to move
case f.field[f.robot[1] + 1][f.robot[0]] == '.':
f.field[f.robot[1] + 1][f.robot[0]] = '@'
f.field[f.robot[1]][f.robot[0]] = '.'
f.robot[1]++
return
// infront of box
default:
loop := true
for i := 2 ; loop; i++ {
switch {
case f.field[f.robot[1] + i][f.robot[0]] == '#': return
case f.field[f.robot[1] + i][f.robot[0]] == 'O': continue
case f.field[f.robot[1] + i][f.robot[0]] == '.':
// shift boxes
f.field[f.robot[1] + i][f.robot[0]] = 'O'
loop = false
}
}
// continue shifting boxes
f.field[f.robot[1] + 1][f.robot[0]] = '@'
f.field[f.robot[1]][f.robot[0]] = '.'
f.robot[1]++
return
}
}
func (f *Field) StepRight() {
switch {
// blocked
case f.field[f.robot[1]][f.robot[0] + 1] == '#':
return
// free to move
case f.field[f.robot[1]][f.robot[0] + 1] == '.':
f.field[f.robot[1]][f.robot[0] + 1] = '@'
f.field[f.robot[1]][f.robot[0]] = '.'
f.robot[0]++
return
// infront of box
default:
loop := true
for i := 2 ; loop; i++ {
switch {
case f.field[f.robot[1]][f.robot[0] + i] == '#': return
case f.field[f.robot[1]][f.robot[0] + i] == 'O': continue
case f.field[f.robot[1]][f.robot[0] + i] == '.':
// shift boxes
f.field[f.robot[1]][f.robot[0] + i] = 'O'
loop = false
}
}
// continue shifting boxes
f.field[f.robot[1]][f.robot[0] + 1] = '@'
f.field[f.robot[1]][f.robot[0]] = '.'
f.robot[0]++
return
}
}
func (f *Field) StepLeft() {
switch {
// blocked
case f.field[f.robot[1]][f.robot[0] - 1] == '#':
return
// free to move
case f.field[f.robot[1]][f.robot[0] - 1] == '.':
f.field[f.robot[1]][f.robot[0] - 1] = '@'
f.field[f.robot[1]][f.robot[0]] = '.'
f.robot[0]--
return
// infront of box
default:
loop := true
for i := 2 ; loop; i++ {
switch {
case f.field[f.robot[1]][f.robot[0] - i] == '#': return
case f.field[f.robot[1]][f.robot[0] - i] == 'O': continue
case f.field[f.robot[1]][f.robot[0] - i] == '.':
// shift boxes
f.field[f.robot[1]][f.robot[0] - i] = 'O'
loop = false
}
}
// continue shifting boxes
f.field[f.robot[1]][f.robot[0] - 1] = '@'
f.field[f.robot[1]][f.robot[0]] = '.'
f.robot[0]--
return
}
}
func (f *Field) Print() {
for _, line := range f.field {
fmt.Println(string(line))
}
}
func (f *Field) Gps() int {
acc := 0
for y, line := range f.field {
for x, char := range line {
if char == 'O' {
acc += 100 * y + x
}
}
}
return acc
}
// ----------------------------------------
func check(err error) { if err != nil { panic(err) } }
func main() {
dat, err := os.ReadFile("data.txt")
check(err)
input := strings.TrimSpace(string(dat))
field := NewField(strings.Split(input, "\n\n")[0])
directions := NewDirections(strings.Split(input, "\n\n")[1])
//field.Print()
for _, d := range directions {
switch {
case d == Up: field.StepUp()
case d == Down: field.StepDown()
case d == Right: field.StepRight()
case d == Left: field.StepLeft()
}
//field.Print()
}
fmt.Println(field.Gps())
}