169 lines
3.0 KiB
Go
169 lines
3.0 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
helpers "git.bullercodeworks.com/brian/adventofcode/helpers"
|
|
)
|
|
|
|
func main() {
|
|
inp := helpers.StdinToStringSlice()
|
|
part1(inp)
|
|
fmt.Println()
|
|
part2(inp)
|
|
}
|
|
|
|
func part1(inp []string) {
|
|
rules, updates := processInput(inp)
|
|
var result int
|
|
for i := range updates {
|
|
if rules.Validate(updates[i]) {
|
|
result = result + updates[i][len(updates[i])/2]
|
|
}
|
|
}
|
|
fmt.Println("# Part 1")
|
|
fmt.Printf("Valid Updates: %d\n", result)
|
|
}
|
|
|
|
func part2(inp []string) {
|
|
rules, updates := processInput(inp)
|
|
var result int
|
|
for i := range updates {
|
|
var iter int
|
|
var wasIncorrect bool
|
|
for !rules.Validate(updates[i]) {
|
|
if iter > 100 {
|
|
panic(errors.New("Naive correction won't work..."))
|
|
}
|
|
updates[i] = rules.Correct(updates[i])
|
|
iter++
|
|
wasIncorrect = true
|
|
}
|
|
if wasIncorrect {
|
|
result = result + updates[i][len(updates[i])/2]
|
|
}
|
|
}
|
|
fmt.Println("# Part 2")
|
|
fmt.Printf("Corrected Updates: %d\n", result)
|
|
}
|
|
|
|
func processInput(inp []string) (*PageOrderingRules, [][]int) {
|
|
var rawRules []string
|
|
var strUpdates []string
|
|
var inRules bool
|
|
inRules = true
|
|
for i := range inp {
|
|
if inp[i] == "" {
|
|
inRules = false
|
|
continue
|
|
}
|
|
if inRules {
|
|
rawRules = append(rawRules, inp[i])
|
|
} else {
|
|
strUpdates = append(strUpdates, inp[i])
|
|
}
|
|
}
|
|
var updates [][]int
|
|
rules := PageOrderingRules{Rules: parseOrderingRules(rawRules)}
|
|
for i := range strUpdates {
|
|
updates = append(updates, parseUpdate(strUpdates[i]))
|
|
}
|
|
|
|
return &rules, updates
|
|
}
|
|
|
|
type PageOrderingRules struct {
|
|
Rules []Rule
|
|
}
|
|
|
|
func (p *PageOrderingRules) Correct(update []int) []int {
|
|
if p.Validate(update) {
|
|
return update
|
|
}
|
|
for i := range p.Rules {
|
|
update = p.Rules[i].Correct(update)
|
|
}
|
|
return update
|
|
}
|
|
|
|
func (p *PageOrderingRules) Validate(update []int) bool {
|
|
for i := range p.Rules {
|
|
if !p.Rules[i].Validates(update) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (p PageOrderingRules) String() string {
|
|
var ret string
|
|
for i := range p.Rules {
|
|
ret = fmt.Sprintf("%s%s\n", ret, p.Rules[i])
|
|
}
|
|
return ret
|
|
}
|
|
|
|
type Rule struct {
|
|
first, second int
|
|
}
|
|
|
|
func (r *Rule) Validates(update []int) bool {
|
|
for i := range update {
|
|
if update[i] == r.first {
|
|
for j := range update {
|
|
if update[j] == r.second {
|
|
return i < j
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (r *Rule) Correct(update []int) []int {
|
|
if r.Validates(update) {
|
|
return update
|
|
}
|
|
var idx, jdx int
|
|
for i := range update {
|
|
if update[i] == r.first {
|
|
idx = i
|
|
}
|
|
if update[i] == r.second {
|
|
jdx = i
|
|
}
|
|
}
|
|
update[idx], update[jdx] = update[jdx], update[idx]
|
|
return update
|
|
}
|
|
|
|
func (r Rule) String() string {
|
|
return fmt.Sprintf("%d|%d", r.first, r.second)
|
|
}
|
|
|
|
func parseOrderingRules(inp []string) []Rule {
|
|
var ret []Rule
|
|
for i := range inp {
|
|
if inp[i] == "" {
|
|
return ret
|
|
}
|
|
rule := Rule{}
|
|
fmt.Sscanf(inp[i], "%d|%d", &rule.first, &rule.second)
|
|
ret = append(ret, rule)
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func parseUpdate(inp string) []int {
|
|
var ret []int
|
|
pts := strings.Split(inp, ",")
|
|
for i := range pts {
|
|
var wrk int
|
|
fmt.Sscanf(pts[i], "%d", &wrk)
|
|
ret = append(ret, wrk)
|
|
}
|
|
return ret
|
|
}
|