use std::{io::{stdin, Read}, str::Chars, iter::Peekable, cmp::Ordering};
fn main() {
let mut stdin = stdin();
let mut buf = String::new();
stdin.read_to_string(&mut buf).unwrap();
// let mut c = 0; // part 1
// let mut total = 0;
// for i in buf.split("\n\n") {
// c += 1;
// let mut sp2 = i.split("\n");
// let left = parse(&mut sp2.next().unwrap().chars().peekable());
// let right = parse(&mut sp2.next().unwrap().chars().peekable());
// let comp = compare(&left, &right).unwrap();
// if comp { total += c; }
// }
// println!("{}", total);
let mut split: Vec<&str> = buf.split("\n").collect(); // part 2. even uglier
split.push("[[2]]");
split.push("[[6]]");
let mut items: Vec<Elem> = split.iter().map(|s| parse(&mut s.chars().peekable())).collect();
items.sort_by(|a, b| match compare(&a, &b) {
None => Ordering::Equal,
Some(false) => Ordering::Greater,
Some(true) => Ordering::Less
});
let s1 = items.iter().position(|n| is_sep(n, 2)).unwrap() + 1;
let s2 = items.iter().position(|n| is_sep(n, 6)).unwrap() + 1;
println!("{}*{} = {}", s1, s2, s1 * s2);
}
fn parse(a: &mut Peekable<Chars>) -> Elem { // i do not know how parser work
let mut c = a.next().unwrap();
if c == '[' {
let mut vec: Vec<Elem> = vec![];
if *a.peek().unwrap() == ']' { // this is really ugly but i don't know how to make it better without accidentally eating some input
a.next().unwrap();
} else {
while c != ']' {
let n = parse(a);
vec.push(n);
c = a.next().unwrap();
}
}
Elem::L(Box::new(vec))
} else {
let mut result: u32 = c.to_digit(10).unwrap();
while match a.peek() {
Some(c) => c.is_digit(10),
None => false
} {
c = a.next().unwrap();
result *= 10;
result += c.to_digit(10).unwrap();
}
Elem::N(result)
}
}
fn compare(l: &Elem, r: &Elem) -> Option<bool> {
use Elem::*;
match (l, r) { // fairly simple casework, badly written
(N(a), N(b)) => {
if a > b {
Some(false)
} else if a == b {
None
} else {
Some(true)
}
}
(L(a), L(b)) => {
let mut i = 0;
loop {
if i >= a.len() && i >= b.len() {
return None;
} else if i >= a.len() {
return Some(true);
} else if i >= b.len() {
return Some(false);
} else if let Some(b) = compare(&a[i], &b[i]) {
return Some(b);
}
i += 1;
}
}
(N(a), L(_)) => {
compare(&Elem::L(Box::new(vec![Elem::N(*a)])), r)
}
(L(_), N(b)) => {
compare(l, &Elem::L(Box::new(vec![Elem::N(*b)])))
}
}
}
fn is_sep(e: &Elem, n: u32) -> bool { // suffering,
if let Elem::L(a) = e {
if a.len() == 1 {
let f = &a[0];
if let Elem::L(b) = f {
if b.len() == 1 {
let ff = &b[0];
if let Elem::N(nn) = ff { n == *nn } else { false } // i don't think it's possible to do this as an && chain cause of the use of if let. kinda sucks that rust does this
} else { false }
} else { false }
} else { false }
} else { false }
}
enum Elem {
N(u32),
L(Box<Vec<Elem>>) // i hate boxes
}