main.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. package main
  2. import (
  3. "bufio"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "log"
  8. "os"
  9. )
  10. func main() {
  11. r := bufio.NewReader(os.Stdin)
  12. sitMap := make([]byte, 0, 128)
  13. width := 0
  14. height := 0
  15. var guard *Cursor
  16. // Read map
  17. for {
  18. b, err := r.ReadByte()
  19. if errors.Is(err, io.EOF) {
  20. break
  21. }
  22. if err != nil {
  23. log.Fatalf("While reading input: %v", err)
  24. }
  25. if b == '\n' {
  26. if width == 0 {
  27. width = len(sitMap)
  28. }
  29. continue
  30. }
  31. switch b {
  32. case Left, Right, Up, Down:
  33. tmp := NewCursor(width, len(sitMap), b)
  34. guard = &tmp
  35. // Replace ^ with . so we don't run into our past
  36. // self.
  37. b = '.'
  38. }
  39. sitMap = append(sitMap, b)
  40. }
  41. height = len(sitMap) / width
  42. // Walk map
  43. positions := make(map[Coord]struct{})
  44. for 0 <= guard.Pos.X && guard.Pos.X <= width &&
  45. 0 <= guard.Pos.Y && guard.Pos.Y <= height {
  46. positions[guard.Pos] = struct{}{}
  47. idx := IndexOf(guard.Front(), width)
  48. if idx < 0 || len(sitMap) < idx {
  49. break
  50. }
  51. e := sitMap[idx]
  52. switch e {
  53. case '#':
  54. guard.Turn()
  55. case '.':
  56. guard.Forward()
  57. default:
  58. log.Fatalf("Unexpected map element %#v at line %d, column %d", string(e), guard.Pos.X+1, guard.Pos.Y+1)
  59. }
  60. }
  61. fmt.Println(len(positions))
  62. }
  63. type Orientation = byte
  64. const (
  65. Left Orientation = '<'
  66. Up Orientation = '^'
  67. Down Orientation = 'v'
  68. Right Orientation = '>'
  69. )
  70. type Coord struct{ X, Y int }
  71. func IndexOf(c Coord, width int) int {
  72. return c.X + c.Y*width
  73. }
  74. func OrientationOf(dir Coord) Orientation {
  75. var o Orientation
  76. switch dir {
  77. case Coord{-1, 0}:
  78. o = Left
  79. case Coord{1, 0}:
  80. o = Right
  81. case Coord{0, -1}:
  82. o = Up
  83. case Coord{0, 1}:
  84. o = Down
  85. default:
  86. panic(fmt.Sprintf("Unknown direction %#v", dir))
  87. }
  88. return o
  89. }
  90. func NewCursor(width, idx int, o Orientation) Cursor {
  91. x := idx % width
  92. y := idx / width
  93. d := Coord{}
  94. switch o {
  95. case Left:
  96. d.X = -1
  97. case Right:
  98. d.X = 1
  99. case Up:
  100. d.Y = -1
  101. case Down:
  102. d.Y = 1
  103. }
  104. return Cursor{Pos: Coord{x, y}, Dir: d}
  105. }
  106. type Cursor struct {
  107. Pos, Dir Coord
  108. }
  109. func (c *Cursor) Forward() {
  110. c.Pos = c.Front()
  111. }
  112. func (c *Cursor) Turn() {
  113. tmp := c.Dir.X
  114. c.Dir.X = -1 * c.Dir.Y
  115. c.Dir.Y = tmp
  116. }
  117. func (c *Cursor) Front() Coord {
  118. return Coord{c.Pos.X + c.Dir.X, c.Pos.Y + c.Dir.Y}
  119. }