package main import ( "bufio" "fmt" "log" "math" "os" "strconv" ) func processLines(path string, f func(string) (stop bool, err error)) error { file, err := os.Open(path) if err != nil { return err } defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { stop, err := f(scanner.Text()) if stop || err != nil { return err } } if err := scanner.Err(); err != nil { return err } return nil } type ship struct { // Ship position and heading e, n, heading int // Waypoint positions pe, pn int } func (s *ship) part2(inst string) error { fmt.Println("Read inst", inst) c := inst[0] amt, err := strconv.Atoi(inst[1:]) if err != nil { return err } switch c { case 'N': s.pn += amt case 'S': s.pn -= amt case 'W': s.pe -= amt case 'E': s.pe += amt case 'R': err = s.rotateWaypoint(amt) case 'L': err = s.rotateWaypoint(-amt) case 'F': err = s.moveToWaypoint(amt) default: err = fmt.Errorf("unknown instruction %s", inst) } fmt.Printf("After move %+v\n", s) return err } func (s *ship) moveToWaypoint(amt int) error { s.n += amt * s.pn s.e += amt * s.pe return nil } func (s *ship) rotateWaypoint(amt int) error { if amt < 0 { amt = 360 + amt } for i := 0; i < amt/90; i++ { s.pe, s.pn = s.pn, -s.pe } return nil } func (s *ship) forward(amt int) error { switch s.heading { case 0: s.n += amt case 90: s.e += amt case 180: s.n -= amt case 270: s.e -= amt default: return fmt.Errorf("unable to move in heading %d", s.heading) } return nil } func (s *ship) changeHeading(amt int) error { // Add to heading for amt < 0 { amt = 360 + amt } s.heading = (s.heading + amt) % 360 return nil } func (s *ship) move(inst string) error { c := inst[0] amt, err := strconv.Atoi(inst[1:]) if err != nil { return err } switch c { case 'N': s.n += amt case 'S': s.n -= amt case 'W': s.e -= amt case 'E': s.e += amt case 'R': return s.changeHeading(amt) case 'L': return s.changeHeading(-amt) case 'F': return s.forward(amt) default: return fmt.Errorf("unknown instruction %s", inst) } return nil } func part1() { s := ship{0, 0, 90, 0, 0} if err := processLines("input.txt", func(line string) (bool, error) { return false, s.move(line) }); err != nil { log.Fatal(err) } dist := int(math.Abs(float64(s.e)) + math.Abs(float64(s.n))) fmt.Printf("Resulting position %d,%d Distance: %d\n", s.e, s.n, dist) } func part2() { s := ship{0, 0, 90, 10, 1} if err := processLines("input.txt", func(line string) (bool, error) { return false, s.part2(line) }); err != nil { log.Fatal(err) } dist := int(math.Abs(float64(s.e)) + math.Abs(float64(s.n))) fmt.Printf("Resulting position %d,%d Distance: %d\n", s.e, s.n, dist) } func main() { part1() part2() }