mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-06-07 20:53:30 +02:00
2020-day16: slow/730 - lots of input parsing, sample set -> corresponding rules
This commit is contained in:
+126
-22
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user