Files
adventofcode/2024/gareth/day05/day05.go
Gareth 88938a8627 Day05
2024-12-05 13:39:33 +00:00

135 lines
2.6 KiB
Go

package day05
import (
"strconv"
"strings"
)
type Rule struct {
X, Y int
}
func ParseInput(input string) ([]Rule, [][]int) {
sections := strings.Split(input, "\n\n")
ruleLines := strings.Split(strings.TrimSpace(sections[0]), "\n")
var rules []Rule
for _, ruleLine := range ruleLines {
parts := strings.Split(ruleLine, "|")
x, _ := strconv.Atoi(parts[0])
y, _ := strconv.Atoi(parts[1])
rules = append(rules, Rule{X: x, Y: y})
}
updateLines := strings.Split(strings.TrimSpace(sections[1]), "\n")
var updates [][]int
for _, updateLine := range updateLines {
parts := strings.Split(updateLine, ",")
var update []int
for _, part := range parts {
page, _ := strconv.Atoi(part)
update = append(update, page)
}
updates = append(updates, update)
}
return rules, updates
}
func ValidateUpdate(update []int, rules []Rule) bool {
indexMap := make(map[int]int)
for i, page := range update {
indexMap[page] = i
}
for _, rule := range rules {
pageX, indexX := indexMap[rule.X]
pageY, indexY := indexMap[rule.Y]
if indexX && indexY && pageX > pageY {
return false
}
}
return true
}
func FindMiddle(update []int) int {
n := len(update)
return update[n/2]
}
func SortUpdate(update []int, rules []Rule) []int {
depen := make(map[int][]int)
for _, rule := range rules {
depen[rule.Y] = append(depen[rule.Y], rule.X)
}
visited := make(map[int]bool)
var sorted []int
for _, page := range update {
if !visited[page] {
sorted = Visit(page, depen, visited, update, sorted)
}
}
return sorted
}
func Visit(page int, depen map[int][]int, visited map[int]bool, update []int, sorted []int) []int {
if visited[page] {
return sorted
}
visited[page] = true
for _, d := range depen[page] {
if contains(update, d) {
sorted = Visit(d, depen, visited, update, sorted)
}
}
sorted = append(sorted, page)
return sorted
}
func contains(slice []int, element int) bool {
for _, item := range slice {
if item == element {
return true
}
}
return false
}
func Part1(input string) int {
rules, updates := ParseInput(input)
total := 0
for _, update := range updates {
if ValidateUpdate(update, rules) {
total += FindMiddle(update)
}
}
return total
}
func Part2(input string) int {
rules, updates := ParseInput(input)
var invalidUpdates [][]int
total := 0
for _, update := range updates {
if !ValidateUpdate(update, rules) {
invalidUpdates = append(invalidUpdates, update)
}
}
for _, update := range invalidUpdates {
sortedUpdate := SortUpdate(update, rules)
total += FindMiddle(sortedUpdate)
}
return total
}