181 lines
2.8 KiB
Go
181 lines
2.8 KiB
Go
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()
|
|
}
|