124 lines
2.4 KiB
Go
124 lines
2.4 KiB
Go
|
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
|
||
|
}
|