parsing c00di aoc5

📅 2022-12-05T23:09:43.676Z
👁️ 111 katselukertaa
🔓 Julkinen


//region Parsing

//region Parsing utilities
fn transpose<T: ToOwned<Owned = T>>(v: Vec<VecDeque<T>>) -> Vec<VecDeque<T>> {
    let mut transposed: Vec<VecDeque<T>> = Vec::new();

    let max = v.iter().map(|x| x.len()).max().unwrap_or(0usize);
    for i in 0..max {
        if transposed.len() <= i {
            transposed.push(VecDeque::new());
        }

        for j in 0..v.len() {
            let opt = v[j].get(i);
            if let Some(val) = opt {
                transposed.get_mut(i).unwrap().push_back(val.to_owned());
            }
        }
    }

    return transposed;
}

fn remove_empty_blocks(input: &mut Vec<VecDeque<char>>) {
    for column in input.iter_mut() {
        column.retain(|x| *x != ' ')
    }
}
//endregion

fn ws<'a, F: 'a, O, E: ParseError<&'a str>>(
    inner: F,
) -> impl FnMut(&'a str) -> IResult<&'a str, O, E>
where
    F: FnMut(&'a str) -> IResult<&'a str, O, E>,
{
    delimited(space0, inner, space0)
}

fn block(input: &str) -> IResult<&str, char, VerboseError<&str>> {
    let (input, _) = tag("[")(input)?;
    let (input, chr) = anychar(input)?;
    let (input, _) = tag("]")(input)?;
    Ok((input, chr))
}

fn empty_block(input: &str) -> IResult<&str, char, VerboseError<&str>> {
    let (input, _) = count(tag(" "), 3)(input)?;
    Ok((input, ' '))
}

fn block_line(input: &str) -> IResult<&str, VecDeque<char>, VerboseError<&str>> {
    let (input, blocks) = separated_list1(tag(" "), alt((block, empty_block)))(input)?;
    Ok((input, VecDeque::from(blocks)))
}

fn initial_state(input: &str) -> IResult<&str, Vec<VecDeque<char>>, VerboseError<&str>> {
    let (input, lines) = separated_list1(newline, block_line)(input)?;
    let mut transpose = transpose(lines);

    // Must be done after transpose
    remove_empty_blocks(&mut transpose);

    Ok((input, transpose))
}

fn stack_numbers(input: &str) -> IResult<&str, Vec<u32>, VerboseError<&str>> {
    let (input, _) = multispace0(input)?;
    let (input, numbers) = separated_list1(space1, u32)(input)?;
    let (input, _) = multispace0(input)?;
    Ok((input, numbers))
}

fn action(input: &str) -> IResult<&str, Action, VerboseError<&str>> {
    let (input, (_, amount, _, from, _, to)) = tuple((
        ws(tag("move")),        map(u32, |x| x.to_usize()), // moving zero items does nothing
        ws(tag("from")), verify(map(u32, |x| x.to_usize()), |x| *x >= 1),
        ws(tag("to"  )), verify(map(u32, |x| x.to_usize()), |x| *x >= 1)
    ))(input)?;

    Ok((input, Action { amount, from, to }))
}

fn procedure0(input: &str) -> IResult<&str, Procedure, VerboseError<&str>> {
    let (input, initial_state) = initial_state(input)?;
    let (input,             _) = stack_numbers(input)?;

    let (input, actions) = separated_list1(newline, action)(input)?;
    Ok((input, Procedure { initial_state, actions }))
}

fn procedure(input: &str) -> IResult<&str, Procedure, VerboseError<&str>> {
    terminated(procedure0, opt(newline))(input)
}

//endregion