aoc-2020/d12/main.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()
}