diff options
| author | Reiner Herrmann <reiner@reiner-h.de> | 2022-12-16 19:21:38 +0100 |
|---|---|---|
| committer | Reiner Herrmann <reiner@reiner-h.de> | 2022-12-16 19:21:38 +0100 |
| commit | 6e8c0c66ddb5f24c8f25a702371bbcf0c5de5e7b (patch) | |
| tree | bcb0e54d8e4a077894c64bad6b4da80cbfc69dbc /src | |
| parent | decb41c8226d50121dd2febd0c669b4e208eb514 (diff) | |
day13
Diffstat (limited to 'src')
| -rw-r--r-- | src/bin/day13.rs | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/src/bin/day13.rs b/src/bin/day13.rs new file mode 100644 index 0000000..0798505 --- /dev/null +++ b/src/bin/day13.rs @@ -0,0 +1,201 @@ +use std::cmp::Ordering; + +static DAY: u8 = 13; + +fn main() { + let input = advent::read_lines(DAY); + println!("{DAY}a: {}", pair_indices(&input)); + println!("{DAY}b: {}", decoder_key(&input)); +} + +#[derive(PartialEq,Eq,Debug)] +enum PacketData { + Int { value: u32 }, + List { value: Vec<PacketData> }, +} + +#[derive(PartialEq,Eq,Debug,PartialOrd,Ord)] +enum ComparisonResult { + True, + False, + Next, +} + +impl PacketData { + fn new(input: &str) -> PacketData { + let mut datalist = Vec::new(); + let mut head = PacketData::List { value: Vec::new() }; + let mut number = None; + assert_eq!(input.chars().next().unwrap(), '['); + for c in input.chars() { + match c { + '[' => { + datalist.push(head); + head = PacketData::List { value: Vec::new() }; + }, + ']' => { + let mut parent = datalist.pop().expect("list should not be empty"); + match parent { + PacketData::Int { value: _ } => panic!("parent should be a list"), + PacketData::List { ref mut value } => { + if let Some(n) = number { + match head { + PacketData::List { ref mut value } => value.push(PacketData::Int { value: n }), + PacketData::Int { value: _ } => panic!("head should be a list"), + } + number = None; + } + value.push(head); + head = parent; + } + } + }, + digit if c.is_ascii_digit() => { + let digit = digit.to_digit(10).unwrap(); + match number { + None => number = Some(digit), + Some(n) => { + number = Some(n * 10 + digit); + } + } + }, + ',' => { + if let Some(n) = number { + match head { + PacketData::List { ref mut value } => value.push(PacketData::Int { value: n }), + PacketData::Int { value: _ } => panic!("head should be a list"), + } + number = None; + } + /* if previous char waas ], it has already been handled */ + } + _ => unimplemented!(), + } + } + + match head { + PacketData::List { mut value } => value.pop().unwrap(), + PacketData::Int { value: _ } => panic!("head should have a list"), + } + } + + fn right_order(left: &PacketData, right: &PacketData) -> ComparisonResult { + match left { + PacketData::Int { value: val_left } => { + match right { + PacketData::Int { value: val_right } => match val_left.cmp(val_right) { + Ordering::Less => ComparisonResult::True, + Ordering::Greater => ComparisonResult::False, + Ordering::Equal => ComparisonResult::Next, + } + PacketData::List { value: _val_right } => { + let new_left = PacketData::new(&format!("[{}]", val_left)); + PacketData::right_order(&new_left, right) + } + } + }, + PacketData::List { value: val_left } => { + match right { + PacketData::Int { value: val_right } => { + let new_right = PacketData::new(&format!("[{}]", val_right)); + PacketData::right_order(left, &new_right) + }, + PacketData::List { value: val_right } => { + for (item_left, item_right) in val_left.iter().zip(val_right.iter()) { + let result = PacketData::right_order(item_left, item_right); + match result { + ComparisonResult::Next => continue, + res => return res, + } + } + match val_left.len().cmp(&val_right.len()) { + Ordering::Less => ComparisonResult::True, + Ordering::Greater => ComparisonResult::False, + Ordering::Equal => ComparisonResult::Next, + } + } + } + } + } + } +} + +impl PartialOrd for PacketData { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } + +} + +impl Ord for PacketData { + fn cmp(&self, other: &Self) -> Ordering { + match PacketData::right_order(self, other) { + ComparisonResult::True => Ordering::Less, + _ => Ordering::Greater, + } + } +} + +fn pair_indices(input: &[String]) -> usize { + input.chunks(3) + .map(|c| (PacketData::new(&c[0]), PacketData::new(&c[1]))) + .enumerate() + .filter(|(_,pair)| PacketData::right_order(&pair.0, &pair.1) == ComparisonResult::True) + .map(|(idx,_)| idx + 1) + .sum() +} + +fn decoder_key(input: &[String]) -> usize { + let mut input = Vec::from(input); + input.push("[[2]]".to_string()); + input.push("[[6]]".to_string()); + let mut input = input.iter() + .filter(|line| !line.is_empty()) + .map(|line| PacketData::new(line)) + .collect::<Vec<_>>(); + input.sort(); + let packet2 = PacketData::new("[[2]]"); + let packet6 = PacketData::new("[[6]]"); + input.iter() + .enumerate() + .filter(|&(_,packet)| [&packet2, &packet6].contains(&packet)) + .map(|(pos,_)| pos + 1) + .product() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test() { + let input = [ + "[1,1,3,1,1]", + "[1,1,5,1,1]", + "", + "[[1],[2,3,4]]", + "[[1],4]", + "", + "[9]", + "[[8,7,6]]", + "", + "[[4,4],4,4]", + "[[4,4],4,4,4]", + "", + "[7,7,7,7]", + "[7,7,7]", + "", + "[]", + "[3]", + "", + "[[[]]]", + "[[]]", + "", + "[1,[2,[3,[4,[5,6,7]]]],8,9]", + "[1,[2,[3,[4,[5,6,0]]]],8,9]", + ].iter().map(|&x| String::from(x)).collect::<Vec<_>>(); + + assert_eq!(pair_indices(&input), 13); + assert_eq!(decoder_key(&input), 140); + } +} |
