Day 16 (Golang)
This commit is contained in:
parent
8c87ea5e72
commit
67c3c6e0f2
8 changed files with 371 additions and 2 deletions
2
.github/README.md
vendored
2
.github/README.md
vendored
|
@ -31,7 +31,7 @@ Puzzle inputs and descriptions are not included in this repository. You'll have
|
|||
| [13](/13-shuttleSearch) | ![Partially complete][partial] | [Link](/13-shuttleSearch/python) | | |
|
||||
| [14](/14-dockingData) | ![Completed][check] | [Link](/14-dockingData/python) | [Link](/14-dockingData/go) | |
|
||||
| [15](/15-rambunctiousRecitation) \* | ![Completed][check] | [Link](/15-rambunctiousRecitation/python) | [Link](/15-rambunctiousRecitation/go) | |
|
||||
| [16](/16-ticketTranslation) | ![Partially complete][partial] | [Link](/16-ticketTranslation/python) | | |
|
||||
| [16](/16-ticketTranslation) | ![Completed][check] | [Link](/16-ticketTranslation/python) | [Link](/16-ticketTranslation/go) | |
|
||||
| [17](/17-conwayCubes) | ![Partially complete][partial] | [Link](/17-conwayCubes/python) | | |
|
||||
| [18](/18-operationOrder) | ![Partially complete][partial] | [Link](/18-operationOrder/python) | | |
|
||||
| [19](/19-monsterMessages) | ![Completed][check] | [Link](/19-monsterMessages/python) | [Link](/19-monsterMessages/go) | |
|
||||
|
|
|
@ -13,6 +13,18 @@ Test cases
|
|||
1.1 pass
|
||||
2.1 pass
|
||||
|
||||
Answers
|
||||
Part 1: 29019
|
||||
Part 2: 517827547723
|
||||
|
||||
❯ go run .\go\
|
||||
AoC 2020: day 16 - Ticket Translation
|
||||
Go go1.15.2
|
||||
|
||||
Test cases
|
||||
1.1 pass
|
||||
2.1 pass
|
||||
|
||||
Answers
|
||||
Part 1: 29019
|
||||
Part 2: 517827547723
|
||||
|
|
105
16-ticketTranslation/go/challenge/common.go
Normal file
105
16-ticketTranslation/go/challenge/common.go
Normal file
|
@ -0,0 +1,105 @@
|
|||
package challenge
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type rule struct {
|
||||
Name string
|
||||
Ranges [4]int
|
||||
}
|
||||
|
||||
func newRule(instr string) rule {
|
||||
insplit := strings.Split(strings.TrimSpace(instr), ": ")
|
||||
field := insplit[0]
|
||||
conditions := insplit[1]
|
||||
ranges := strings.Split(conditions, "or")
|
||||
var rangeArray [4]int
|
||||
for i, sub := range ranges {
|
||||
x := strings.Split(strings.TrimSpace(sub), "-")
|
||||
xoi, err := strconv.Atoi(x[0])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
xti, err := strconv.Atoi(x[1])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
rangeArray[i*2] = xoi
|
||||
rangeArray[(i*2)+1] = xti
|
||||
}
|
||||
return rule{
|
||||
Name: field,
|
||||
Ranges: rangeArray,
|
||||
}
|
||||
}
|
||||
|
||||
type ticket struct {
|
||||
fields []int
|
||||
}
|
||||
|
||||
func newTicket(instr string) ticket {
|
||||
insplit := strings.Split(strings.TrimSpace(instr), ",")
|
||||
var o []int
|
||||
for _, x := range insplit {
|
||||
i, err := strconv.Atoi(x)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
o = append(o, i)
|
||||
}
|
||||
return ticket{
|
||||
fields: o,
|
||||
}
|
||||
}
|
||||
|
||||
func parse(instr string) ([]rule, ticket, []ticket) {
|
||||
|
||||
splitInput := strings.Split(strings.TrimSpace(instr), "\n\n")
|
||||
|
||||
var rules []rule
|
||||
var myTicket ticket
|
||||
var otherTickets []ticket
|
||||
|
||||
for _, x := range strings.Split(splitInput[0], "\n") {
|
||||
rules = append(rules, newRule(x))
|
||||
}
|
||||
|
||||
splitMyTicket := strings.Split(splitInput[1], "\n")
|
||||
myTicket = newTicket(splitMyTicket[len(splitMyTicket)-1])
|
||||
|
||||
for _, x := range strings.Split(splitInput[2], "\n")[1:] {
|
||||
otherTickets = append(otherTickets, newTicket(x))
|
||||
}
|
||||
|
||||
return rules, myTicket, otherTickets
|
||||
}
|
||||
|
||||
func testValue(value int, condition [4]int) bool {
|
||||
return (condition[0] <= value && value <= condition[1]) || (condition[2] <= value && value <= condition[3])
|
||||
}
|
||||
|
||||
func findInvalid(rules []rule, tickets []ticket) ([]int, []int) {
|
||||
var invalidValues []int
|
||||
var invalidIndexes []int
|
||||
|
||||
for i, ticket := range tickets {
|
||||
for _, field := range ticket.fields {
|
||||
var fieldIsValid bool
|
||||
for _, rule := range rules {
|
||||
if testValue(field, rule.Ranges) {
|
||||
fieldIsValid = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !fieldIsValid {
|
||||
invalidValues = append(invalidValues, field)
|
||||
invalidIndexes = append(invalidIndexes, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return invalidValues, invalidIndexes
|
||||
}
|
13
16-ticketTranslation/go/challenge/partOne.go
Normal file
13
16-ticketTranslation/go/challenge/partOne.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package challenge
|
||||
|
||||
func PartOne(instr string) int {
|
||||
rules, _, tickets := parse(instr)
|
||||
invalidValues, _ := findInvalid(rules, tickets)
|
||||
|
||||
var sigma int
|
||||
for _, v := range invalidValues {
|
||||
sigma += v
|
||||
}
|
||||
|
||||
return sigma
|
||||
}
|
79
16-ticketTranslation/go/challenge/partTwo.go
Normal file
79
16-ticketTranslation/go/challenge/partTwo.go
Normal file
|
@ -0,0 +1,79 @@
|
|||
package challenge
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
mapset "github.com/deckarep/golang-set"
|
||||
)
|
||||
|
||||
func PartTwo(instr string) int {
|
||||
rules, myTicket, tickets := parse(instr)
|
||||
|
||||
// purge bad indexes
|
||||
_, invalidIndexes := findInvalid(rules, tickets)
|
||||
sort.Ints(invalidIndexes)
|
||||
|
||||
for i := len(invalidIndexes) - 1; i >= 0; i -= 1 { // iterate backwards
|
||||
idx := invalidIndexes[i]
|
||||
tickets = append(tickets[:idx], tickets[idx+1:]...)
|
||||
}
|
||||
|
||||
ticketLength := len(tickets[0].fields)
|
||||
|
||||
// And with this I have broken my unwritten rule of no external libraries...
|
||||
// Oh well. I like sets.
|
||||
candidates := make(map[string]mapset.Set)
|
||||
for _, rule := range rules {
|
||||
candidates[rule.Name] = mapset.NewSet()
|
||||
}
|
||||
|
||||
for col := 0; col < ticketLength; col += 1 {
|
||||
var values []int
|
||||
for _, ticket := range tickets {
|
||||
values = append(values, ticket.fields[col])
|
||||
}
|
||||
|
||||
for _, rule := range rules {
|
||||
completeMatch := true
|
||||
for _, v := range values {
|
||||
if !testValue(v, rule.Ranges) {
|
||||
completeMatch = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if completeMatch {
|
||||
// pleeeeease give us map pointers
|
||||
// please
|
||||
x := candidates[rule.Name]
|
||||
x.Add(col)
|
||||
candidates[rule.Name] = x
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parameterIndexes := make(map[string]int)
|
||||
removed := mapset.NewSet()
|
||||
|
||||
for col := 0; col < ticketLength; col += 1 {
|
||||
for name, cset := range candidates {
|
||||
candidatesSet := cset.Difference(removed)
|
||||
|
||||
if candidatesSet.Cardinality() == 1 {
|
||||
idx := candidatesSet.Pop().(int)
|
||||
parameterIndexes[name] = idx
|
||||
removed.Add(idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
product := 1
|
||||
for param, v := range parameterIndexes {
|
||||
if strings.Contains(param, "departure") {
|
||||
product *= myTicket.fields[v]
|
||||
}
|
||||
}
|
||||
|
||||
return product
|
||||
}
|
155
16-ticketTranslation/go/main.go
Normal file
155
16-ticketTranslation/go/main.go
Normal file
|
@ -0,0 +1,155 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"adventOfCode/16-ticketTranslation/go/challenge"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
var forceTime bool
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
for _, v := range os.Args[1:] {
|
||||
if v == "ft" {
|
||||
forceTime = true
|
||||
}
|
||||
}
|
||||
|
||||
runTests(infoStruct)
|
||||
|
||||
fmt.Println("Answers")
|
||||
|
||||
fmt.Printf("Running part %s...\r", color.BlueString("1"))
|
||||
outputString := fmt.Sprintf("Part %s: ", color.BlueString("1"))
|
||||
x, t := runAndTime(func() int { return challenge.PartOne(challengeInput) })
|
||||
outputString += color.BlueString(strconv.Itoa(x))
|
||||
if t > 15 || forceTime {
|
||||
outputString += fmt.Sprintf(" in %s seconds", color.BlueString(fmt.Sprintf("%.8f", t)))
|
||||
}
|
||||
for i := 0; i < 12; i += 1 {
|
||||
outputString += " "
|
||||
}
|
||||
outputString += "\n"
|
||||
fmt.Fprint(color.Output, outputString)
|
||||
|
||||
fmt.Printf("Running part %s...\r", color.BlueString("2"))
|
||||
outputString = fmt.Sprintf("Part %s: ", color.BlueString("2"))
|
||||
x, t = runAndTime(func() int { return challenge.PartTwo(challengeInput) })
|
||||
outputString += color.BlueString(strconv.Itoa(x))
|
||||
if t > 15 || forceTime {
|
||||
outputString += fmt.Sprintf(" in %s seconds", color.BlueString(fmt.Sprintf("%.8f", t)))
|
||||
}
|
||||
for i := 0; i < 12; i += 1 {
|
||||
outputString += " "
|
||||
}
|
||||
outputString += "\n"
|
||||
fmt.Fprint(color.Output, outputString)
|
||||
|
||||
}
|
||||
|
||||
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 {
|
||||
readable_test_num := color.BlueString(n + "." + strconv.Itoa(i+1))
|
||||
fmt.Fprintf(color.Output, "Running %s...\r", readable_test_num)
|
||||
|
||||
outputString := readable_test_num + " "
|
||||
|
||||
result, t := runAndTime(func() int { return f(tc.Input) })
|
||||
|
||||
if result == tc.Expected {
|
||||
outputString += color.GreenString("pass")
|
||||
} else {
|
||||
outputString += fmt.Sprintf("%s (got %s, expected %s)", color.RedString("fail"), color.BlueString(strconv.Itoa(result)), color.BlueString(strconv.Itoa(tc.Expected)))
|
||||
}
|
||||
|
||||
if t > 15 || forceTime {
|
||||
outputString += fmt.Sprintf(" in %s seconds", color.BlueString(fmt.Sprintf("%.8f", t)))
|
||||
}
|
||||
|
||||
for i := 0; i < 12; i += 1 {
|
||||
outputString += " "
|
||||
}
|
||||
outputString += "\n"
|
||||
|
||||
fmt.Fprint(color.Output, outputString)
|
||||
}
|
||||
}
|
||||
|
||||
rt(infoStruct.TestCases.One, challenge.PartOne, "1")
|
||||
rt(infoStruct.TestCases.Two, challenge.PartTwo, "2")
|
||||
|
||||
fmt.Println()
|
||||
|
||||
}
|
||||
|
||||
func runAndTime(f func() int) (int, float64) {
|
||||
st := time.Now()
|
||||
x := f()
|
||||
et := time.Now()
|
||||
return x, et.Sub(st).Seconds()
|
||||
}
|
5
go.mod
5
go.mod
|
@ -2,4 +2,7 @@ module adventOfCode
|
|||
|
||||
go 1.15
|
||||
|
||||
require github.com/fatih/color v1.10.0
|
||||
require (
|
||||
github.com/deckarep/golang-set v1.7.1
|
||||
github.com/fatih/color v1.10.0
|
||||
)
|
||||
|
|
2
go.sum
2
go.sum
|
@ -1,3 +1,5 @@
|
|||
github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ=
|
||||
github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
|
||||
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue