165 lines
4.5 KiB
Go
165 lines
4.5 KiB
Go
package main
|
|
|
|
import (
|
|
"AoC2020/helper"
|
|
"fmt"
|
|
"os"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
func main() {
|
|
lineBreak := "\n"
|
|
args := os.Args[1:]
|
|
input, err := helper.GetFile(args[0])
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
rows := strings.Split(input, lineBreak+lineBreak)
|
|
rulesInput := strings.Split(rows[0], lineBreak)
|
|
ruleNames := getRuleNames(rulesInput)
|
|
rules := getRules(rulesInput)
|
|
myTicket := getFields(strings.Split(rows[1], lineBreak)[1])
|
|
nearbyTicketsInputs := strings.Split(rows[2], lineBreak)[1:]
|
|
var nearbyTickets [][]int
|
|
for _, val := range nearbyTicketsInputs {
|
|
nearbyTickets = append(nearbyTickets, getFields(val))
|
|
}
|
|
fmt.Printf("RuleNames: %v \n Rules: %v \n myTicket: %v \n nearbyTickets: %v \n", ruleNames, rules, myTicket, nearbyTickets)
|
|
part1(rules, nearbyTickets)
|
|
fmt.Println()
|
|
part2(rules, nearbyTickets,myTicket, ruleNames)
|
|
}
|
|
|
|
func part1(rules [][]int, nearbyTickets [][]int) {
|
|
var invalidFields []int
|
|
for _, ticket := range nearbyTickets {
|
|
invalidFields = append(invalidFields, getInvalidFields(rules, ticket)...)
|
|
}
|
|
fmt.Printf("Invalid Fields: %v \n", invalidFields)
|
|
sum := 0
|
|
for _, field := range invalidFields {
|
|
sum += field
|
|
}
|
|
fmt.Printf("Result: %v \n", sum)
|
|
}
|
|
|
|
func part2(rules [][]int, nearbyTickets [][]int, myTicket []int, ruleNames []string) {
|
|
validTickets := getValidTickets(rules,nearbyTickets)
|
|
var ruleFieldPossibleMapping = make(map[int][]int)
|
|
for fieldIndex := 0; fieldIndex < len(validTickets[0]); fieldIndex++ {
|
|
ruleIndexes := findFittingRulesForFieldsAtPositionN(rules, validTickets, fieldIndex)
|
|
ruleFieldPossibleMapping[fieldIndex] = ruleIndexes
|
|
}
|
|
fmt.Printf("Possible Mapping: %v \n", ruleFieldPossibleMapping)
|
|
var ruleFieldMapping = make(map[int]int)
|
|
for len(ruleFieldMapping) < len(ruleFieldPossibleMapping) {
|
|
for field, possibleMapping := range ruleFieldPossibleMapping {
|
|
if len(possibleMapping) == 1 {
|
|
reducePossibleMapping(ruleFieldPossibleMapping,possibleMapping[0])
|
|
ruleFieldMapping[field] = possibleMapping[0]
|
|
}
|
|
}
|
|
}
|
|
for fieldIndex, ruleIndex := range ruleFieldMapping {
|
|
fmt.Printf("Rule: %v Position: %v Value: %v \n", ruleNames[ruleIndex], fieldIndex, myTicket[fieldIndex])
|
|
}
|
|
}
|
|
|
|
func reducePossibleMapping(ruleFieldPossibleMapping map[int][]int, possibleMapping int){
|
|
for key, val := range ruleFieldPossibleMapping{
|
|
ruleFieldPossibleMapping[key] = remove(val,possibleMapping)
|
|
}
|
|
}
|
|
|
|
func getRules(input []string) [][]int {
|
|
var rules [][]int
|
|
for _, val := range input {
|
|
r, _ := regexp.Compile("[0-9]*-[0-9]*")
|
|
ruleStrings := r.FindAllString(val, -1)
|
|
for _, ruleString := range ruleStrings {
|
|
rule, _ := helper.MapToNumber(strings.Split(ruleString, "-"))
|
|
rules = append(rules, rule)
|
|
}
|
|
}
|
|
return rules
|
|
}
|
|
|
|
func getRuleNames(input []string) []string {
|
|
var ruleNames []string
|
|
for _, val := range input {
|
|
r, _ := regexp.Compile("[a-z| ]*:")
|
|
ruleName := r.FindString(val)
|
|
ruleNames = append(ruleNames, ruleName)
|
|
|
|
}
|
|
return ruleNames
|
|
}
|
|
|
|
func getFields(ticket string) []int {
|
|
fieldValues := strings.Split(ticket, ",")
|
|
fields, _ := helper.MapToNumber(fieldValues)
|
|
return fields
|
|
}
|
|
|
|
func fullfillsRule(rule []int, field int) bool {
|
|
return field >= rule[0] && field <= rule[1]
|
|
}
|
|
|
|
func findFittingRulesForFieldsAtPositionN(rules [][]int, tickets [][]int, position int) []int {
|
|
var fittingRules []int
|
|
for i := 0; i < len(rules); i += 2 {
|
|
if rulesApplyForAllFieldsAtPositionN(rules[i:i+2], tickets, position) {
|
|
fittingRules = append(fittingRules,i/2)
|
|
}
|
|
}
|
|
return fittingRules
|
|
}
|
|
|
|
func rulesApplyForAllFieldsAtPositionN(rules [][]int, tickets [][]int, position int) bool {
|
|
for _, ticket := range tickets {
|
|
if !fullfillsRule(rules[1], ticket[position]) && !fullfillsRule(rules[0], ticket[position]) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func fullFillAtLeastOneRule(rules [][]int, field int) bool {
|
|
for _, val := range rules {
|
|
if fullfillsRule(val, field) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func getInvalidFields(rules [][]int, ticket []int) []int {
|
|
var invalidFields []int
|
|
for _, field := range ticket {
|
|
if !fullFillAtLeastOneRule(rules, field) {
|
|
invalidFields = append(invalidFields, field)
|
|
}
|
|
}
|
|
return invalidFields
|
|
}
|
|
|
|
func getValidTickets(rules [][]int, tickets [][]int) [][]int {
|
|
var validTickets [][]int
|
|
for _, ticket := range tickets {
|
|
if len(getInvalidFields(rules,ticket)) == 0 {
|
|
validTickets = append(validTickets,ticket)
|
|
}
|
|
}
|
|
return validTickets
|
|
}
|
|
|
|
func remove(s []int, val int) []int {
|
|
var newS []int
|
|
for _,elem := range s {
|
|
if val != elem {
|
|
newS = append(newS,elem)
|
|
}
|
|
}
|
|
return newS
|
|
} |