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::>() }) .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::>(); 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 { 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, } }