159 lines
4.4 KiB
Rust
159 lines
4.4 KiB
Rust
use std::fs::File;
|
|
use std::io::{self, BufRead};
|
|
use std::path::Path;
|
|
use std::cmp::Ordering;
|
|
|
|
#[derive(Debug)]
|
|
enum Elem {
|
|
Number(u8),
|
|
List(Vec<Elem>),
|
|
}
|
|
|
|
use crate::Elem::{Number, List};
|
|
|
|
// I modified my input because the only 2 digits number was 10
|
|
// I replaced all 10s with ':' so that I can parse more easely
|
|
|
|
fn parse_line(line: &str, index: usize) -> (Elem, usize) {
|
|
let mut list: Vec<Elem> = vec![];
|
|
let mut len = 0;
|
|
while index + len < line.len() {
|
|
let c = line.as_bytes()[index + len];
|
|
len += 1;
|
|
match c {
|
|
b'[' => {
|
|
let (sublist, sublist_len) = parse_line(line, index + len);
|
|
len += sublist_len;
|
|
list.push(sublist);
|
|
},
|
|
b']' => return (List(list), len),
|
|
b'0'..=b':' => list.push(Number(c - b'0')),
|
|
_ => (),
|
|
};
|
|
}
|
|
unreachable!("parse_line end of function");
|
|
}
|
|
|
|
fn compare(lhs: &Elem, rhs: &Elem) -> Ordering {
|
|
let mut lhs_v = &vec![];
|
|
let mut rhs_v = &vec![];
|
|
|
|
if let List(a) = lhs {
|
|
lhs_v = a;
|
|
}
|
|
if let List(a) = rhs {
|
|
rhs_v = a;
|
|
}
|
|
|
|
for i in 0..lhs_v.len() {
|
|
if i >= rhs_v.len() {
|
|
return Ordering::Greater;
|
|
}
|
|
let compare_result = match (&lhs_v[i], &rhs_v[i]) {
|
|
(List(_), List(_)) => compare(&lhs_v[i], &rhs_v[i]),
|
|
(List(_), Number(b)) => compare(&lhs_v[i], &List(vec![Number(*b)])),
|
|
(Number(a), List(_)) => compare(&List(vec![Number(*a)]), &rhs_v[i]),
|
|
(Number(a), Number(b)) => a.cmp(b),
|
|
};
|
|
if compare_result != Ordering::Equal {
|
|
return compare_result;
|
|
}
|
|
}
|
|
|
|
if rhs_v.len() > lhs_v.len() {
|
|
return Ordering::Less;
|
|
}
|
|
Ordering::Equal
|
|
}
|
|
|
|
fn main() {
|
|
let file_path = String::from("input");
|
|
println!("In file {}", file_path);
|
|
let mut data: Vec<Elem> = vec![];
|
|
|
|
if let Ok(lines) = read_lines(file_path) {
|
|
// Consumes the iterator, returns an (Optional) String
|
|
for (i, line) in lines.enumerate() {
|
|
if let Ok(ip) = line {
|
|
match i % 3 {
|
|
0..=1 => data.push(parse_line(&ip, 1).0),
|
|
_ => (),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
let mut ret = 0;
|
|
|
|
for i in (0..data.len()).filter(|x| x % 2 == 0) {
|
|
if compare(&data[i], &data[i+1]) == Ordering::Less {
|
|
ret += i / 2 + 1;
|
|
}
|
|
}
|
|
println!("{}", ret);
|
|
}
|
|
|
|
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
|
|
where P: AsRef<Path>, {
|
|
let file = File::open(filename)?;
|
|
Ok(io::BufReader::new(file).lines())
|
|
}
|
|
|
|
#[cfg(test)]
|
|
fn compare_all_test_tool(lhs: &Elem, rhs: &Elem) {
|
|
assert_eq!(compare(&lhs, &rhs), Ordering::Less);
|
|
assert_eq!(compare(&rhs, &lhs), Ordering::Greater);
|
|
assert_eq!(compare(&rhs, &rhs), Ordering::Equal);
|
|
assert_eq!(compare(&lhs, &lhs), Ordering::Equal);
|
|
}
|
|
|
|
#[cfg(test)]
|
|
fn parse_all_test_tool(lhs: &Elem, rhs: &Elem, lhs_s: &str, rhs_s: &str) {
|
|
let lhs_s = parse_line(lhs_s, 1).0;
|
|
assert_eq!(compare(&lhs, &lhs_s), Ordering::Equal);
|
|
let rhs_s = parse_line(rhs_s, 1).0;
|
|
assert_eq!(compare(&rhs, &rhs_s), Ordering::Equal);
|
|
}
|
|
|
|
#[cfg(test)]
|
|
fn all_test_tool(lhs: &Elem, rhs: &Elem, lhs_s: &str, rhs_s: &str) {
|
|
parse_all_test_tool(&lhs, &rhs, lhs_s, rhs_s);
|
|
compare_all_test_tool(&lhs, &rhs);
|
|
}
|
|
|
|
#[test]
|
|
fn simple_list() {
|
|
let lhs_s = "[1,1,2]";
|
|
let rhs_s = "[1,3,1]";
|
|
let lhs = List(vec![Number(1), Number(1), Number(2)]);
|
|
let rhs = List(vec![Number(1), Number(3), Number(1)]);
|
|
all_test_tool(&lhs, &rhs, lhs_s, rhs_s);
|
|
}
|
|
|
|
#[test]
|
|
fn simple_list_with_conversion() {
|
|
let lhs_s = "[1,1,2]";
|
|
let rhs_s = "[1,[3],1]";
|
|
let lhs = List(vec![Number(1), Number(1), Number(2)]);
|
|
let rhs = List(vec![Number(1), List(vec![Number(3)]), Number(1)]);
|
|
all_test_tool(&lhs, &rhs, lhs_s, rhs_s);
|
|
}
|
|
|
|
#[test]
|
|
fn recursive_empty_list_simple() {
|
|
let lhs_s = "[[]]";
|
|
let rhs_s = "[[[]]]";
|
|
let lhs = List(vec![List(vec![])]);
|
|
let rhs = List(vec![List(vec![List(vec![])])]);
|
|
all_test_tool(&lhs, &rhs, lhs_s, rhs_s);
|
|
}
|
|
|
|
#[test]
|
|
fn recursive_empty_list() {
|
|
let lhs_s = "[[[[]]]]";
|
|
let rhs_s = "[[[[[]]]]]";
|
|
let lhs = List(vec![List(vec![List(vec![List(vec![])])])]);
|
|
let rhs = List(vec![List(vec![List(vec![List(vec![List(vec![])])])])]);
|
|
all_test_tool(&lhs, &rhs, lhs_s, rhs_s);
|
|
}
|