Day 16 (Golang)

This commit is contained in:
akp 2020-12-25 17:55:00 +00:00
parent 8c87ea5e72
commit 67c3c6e0f2
No known key found for this signature in database
GPG key ID: D3E7EAA31B39637E
8 changed files with 371 additions and 2 deletions

2
.github/README.md vendored
View file

@ -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) | |

View file

@ -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

View 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
}

View 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
}

View 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
}

View 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
View file

@ -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
View file

@ -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=