198 lines
3.5 KiB
Go
198 lines
3.5 KiB
Go
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))
|
|
}
|