Day 12 (Golang)
This commit is contained in:
parent
a83343a22f
commit
3729c52f23
6 changed files with 386 additions and 1 deletions
2
.github/README.md
vendored
2
.github/README.md
vendored
|
@ -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 | | | |
|
||||
|
|
|
@ -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
|
||||
|
|
53
12-rainRisk/go/challenge/common.go
Normal file
53
12-rainRisk/go/challenge/common.go
Normal 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
|
||||
}
|
87
12-rainRisk/go/challenge/partOne.go
Normal file
87
12-rainRisk/go/challenge/partOne.go
Normal 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
|
||||
}
|
133
12-rainRisk/go/challenge/partTwo.go
Normal file
133
12-rainRisk/go/challenge/partTwo.go
Normal 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
100
12-rainRisk/go/main.go
Normal 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()
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue