You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
165 lines
4.5 KiB
165 lines
4.5 KiB
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 |
|
} |