170 lines
4.3 KiB
Rust
170 lines
4.3 KiB
Rust
use nom::{IResult,
|
|
multi::{many1, separated_list0},
|
|
sequence::{separated_pair, terminated},
|
|
character::complete::{self, multispace1, multispace0},
|
|
bytes::complete::tag,
|
|
branch::alt, Parser};
|
|
|
|
#[derive(Debug, Clone)]
|
|
enum Item {
|
|
NestedList(List),
|
|
Num(u8),
|
|
} use Item::*;
|
|
|
|
type List = Vec<Item>;
|
|
|
|
fn parse_item(input: &str) -> IResult<&str, Item> {
|
|
let (input, item) = alt((
|
|
complete::u8.map(|n| Num(n)),
|
|
parse_list.map(|l| NestedList(l))
|
|
))(input)?;
|
|
|
|
Ok((input, item))
|
|
}
|
|
|
|
fn parse_list(input: &str) -> IResult<&str, List> {
|
|
let (input, _) = tag("[")(input)?;
|
|
let (input, list) = separated_list0(tag(","), parse_item)(input)?;
|
|
|
|
let (input, _) = tag("]")(input)?;
|
|
|
|
Ok((input, list))
|
|
}
|
|
|
|
fn parse_input(input: &str) -> IResult<&str, Vec<(List, List)>> {
|
|
let (input, result) = many1(
|
|
terminated(
|
|
separated_pair(
|
|
parse_list,
|
|
multispace1,
|
|
parse_list
|
|
),
|
|
multispace0
|
|
)
|
|
)(input)?;
|
|
|
|
Ok((input, result))
|
|
}
|
|
|
|
fn print_list(list: &List) {
|
|
print!("[");
|
|
for item in list {
|
|
match item {
|
|
NestedList(l) => print_list(l),
|
|
Num(n) => print!("{n}"),
|
|
}
|
|
print!(",")
|
|
}
|
|
print!("]")
|
|
}
|
|
|
|
fn print_list_pair(lists: &(List, List)) {
|
|
print_list(&lists.0);
|
|
println!();
|
|
print_list(&lists.1);
|
|
println!();
|
|
println!();
|
|
}
|
|
|
|
fn check_lists(lists: &(List, List)) -> Option<bool> {
|
|
let mut l1 = lists.0.iter();
|
|
let mut l2 = lists.1.iter();
|
|
|
|
loop {
|
|
match (l1.next(), l2.next()) {
|
|
(None, Some(_)) => return Some(true),
|
|
(Some(_), None) => return Some(false),
|
|
(None, None) => return None,
|
|
(Some(Num(n)), Some(Num(m))) => if n < m {
|
|
return Some(true);
|
|
} else if n > m {
|
|
return Some(false);
|
|
} else {
|
|
continue;
|
|
},
|
|
(Some(NestedList(left)), Some(NestedList(right))) => match check_lists(&(left.to_vec(), right.to_vec())) {
|
|
None => continue,
|
|
result => return result,
|
|
},
|
|
(Some(NestedList(left)), Some(Num(m))) => match check_lists(&(left.to_vec(), vec![Num(*m)])) {
|
|
None => continue,
|
|
result => return result,
|
|
},
|
|
(Some(Num(n)), Some(NestedList(right))) => match check_lists(&(vec![Num(*n)], right.to_vec())) {
|
|
None => continue,
|
|
result => return result,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
let input_text = include_str!("../input.txt");
|
|
let (_rest, list_pairs) = parse_input(input_text).unwrap();
|
|
|
|
// Checking the parsing (which worked first try btw like wtf)
|
|
// for list_pair in &lists {
|
|
// print_list_pair(list_pair)
|
|
// }
|
|
|
|
let mut index = 0;
|
|
let mut result = 0;
|
|
for list_pair in &list_pairs {
|
|
index += 1;
|
|
|
|
match check_lists(list_pair) {
|
|
Some(true) => result += index,
|
|
Some(false) => continue,
|
|
None => unreachable!(),
|
|
}
|
|
}
|
|
|
|
println!("Sum of indices is: {result}");
|
|
|
|
let first_divider_packet = vec![NestedList(vec![Num(2)])];
|
|
let second_divider_packet = vec![NestedList(vec![Num(6)])];
|
|
|
|
let mut list = Vec::new();
|
|
for list_pair in list_pairs {
|
|
list.push(list_pair.0);
|
|
list.push(list_pair.1);
|
|
}
|
|
|
|
list.push(first_divider_packet.clone());
|
|
list.push(second_divider_packet.clone());
|
|
|
|
list.sort_by(|l, r| match check_lists(&(l.to_vec(), r.to_vec())) {
|
|
None => std::cmp::Ordering::Equal,
|
|
Some(true) => std::cmp::Ordering::Less,
|
|
Some(false) => std::cmp::Ordering::Greater,
|
|
});
|
|
|
|
// Checking the sorting (which works :D)
|
|
// for l in &list {
|
|
// print_list(l);
|
|
// println!();
|
|
// }
|
|
|
|
let mut first_index = 0;
|
|
let mut second_index = 0;
|
|
index = 1;
|
|
|
|
for l in & list {
|
|
if check_lists(&(l.to_vec(), first_divider_packet.clone())) == None {
|
|
first_index = index;
|
|
} else if check_lists(&(l.to_vec(), second_divider_packet.clone())) == None {
|
|
second_index = index;
|
|
}
|
|
|
|
if first_index != 0 && second_index != 0 {
|
|
break;
|
|
}
|
|
|
|
index += 1;
|
|
}
|
|
|
|
println!("Divider packets' indices multiplied: {}", first_index*second_index);
|
|
}
|