github.com/cycloss/advent-of-code@v0.0.0-20221210145555-15039b95faa6/2016/day1/day1.go (about) 1 package main 2 3 import ( 4 "bufio" 5 "bytes" 6 "fmt" 7 "os" 8 "strconv" 9 10 "github.com/cycloss/advent-of-code/utils" 11 ) 12 13 type vector struct { 14 x, y int 15 } 16 17 func newVector(x, y int) vector { 18 return vector{x: x, y: y} 19 } 20 21 // up, right, down, left 22 func makeCardinalVectors() []vector { 23 return []vector{newVector(0, 1), newVector(1, 0), newVector(0, -1), newVector(-1, 0)} 24 } 25 26 func (v vector) add(v2 vector) vector { 27 return newVector(v.x+v2.x, v.y+v2.y) 28 } 29 30 func (v vector) allIntermediaryTo(v2, cardinal vector) []vector { 31 intermediary := []vector{} 32 for ; v != v2; v = v.add(cardinal) { 33 intermediary = append(intermediary, v) 34 } 35 return intermediary 36 } 37 38 type instruction struct { 39 dirMod, dist int 40 } 41 42 func (i instruction) String() string { 43 return fmt.Sprintf("dirMod: %d, dist: %d", i.dirMod, i.dist) 44 } 45 46 func newInstructionFromRaw(raw []byte) instruction { 47 48 dirMod := func(firstChar byte) int { 49 if firstChar == 'R' { 50 return 1 51 } else { 52 return -1 53 } 54 }(raw[0]) 55 56 dist := func(raw []byte) int { 57 numBytes := bytes.TrimSuffix(raw[1:], []byte{','}) 58 num, err := strconv.Atoi(string(numBytes)) 59 if err != nil { 60 utils.ExitFatal("%v", err) 61 } 62 return num 63 }(raw) 64 65 return instruction{dirMod: dirMod, dist: dist} 66 } 67 68 func (i instruction) toVector(cardinal vector) vector { 69 return vector{x: cardinal.x * i.dist, y: cardinal.y * i.dist} 70 } 71 72 func main() { 73 cardinals := makeCardinalVectors() 74 // 0 is north 75 dirIndex := 0 76 currentPos := vector{x: 0, y: 0} 77 78 f, err := os.Open("./2016/day1/input.txt") 79 if err != nil { 80 utils.ExitFatal("%v", err) 81 } 82 defer f.Close() 83 scan := bufio.NewScanner(f) 84 scan.Split(bufio.ScanWords) 85 86 visited := map[vector]bool{} 87 88 found := false 89 90 for scan.Scan() { 91 rawInstruction := scan.Bytes() 92 instruction := newInstructionFromRaw(rawInstruction) 93 dirIndex = mod(dirIndex+instruction.dirMod, 4) 94 normalisedDirection := cardinals[dirIndex] 95 walkVector := instruction.toVector(normalisedDirection) 96 97 nextPos := currentPos.add(walkVector) 98 intermediate := currentPos.allIntermediaryTo(nextPos, normalisedDirection) 99 if !found { 100 inner: 101 for _, pos := range intermediate { 102 if _, exists := visited[pos]; exists { 103 fmt.Printf("%+v", pos) 104 fmt.Printf("distance 2: %d\n", abs(pos.x)+abs(pos.y)) 105 found = true 106 break inner 107 } else { 108 visited[pos] = true 109 } 110 } 111 } 112 currentPos = nextPos 113 } 114 115 fmt.Printf("distance 1: %d\n", abs(currentPos.x)+(currentPos.y)) 116 117 } 118 119 func mod(a, b int) int { 120 return (a%b + b) % b 121 } 122 123 func abs(n int) int { 124 if n < 0 { 125 return -n 126 } else { 127 return n 128 } 129 }