You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

74 lines
2.3 KiB
Rust

use serde_json::{json, Value};
use std::cmp::Ordering;
fn main() {
let contents = std::fs::read_to_string("data.txt").expect("Failed to read file");
// Part 1
let sum = contents
.trim()
.split("\n\n")
.map(|pair| {
pair.split("\n")
.map(|str| serde_json::from_str(str).unwrap())
.collect::<Vec<Value>>()
})
.enumerate()
.map(|(i, p)| (i + 1, in_order(&p[0], &p[1])))
.fold(0, |acc, (i, good)| {
acc + if good.unwrap_or(false) { i } else { 0 }
});
println!("Part 1. Sum: {:?}", sum);
// Part 2
let two = json!([[2]]);
let six = json!([[6]]);
let mut packets = contents
.split("\n")
.filter(|&l| !l.is_empty())
.map(|line| serde_json::from_str(line).unwrap())
.collect::<Vec<Value>>();
packets.append(&mut vec![two.clone(), six.clone()]);
packets.sort_by(cmp);
let idx1 = packets.iter().position(|x| x == &two).unwrap();
let idx2 = packets.iter().position(|x| x == &six).unwrap();
println!("Part 2. Decoder Key: {:?}", (idx1 + 1) * (idx2 + 1));
}
fn in_order(left: &Value, right: &Value) -> Option<bool> {
match left {
Value::Number(l) => match right {
Value::Number(r) => match l.as_u64().cmp(&r.as_u64()) {
Ordering::Less => Some(true),
Ordering::Greater => Some(false),
Ordering::Equal => None,
},
Value::Array(_) => in_order(&json!([left]), &right),
_ => panic!("Bad input"),
},
Value::Array(l) => match right {
Value::Number(_) => in_order(&left, &json!([right])),
Value::Array(r) => match (l.len(), r.len()) {
(0, 0) => None,
(0, _) => Some(true),
(_, 0) => Some(false),
(_, _) => match in_order(&l[0], &r[0]) {
None => in_order(&json!(l[1..]), &json!(r[1..])),
a => a,
},
},
_ => panic!("Bad input"),
},
_ => panic!("Bad input"),
}
}
fn cmp(l: &Value, r: &Value) -> Ordering {
match in_order(l, r) {
Some(true) => Ordering::Less,
Some(false) => Ordering::Greater,
None => Ordering::Equal,
}
}