2020-day16: slow/730 - lots of input parsing, sample set -> corresponding rules

This commit is contained in:
alexchao26
2020-12-16 00:58:11 -05:00
parent 81adaec4b9
commit 094477ef63
2 changed files with 147 additions and 42 deletions
+126 -22
View File
@@ -6,6 +6,7 @@ import (
"strings"
"github.com/alexchao26/advent-of-code-go/mathutil"
"github.com/alexchao26/advent-of-code-go/util"
)
@@ -15,32 +16,135 @@ func main() {
flag.Parse()
fmt.Println("Running part", part)
ans := ticketTranslation(util.ReadFile("./input.txt"), part)
fmt.Println("Output:", ans)
}
func ticketTranslation(input string, part int) int {
rules, myTicket, nearbyTickets := parseInput(input)
var validTickets [][]int // for part 2
var errorRate int
for _, ticket := range nearbyTickets {
isValidTicket := true
for _, ticketValue := range ticket {
valuePassesRules := false
for _, ruleBounds := range rules {
if valuePassesRule(ticketValue, ruleBounds) {
valuePassesRules = true
break
}
}
if !valuePassesRules {
errorRate += ticketValue
isValidTicket = false // for part 2
break
}
}
// filter out valid tickets for part 2
if isValidTicket {
validTickets = append(validTickets, ticket)
}
}
if part == 1 {
ans := part1(util.ReadFile("./input.txt"))
util.CopyToClipboard(fmt.Sprintf("%v", ans))
fmt.Println("Output:", ans)
} else {
ans := part2(util.ReadFile("./input.txt"))
util.CopyToClipboard(fmt.Sprintf("%v", ans))
fmt.Println("Output:", ans)
return errorRate
}
}
func part1(input string) int {
parsed := parseInput(input)
_ = parsed
// part 2, figure out which field belongs to which
fieldNameToIndex := map[string]int{}
skipTicketIndices := map[int]bool{}
// run until all the rules are accounted for
for len(rules) > 0 {
// iterate over "columns" of the valid tickets matrix
for ticketValIndex := range validTickets[0] {
if skipTicketIndices[ticketValIndex] {
continue
}
// run all the rules against each ticket, store which ones pass for
// all values at this ticket index. if only one rule applies, it
// must be for this index within a ticket
var passingNames []string
for ruleName, ruleBounds := range rules {
allValuesPassed := true
// iterate over all tickets and if any fail for this rule, break out
for _, ticket := range validTickets {
ticketValue := ticket[ticketValIndex]
if !valuePassesRule(ticketValue, ruleBounds) {
allValuesPassed = false
break
}
}
return 0
}
// append this rule name as one that passed for these values
if allValuesPassed {
passingNames = append(passingNames, ruleName)
}
}
func part2(input string) int {
return 0
}
func parseInput(input string) (ans []int) {
lines := strings.Split(input, "\n")
for _, l := range lines {
ans = append(ans, mathutil.StrToInt(l))
// if only one rule passes, assign it to this ticket value index
// remove it from the rules list
if len(passingNames) == 1 {
fieldNameToIndex[passingNames[0]] = ticketValIndex
// remove the rule from the map b/c we've determined its index
delete(rules, passingNames[0])
// remember which indices have already been taken by a rule
skipTicketIndices[ticketValIndex] = true
}
}
}
return ans
// get final answer by multiplying all ticket details/rules prefixed "departure"
departureProduct := 1
for rule, valueIndex := range fieldNameToIndex {
if strings.HasPrefix(rule, "departure") {
departureProduct *= myTicket[valueIndex]
}
}
return departureProduct
}
func valuePassesRule(value int, ruleBounds [2][2]int) bool {
firstBounds := ruleBounds[0]
secondBounds := ruleBounds[1]
return ((value >= firstBounds[0] && value <= firstBounds[1]) ||
(value >= secondBounds[0] && value <= secondBounds[1]))
}
func parseInput(input string) (map[string][2][2]int, []int, [][]int) {
blocks := strings.Split(input, "\n\n")
// parse rules from first block
rules := map[string][2][2]int{}
for _, rule := range strings.Split(blocks[0], "\n") {
parts := strings.Split(rule, ": ")
name := parts[0]
var r1L, r1H, r2L, r2H int
fmt.Sscanf(parts[1], "%d-%d or %d-%d", &r1L, &r1H, &r2L, &r2H)
rules[name] = [2][2]int{
[2]int{r1L, r1H},
[2]int{r2L, r2H},
}
}
// my ticket values in second block
splitTicket := strings.Split(blocks[1], "\n")
var myTicket []int
for _, v := range strings.Split(splitTicket[1], ",") {
myTicket = append(myTicket, mathutil.StrToInt(v))
}
// all values for nearby tickets
var nearbyTickets [][]int
for _, nearby := range strings.Split(blocks[2], "\n")[1:] {
var near []int
for _, v := range strings.Split(nearby, ",") {
near = append(near, mathutil.StrToInt(v))
}
nearbyTickets = append(nearbyTickets, near)
}
return rules, myTicket, nearbyTickets
}
+21 -20
View File
@@ -2,37 +2,38 @@ package main
import (
"testing"
"github.com/alexchao26/advent-of-code-go/util"
)
func Test_part1(t *testing.T) {
tests := []struct {
name string
input string
want int
}{
// {"actual", util.ReadFile("input.txt"), ACTUAL_ANSWER},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := part1(tt.input); got != tt.want {
t.Errorf("part1() = %v, want %v", got, tt.want)
}
})
}
}
var example1 = `class: 1-3 or 5-7
row: 6-11 or 33-44
seat: 13-40 or 45-50
func Test_part2(t *testing.T) {
your ticket:
7,1,14
nearby tickets:
7,3,47
40,4,50
55,2,20
38,6,12`
func Test_ticketTranslation(t *testing.T) {
tests := []struct {
name string
input string
part int
want int
}{
// {"actual", util.ReadFile("input.txt"), ACTUAL_ANSWER},
{"example_part1", example1, 1, 71},
{"actual", util.ReadFile("input.txt"), 1, 32835},
{"actual", util.ReadFile("input.txt"), 2, 514662805187},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := part2(tt.input); got != tt.want {
t.Errorf("part2() = %v, want %v", got, tt.want)
if got := ticketTranslation(tt.input, tt.part); got != tt.want {
t.Errorf("ticketTranslation() = %v, want %v", got, tt.want)
}
})
}