use std::{
fs::File,
io::{BufRead, BufReader},
path::Path,
};
pub fn solve(input: &Path) -> anyhow::Result<()> {
println!("part one: {}", part_one(input)?);
println!("part two: {}", part_two(input)?);
Ok(())
}
fn part_one(input: &Path) -> anyhow::Result<i32> {
let reader = BufReader::new(File::open(input)?);
let mut reading_rules = true;
let mut rules = vec![];
let mut pages_to_update = vec![];
for line in reader.lines() {
let line = line?;
if line.is_empty() {
reading_rules = false;
continue;
}
if reading_rules {
rules.push(
line.split("|")
.map(|s| s.parse::<i32>().unwrap())
.collect::<Vec<i32>>(),
)
} else {
pages_to_update.push(
line.split(",")
.map(|s| s.parse::<i32>().unwrap())
.collect::<Vec<i32>>(),
)
}
}
let mut answer = 0;
for pages in pages_to_update {
if is_in_order(&pages, &rules) {
answer += pages[pages.len() / 2];
}
}
Ok(answer)
}
fn is_in_order(pages: &[i32], rules: &[Vec<i32>]) -> bool {
for (left_index, page) in pages.iter().enumerate() {
for rule in rules.iter().filter(|&r| r[0] == *page) {
if let Some(right_index) = pages.iter().position(|n| *n == rule[1]) {
if right_index < left_index {
return false;
}
}
}
}
true
}
fn part_two(input: &Path) -> anyhow::Result<i32> {
let reader = BufReader::new(File::open(input)?);
let mut reading_rules = true;
let mut rules = vec![];
let mut pages_to_update = vec![];
for line in reader.lines() {
let line = line?;
if line.is_empty() {
reading_rules = false;
continue;
}
if reading_rules {
rules.push(
line.split("|")
.map(|s| s.parse::<i32>().unwrap())
.collect::<Vec<i32>>(),
)
} else {
pages_to_update.push(
line.split(",")
.map(|s| s.parse::<i32>().unwrap())
.collect::<Vec<i32>>(),
)
}
}
let mut answer = 0;
for pages in pages_to_update
.iter()
.filter(|pages| !is_in_order(pages, &rules))
{
answer += ordered(pages, &rules)[pages.len() / 2];
}
Ok(answer)
}
fn ordered(pages: &[i32], rules: &[Vec<i32>]) -> Vec<i32> {
let mut pages = pages.to_owned();
'w: while !is_in_order(&pages, rules) {
for (left_index, page) in pages.iter().enumerate() {
for rule in rules.iter().filter(|&r| r[0] == *page) {
if let Some(right_index) = pages.iter().position(|n| *n == rule[1]) {
if right_index < left_index {
pages.swap(right_index, left_index);
continue 'w;
}
}
}
}
}
pages
}