package main import ( "bufio" "fmt" "os" "strconv" "time" ) func main() { start := time.Now() partOne() duration := time.Since(start) partTwo() duration2 := time.Since(start) fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration) } type ship struct { horizontal int vertical int direction rune // E W N S } // both horizontal/vertical are relative to ship type waypoint struct { horizontal int vertical int } func parseLine(s string) (rune, int) { i, _ := strconv.Atoi(s[1:]) return []rune(s)[0], i } func movePartOne(s ship, action rune, vector int) ship { switch action { case 'R', 'L': s.direction = rotateShip(s.direction, vector, action) case 'N': s.vertical = s.vertical + vector case 'S': s.vertical = s.vertical - vector case 'E': s.horizontal = s.horizontal + vector case 'W': s.horizontal = s.horizontal - vector case 'F': s = movePartOne(s, s.direction, vector) } return s } func movePartTwo(s ship, w waypoint, action rune, vector int) (ship, waypoint) { switch action { case 'R', 'L': w = rotateWaypoint(w, action, vector) case 'N': w.vertical = w.vertical + vector case 'S': w.vertical = w.vertical - vector case 'E': w.horizontal = w.horizontal + vector case 'W': w.horizontal = w.horizontal - vector case 'F': s.horizontal = s.horizontal + (w.horizontal * vector) s.vertical = s.vertical + (w.vertical * vector) } return s, w } // for example E, 90, L => N; E, 180, R => W; E, 90, R => S func rotateShip(current rune, degrees int, rl rune) rune { // easy if degrees == 180 { switch current { case 'N': return 'S' case 'S': return 'N' case 'E': return 'W' case 'W': return 'E' } } // translate L to R if rl == 'L' { if degrees == 90 { degrees = 270 } else { degrees = 90 } } // the R set if degrees == 90 { switch current { case 'N': return 'E' case 'S': return 'W' case 'E': return 'S' case 'W': return 'N' } } else if degrees == 270 { switch current { case 'N': return 'W' case 'S': return 'E' case 'E': return 'N' case 'W': return 'S' } } return current // we're made a terrible mistake somewhere } func rotateWaypoint(w waypoint, action rune, vector int) waypoint { if vector == 180 { w.horizontal, w.vertical = -w.horizontal, -w.vertical } else if action == 'R' { if vector == 90 { w.horizontal, w.vertical = w.vertical, -w.horizontal } if vector == 270 { w.horizontal, w.vertical = -w.vertical, w.horizontal } } else if action == 'L' { if vector == 90 { w.horizontal, w.vertical = -w.vertical, w.horizontal } if vector == 270 { w.horizontal, w.vertical = w.vertical, -w.horizontal } } return w } func manhattan(i, j int) int { return abs(i) + abs(j) } func abs(x int) int { if x < 0 { return -x } return x } func partOne() { f, _ := os.Open("input") reader := bufio.NewReader(f) scanner := bufio.NewScanner(reader) s := ship{ horizontal: 0, vertical: 0, direction: 'E', } for scanner.Scan() { dir, vec := parseLine(scanner.Text()) s = movePartOne(s, dir, vec) } fmt.Println(manhattan(s.horizontal, s.vertical)) } func partTwo() { f, _ := os.Open("input") reader := bufio.NewReader(f) scanner := bufio.NewScanner(reader) s := ship{ horizontal: 0, vertical: 0, // no longer care about ship direction } w := waypoint{ horizontal: 10, vertical: 1, } for scanner.Scan() { dir, vec := parseLine(scanner.Text()) s, w = movePartTwo(s, w, dir, vec) } fmt.Println(manhattan(s.horizontal, s.vertical)) }