Day 12 (Golang)

This commit is contained in:
akp 2020-12-12 21:00:13 +00:00
parent a83343a22f
commit 3729c52f23
No known key found for this signature in database
GPG key ID: D3E7EAA31B39637E
6 changed files with 386 additions and 1 deletions

2
.github/README.md vendored
View file

@ -27,7 +27,7 @@ Puzzle inputs and descriptions are not included in this repository. You'll have
| [9](/09-encodingError) | ![Completed][check] | [Link](/09-encodingError/python) | [Link](/09-encodingError/go) |
| [10](/10-adapterArray) | ![Completed][check] | [Link](/10-adapterArray/python) | [Link](/10-adapterArray/go) |
| [11](/11-seatingSystem) \* | ![Completed][check] | [Link](/11-seatingSystem/python) | [Link](/11-seatingSystem/python) |
| [12](/12-rainRisk) | ![Partially complete][partial] | [Link](/12-rainRisk/python) | |
| [12](/12-rainRisk) \* | ![Completed][check] | [Link](/12-rainRisk/python) | [Link](/12-rainRisk/go) |
| 13 | | | |
| 14 | | | |
| 15 | | | |

View file

@ -19,6 +19,18 @@ Test cases
1.1 pass
2.1 pass
Answers
Part 1: 1645
Part 2: 35292
go run .\go\
AoC 2020: day 12 - Rain Risk
Go go1.15.2
Test cases
1.1 pass
2.1 pass
Answers
Part 1: 1645
Part 2: 35292

View file

@ -0,0 +1,53 @@
package challenge
import (
"fmt"
"strconv"
"strings"
)
type Instruction struct {
Action string
Magnitude int
Raw string
}
func NewInstruction(rawIns string) Instruction {
ci, err := strconv.Atoi(rawIns[1:])
if err != nil {
panic(err)
}
return Instruction{
Action: strings.ToLower(string(rawIns[0])),
Magnitude: ci,
Raw: rawIns,
}
}
func calculateDirectionDeltas(direction string, amount int) (int, int) {
var (
latDelta int
longDelta int
)
if direction == "n" {
latDelta += amount
} else if direction == "s" {
latDelta -= amount
} else if direction == "e" {
longDelta += amount
} else if direction == "w" {
longDelta -= amount
} else {
panic(fmt.Errorf("invalid direction '%s'", direction))
}
return latDelta, longDelta
}
func parse(instr string) (o []Instruction) {
for _, v := range strings.Split(strings.TrimSpace(instr), "\n") {
o = append(o, NewInstruction(v))
}
return
}

View file

@ -0,0 +1,87 @@
package challenge
import "fmt"
var (
bearingsNum = map[int]string{
0: "n",
90: "e",
180: "s",
270: "w",
}
bearingsLtr = map[string]int{
"n": 0,
"e": 90,
"s": 180,
"w": 270,
}
)
func rotateDirection(current string, direction string, amount int) string {
if !(direction == "l" || direction == "r") {
panic(fmt.Errorf("invalid rotate direction '%s'", direction))
}
currentBearing := bearingsLtr[current]
if direction == "l" {
currentBearing -= amount
} else if direction == "r" {
currentBearing += amount
}
if currentBearing >= 360 {
currentBearing -= 360
} else if currentBearing < 0 {
currentBearing += 360
}
return bearingsNum[currentBearing]
}
func translateMovementOne(currentDirection string, instruction Instruction) (string, int, int) {
// Returns the new current direction and the lat/long delta
latDelta := 0
longDelta := 0
if instruction.Action == "l" || instruction.Action == "r" {
currentDirection = rotateDirection(currentDirection, instruction.Action, instruction.Magnitude)
} else if instruction.Action == "f" {
latDelta, longDelta = calculateDirectionDeltas(currentDirection, instruction.Magnitude)
} else if instruction.Action == "n" || instruction.Action == "s" || instruction.Action == "e" || instruction.Action == "w" {
latDelta, longDelta = calculateDirectionDeltas(instruction.Action, instruction.Magnitude)
} else {
panic(fmt.Errorf("invalid action '%s'", instruction.Action))
}
return currentDirection, latDelta, longDelta
}
func PartOne(instr string) int {
inputSlice := parse(instr)
currentDirection := "e"
lat := 0
long := 0
for _, instruction := range inputSlice {
var (
lad int
lod int
)
currentDirection, lad, lod = translateMovementOne(currentDirection, instruction)
lat += lad
long += lod
}
if lat < 0 {
lat = lat + -2*lat
}
if long < 0 {
long = long + -2 * long
}
return lat + long
}

View file

@ -0,0 +1,133 @@
package challenge
import "fmt"
func makePositive(n int) int {
if n >= 0 {
return n
}
return n + -2*n
}
func makeNegative(n int) int {
if n < 0 {
return n
}
return n + -2*n
}
func rotateWaypoint(current [2]int, direction string, amount int) [2]int {
if !(direction == "l" || direction == "r") {
panic(fmt.Errorf("invalid rotate direction '%s'", direction))
}
latDelta := current[0]
longDelta := current[1]
times := int(amount / 90)
var quadrant int
if latDelta >= 0 && longDelta >= 0 {
quadrant = 1
} else if latDelta < 0 && longDelta >= 0 {
quadrant = 2
} else if latDelta < 0 && longDelta < 0 {
quadrant = 3
} else if latDelta >= 0 && longDelta < 0 {
quadrant = 4
}
if quadrant == 0 {
panic(fmt.Errorf("unable to determine quadrant for %d", current))
}
newQuadrant := quadrant
if direction == "r" {
newQuadrant += times
} else if direction == "l" {
newQuadrant -= times
}
if newQuadrant > 4 {
newQuadrant -= 4
} else if newQuadrant < 1 {
newQuadrant += 4
}
quadrantDiff := quadrant - newQuadrant
if quadrantDiff%2 != 0 {
t := latDelta
latDelta = longDelta
longDelta = t
}
if newQuadrant == 1 {
latDelta = makePositive(latDelta)
longDelta = makePositive(longDelta)
} else if newQuadrant == 2 {
latDelta = makeNegative(latDelta)
longDelta = makePositive(longDelta)
} else if newQuadrant == 3 {
latDelta = makeNegative(latDelta)
longDelta = makeNegative(longDelta)
} else if newQuadrant == 4 {
latDelta = makePositive(latDelta)
longDelta = makeNegative(longDelta)
}
return [2]int{latDelta, longDelta}
}
func moveToWaypoint(waypointDelta [2]int, times int) (int, int) {
return waypointDelta[0] * times, waypointDelta[1] * times
}
func translateMovementTwo(waypointDelta [2]int, instruction Instruction) ([2]int, int, int) {
// Returns the new current direction and the lat/long delta
var (
latDelta int
longDelta int
)
if instruction.Action == "l" || instruction.Action == "r" {
waypointDelta = rotateWaypoint(waypointDelta, instruction.Action, instruction.Magnitude)
} else if instruction.Action == "f" {
latDelta, longDelta = moveToWaypoint(waypointDelta, instruction.Magnitude)
} else if instruction.Action == "n" || instruction.Action == "s" || instruction.Action == "e" || instruction.Action == "w" {
wpLatDelta, wpLongDelta := calculateDirectionDeltas(instruction.Action, instruction.Magnitude)
waypointDelta = [2]int{wpLatDelta + waypointDelta[0], wpLongDelta + waypointDelta[1]}
} else {
panic(fmt.Errorf("invalid action '%s'", instruction.Action))
}
return waypointDelta, latDelta, longDelta
}
func PartTwo(instr string) int {
inputSlice := parse(instr)
waypointDelta := [2]int{1, 10}
lat := 0
long := 0
for _, instruction := range inputSlice {
var (
lad int
lod int
)
waypointDelta, lad, lod = translateMovementTwo(waypointDelta, instruction)
lat += lad
long += lod
}
if lat < 0 {
lat = lat + -2*lat
}
if long < 0 {
long = long + -2 * long
}
return lat + long
}

100
12-rainRisk/go/main.go Normal file
View file

@ -0,0 +1,100 @@
package main
import (
"adventOfCode/12-rainRisk/go/challenge"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"runtime"
"strconv"
"github.com/fatih/color"
)
func main() {
var infoStruct info
{
inb, err := ioutil.ReadFile("info.json")
if err != nil {
fmt.Println("Error: could not open info.json")
os.Exit(-1)
}
err = json.Unmarshal(inb, &infoStruct)
if err != nil {
fmt.Println("Error: could not parse info.json")
os.Exit(-1)
}
}
var (
year = infoStruct.Year
day = infoStruct.Day
title = infoStruct.Title
)
fmt.Fprintf(color.Output, "%s: day %s - %s\n", color.YellowString("AoC "+year), color.BlueString(day), title)
fmt.Fprintf(color.Output, "Go %s\n\n", color.BlueString(runtime.Version()))
var challengeInput string
{
inb, err := ioutil.ReadFile("input.txt")
if err != nil {
fmt.Println("Error: could not open input.txt")
os.Exit(-1)
}
challengeInput = string(inb)
}
runTests(infoStruct)
fmt.Println("Answers")
fmt.Fprintf(color.Output, "Part %s: %s\n", color.BlueString("1"), color.BlueString(strconv.Itoa(challenge.PartOne(challengeInput))))
fmt.Fprintf(color.Output, "Part %s: %s\n", color.BlueString("2"), color.BlueString(strconv.Itoa(challenge.PartTwo(challengeInput))))
}
type tc struct {
Input string `json:"input"`
Expected int `json:"expected"`
}
type info struct {
Year string `json:"year"`
Day string `json:"day"`
Title string `json:"title"`
TestCases struct {
One []tc `json:"one"`
Two []tc `json:"two"`
} `json:"testCases"`
}
func runTests(infoStruct info) {
if len(infoStruct.TestCases.One) == 0 && len(infoStruct.TestCases.Two) == 0 {
fmt.Println("Info: no test cases specified. Skipping tests")
fmt.Println()
return
}
fmt.Println("Test cases")
rt := func(tcs []tc, f func(string) int, n string) {
for i, tc := range tcs {
fmt.Fprintf(color.Output, "%s ", color.BlueString(n+"."+strconv.Itoa(i+1)))
result := f(tc.Input)
if result == tc.Expected {
fmt.Fprintf(color.Output, "%s", color.GreenString("pass"))
} else {
fmt.Fprintf(color.Output, "%s (got %s, expected %s)", color.RedString("fail"), color.BlueString(strconv.Itoa(result)), color.BlueString(strconv.Itoa(tc.Expected)))
}
fmt.Println()
}
}
rt(infoStruct.TestCases.One, challenge.PartOne, "1")
rt(infoStruct.TestCases.Two, challenge.PartTwo, "2")
fmt.Println()
}