advent_of_code_2024/day_05/solution.go

124 lines
2.4 KiB
Go
Raw Normal View History

2024-12-05 18:34:53 +00:00
package day_05
import (
"fmt"
"slices"
"strconv"
"strings"
)
type Rules map[int][]int
type Manual []int
// task:https://adventofcode.com/2024/day/5
// short summary - count valid columns
func SolveBasic(input string) int {
manuals, rules := loadManualAndRules(input)
sum := 0
for _, manual := range manuals {
if isManualValid(manual, rules) {
sum += manual[len(manual)/2]
}
}
return sum
}
// task:https://adventofcode.com/2024/day/5#part2
// short summary - fix and count invalid columns
func SolveComplex(input string) int {
manuals, rules := loadManualAndRules(input)
sum := 0
for _, manual := range manuals {
if !isManualValid(manual, rules) {
manual = fixManual(manual, rules)
sum += manual[len(manual)/2]
}
}
return sum
}
func fixManual(manual Manual, rules Rules) Manual {
for {
index := violationIndex(manual, rules)
if index == -1 {
return manual
}
violation := manual[index]
manual = slices.Delete(manual, index, index+1)
for i := 0; i < len(manual); i++ {
if values, present := rules[manual[i]]; present {
if slices.Contains(values, violation) {
manual = slices.Insert(manual, i, violation)
break
}
}
}
}
}
// helper methods
func isManualValid(manual Manual, rules Rules) bool {
return violationIndex(manual, rules) == -1
}
func violationIndex(manual Manual, rules Rules) int {
illegalValues := []int{}
for i, num := range manual {
if slices.Contains(illegalValues, num) {
return i
}
if _, contains := rules[num]; contains {
illegalValues = append(illegalValues, rules[num]...)
}
}
return -1
}
func loadManualAndRules(input string) ([]Manual, Rules) {
substrings := strings.Split(input, "\n\n")
rules := loadRules(substrings[0])
manuals := loadManuals(substrings[1])
return manuals, rules
}
func loadManuals(s string) []Manual {
var manuals []Manual
for _, line := range strings.Split(s, "\n") {
manuals = append(manuals, loadManual(line))
}
return manuals
}
func loadManual(line string) []int {
var manual Manual
for _, value := range strings.Split(line, ",") {
manual = append(manual, must(strconv.Atoi(value)))
}
return manual
}
func must(val int, err error) int {
if err != nil {
panic(err)
}
return val
}
func loadRules(s string) Rules {
rules := map[int][]int{}
for _, line := range strings.Split(s, "\n") {
var k, v int
_, err := fmt.Sscanf(line, "%d|%d", &k, &v)
if err != nil {
panic(err)
}
rules[v] = append(rules[v], k)
}
return rules
}