224 lines
6.4 KiB
Go
224 lines
6.4 KiB
Go
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())
|
|
}
|