summaryrefslogtreecommitdiff
path: root/2022/src/bin/day_13.rs
diff options
context:
space:
mode:
Diffstat (limited to '2022/src/bin/day_13.rs')
-rw-r--r--2022/src/bin/day_13.rs146
1 files changed, 146 insertions, 0 deletions
diff --git a/2022/src/bin/day_13.rs b/2022/src/bin/day_13.rs
new file mode 100644
index 0000000..b00d790
--- /dev/null
+++ b/2022/src/bin/day_13.rs
@@ -0,0 +1,146 @@
+use nom::{
+ branch::alt,
+ bytes::complete::tag,
+ character::complete::{line_ending, u32},
+ combinator::map,
+ multi::{separated_list0, separated_list1},
+ sequence::{delimited, pair, preceded},
+ IResult,
+};
+use std::{cmp::Ordering, fs};
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let input = fs::read_to_string("inputs/day_13.txt")?;
+ let message = EncodedMessage::parser(&input).unwrap().1;
+
+ dbg!(message.ordered_index_sum());
+ dbg!(message.decoder_key());
+
+ Ok(())
+}
+
+#[derive(Debug)]
+struct EncodedMessage {
+ message_pairs: Vec<(Message, Message)>,
+ ordered_indices: Vec<usize>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+enum Message {
+ List(Vec<Message>),
+ Value(u32),
+}
+
+impl EncodedMessage {
+ fn parser(input: &str) -> IResult<&str, Self> {
+ map(
+ separated_list1(
+ pair(line_ending, line_ending),
+ pair(Message::parser, preceded(line_ending, Message::parser)),
+ ),
+ EncodedMessage::new,
+ )(input)
+ }
+
+ fn new(message_pairs: Vec<(Message, Message)>) -> EncodedMessage {
+ let mut ordered_indices = Vec::new();
+
+ for (i, (left, right)) in message_pairs.iter().enumerate() {
+ if left <= right {
+ ordered_indices.push(i + 1);
+ }
+ }
+ EncodedMessage {
+ message_pairs,
+ ordered_indices,
+ }
+ }
+
+ fn ordered_index_sum(&self) -> usize {
+ self.ordered_indices.iter().sum()
+ }
+
+ fn decoder_key(&self) -> usize {
+ let mut all_packets: Vec<Message> = self
+ .message_pairs
+ .iter()
+ .flat_map(|(left, right)| [left.clone(), right.clone()])
+ .collect();
+ let divider_1 = Message::List(vec![Message::List(vec![Message::Value(2)])]);
+ let divider_2 = Message::List(vec![Message::List(vec![Message::Value(6)])]);
+ all_packets.push(divider_1.clone());
+ all_packets.push(divider_2.clone());
+
+ all_packets.sort();
+
+ let index_1 = all_packets.iter().position(|m| *m == divider_1).unwrap() + 1;
+ let index_2 = all_packets.iter().position(|m| *m == divider_2).unwrap() + 1;
+ index_1 * index_2
+ }
+}
+
+impl Message {
+ fn parser(input: &str) -> IResult<&str, Self> {
+ alt((
+ map(u32, Message::Value),
+ map(
+ delimited(
+ tag("["),
+ separated_list0(tag(","), Message::parser),
+ tag("]"),
+ ),
+ Message::List,
+ ),
+ ))(input)
+ }
+}
+
+impl PartialOrd for Message {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Message {
+ fn cmp(&self, other: &Self) -> Ordering {
+ match (self, other) {
+ (Message::Value(left), Message::Value(right)) => left.cmp(right),
+ (Message::List(left), Message::List(right)) => {
+ for i in 0..left.len() {
+ if i == right.len() {
+ return Ordering::Greater;
+ }
+ let inner_ord = left[i].cmp(&right[i]);
+ if inner_ord != Ordering::Equal {
+ return inner_ord;
+ }
+ }
+ left.len().cmp(&right.len())
+ }
+ (Message::Value(left), Message::List(right)) => {
+ if right.len() == 0 {
+ Ordering::Greater
+ } else {
+ let inner_ord = Message::Value(*left).cmp(&right[0]);
+ if inner_ord != Ordering::Equal {
+ inner_ord
+ } else {
+ 1.cmp(&right.len())
+ }
+ }
+ }
+ (Message::List(left), Message::Value(right)) => {
+ if left.len() == 0 {
+ Ordering::Less
+ } else {
+ let inner_ord = left[0].cmp(&Message::Value(*right));
+ if inner_ord != Ordering::Equal {
+ inner_ord
+ } else {
+ left.len().cmp(&1)
+ }
+ }
+ }
+ }
+ }
+}