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 }