123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- package main
- import (
- "bufio"
- "errors"
- "fmt"
- "io"
- "log"
- "os"
- "strings"
- )
- func trim(bs []byte) []byte {
- if len(bs) > 0 && bs[len(bs)-1] == '\n' {
- return bs[:len(bs)-1]
- }
- return bs
- }
- func coordOf(i, w int) (x, y int) {
- y = int(float64(i) / float64(w))
- x = i - y*w
- return
- }
- func indexOf(x, y, w int) int {
- return x + y*w
- }
- type World struct {
- wmap []byte
- width, height, robot int
- }
- func (w *World) String() string {
- var b strings.Builder
- var n int
- var err error
- for i := 0; i < w.height; i++ {
- idx := i * w.width
- n, err = b.Write(w.wmap[idx : idx+w.width])
- if err != nil {
- panic(fmt.Sprintf("While writing bytes to string: %v", err))
- }
- if n != w.width {
- panic("Wrote fewer bytes to string than expected")
- }
- n, err = b.Write([]byte{'\n'})
- if err != nil {
- panic(fmt.Sprintf("While writing bytes to string: %v", err))
- }
- if n != 1 {
- panic("Wrote fewer bytes to string than expected")
- }
- }
- return b.String()
- }
- func (w *World) Robot(move byte) bool {
- x, y := coordOf(w.robot, w.width)
- var x2, y2 int
- switch move {
- case '<':
- x2, y2 = x-1, y
- case '>':
- x2, y2 = x+1, y
- case '^':
- x2, y2 = x, y-1
- case 'v':
- x2, y2 = x, y+1
- default:
- log.Fatalf("Unknown robot instruction %q", move)
- }
- // Test for world escape.
- if x2 < 0 || w.width <= x2 ||
- y2 < 0 || w.height <= y2 {
- return false
- }
- next := indexOf(x2, y2, w.width)
- delta := next - w.robot
- idx := next
- for w.wmap[idx] != '.' && w.wmap[idx] != '#' {
- idx += delta
- }
- if w.wmap[idx] == '#' { // Walls are immovable.
- return false
- }
- for idx != w.robot { // Move everything over.
- w.wmap[idx] = w.wmap[idx-delta]
- idx -= delta
- }
- w.robot = next
- w.wmap[idx] = '.' // Replace robot with empty space.
- return true
- }
- func main() {
- world := &World{
- wmap: make([]byte, 0, 512),
- }
- r := bufio.NewReader(os.Stdin)
- // Read map
- lastLinefeed := 0
- i := 0
- for {
- i++
- col := i - lastLinefeed
- b, err := r.ReadByte()
- if errors.Is(err, io.EOF) {
- log.Fatal("Unexpected end of file")
- }
- if err != nil {
- line := 1
- if world.width > 0 {
- line = i / world.width
- }
- log.Fatalf("While reading input at line %d, column %d: %v", line, col, err)
- }
- if b == '\n' {
- if col == 1 {
- break
- }
- if world.height == 0 {
- world.width = len(world.wmap)
- }
- lastLinefeed = i
- world.height++
- continue
- }
- switch b {
- case '@':
- world.robot = len(world.wmap)
- case '.', 'O', '#':
- default:
- line := 1
- if world.width > 0 {
- line = i / world.width
- }
- log.Fatalf("Unknown or unexpected map glyph %q at line %d, column %d", b, line, col)
- }
- world.wmap = append(world.wmap, b)
- }
- // Read movements
- i = 0
- for {
- i++
- col := i - lastLinefeed
- move, err := r.ReadByte()
- if errors.Is(err, io.EOF) {
- break
- }
- if err != nil {
- log.Fatalf("While reading movements at line %d, column %d: %v", i, col, err)
- }
- switch move {
- case '\n':
- continue
- case '<', '>', '^', 'v':
- world.Robot(move)
- }
- }
- //fmt.Printf("%s\n", world)
- // Calculate sum of "GPS" coordinates
- sum := 0
- for i, b := range world.wmap {
- if b == 'O' {
- x, y := coordOf(i, world.width)
- sum += 100*y + x
- }
- }
- fmt.Println(sum)
- }
|