Part 1 solution for 2021 day 4

[?]
Dec 8, 2021, 1:04 AM
P7M5N7HRGJBPQPN6NTYYG56EWFZQWGC62AFO6TAIXCSDRPKX3LNQC

Dependencies

Change contents

  • file addition: day4.rs (----------)
    [4.16]
    use std::collections::HashMap;
    fn time_bingo<RI: IntoIterator<Item = CI>, CI: IntoIterator<Item = u8>>(
    draws: &HashMap<u8, usize>,
    board: RI,
    ) -> usize {
    let mut col_notes: [usize; 5] = [0; 5];
    let mut soonest_row = usize::MAX;
    for row in board {
    let mut this_row = 0;
    for (x, c) in row.into_iter().enumerate() {
    let t = draws.get(&c).copied().unwrap_or(usize::MAX);
    this_row = this_row.max(t);
    col_notes[x] = col_notes[x].max(t);
    }
    soonest_row = soonest_row.min(this_row);
    }
    std::iter::once(soonest_row)
    .chain(col_notes.iter().copied())
    .min()
    .unwrap()
    }
    fn score_board<RI: IntoIterator<Item = CI>, CI: IntoIterator<Item = u8>>(
    draws: &HashMap<u8, usize>,
    board: RI,
    step: usize,
    ) -> usize {
    board
    .into_iter()
    .flat_map(IntoIterator::into_iter)
    .filter(|n| match draws.get(n) {
    None => true,
    Some(s) => s > &step,
    })
    .map(<u8 as Into<usize>>::into)
    .sum()
    }
    fn parse_draws(line: &str) -> HashMap<u8, usize> {
    line.split(',')
    .flat_map(|x| x.parse().ok())
    .enumerate()
    .map(|(i, x)| (x, i))
    .collect()
    }
    fn parse_boards<I: Iterator<Item = S>, S: AsRef<str>>(input: &mut I) -> Vec<Vec<Vec<u8>>> {
    input
    .filter(|l| l.as_ref().len() > 0)
    .groups_of(5)
    .map(|chunk| {
    chunk
    .iter()
    .map(|line| {
    line.as_ref()
    .split_whitespace()
    .flat_map(|ns| ns.parse().ok())
    .collect()
    })
    .collect()
    })
    .collect()
    }
    fn main() {
    use std::io::BufRead;
    let filename = std::env::args().nth(1).expect("Expected filename");
    let file = std::io::BufReader::new(
    std::fs::File::open(<String as AsRef<std::path::Path>>::as_ref(&filename)).unwrap(),
    );
    let mut lines = file.lines();
    let draws = lines
    .next()
    .map(|l| parse_draws(&l.unwrap()))
    .expect("File is empty");
    let boards = parse_boards(&mut lines.flat_map(Result::ok));
    let (score,step) = boards.iter()
    .map(|board| {
    let step = time_bingo(&draws, board.iter().map(|r| r.iter().copied()));
    (score_board(&draws,board.iter().map(|r| r.iter().copied()),step), step)
    })
    .min_by(|(_,a),(_,b)| a.cmp(b))
    .unwrap();
    println!("Time: {}", step);
    println!("Score: {}", score);
    let (last_called,_) = draws.iter()
    .filter(|(_,w)| *w == &step)
    .next()
    .unwrap();
    println!("Last called: {}", last_called);
    println!("Product: {}", score * <u8 as Into<usize>>::into(*last_called));
    }
    struct Groups<I> {
    inner: I,
    group_size: usize,
    }
    impl<I: Sized + Iterator> Iterator for Groups<I> {
    type Item = Vec<<I as Iterator>::Item>;
    fn next(&mut self) -> Option<Self::Item> {
    if self.group_size == 0 {
    None
    } else {
    let mut result = Vec::with_capacity(self.group_size);
    for _ in 0..self.group_size {
    match self.inner.next() {
    Some(a) => {
    result.push(a);
    }
    None => {
    break;
    }
    }
    }
    if result.len() == 0 {
    self.group_size = 0;
    None
    } else {
    Some(result)
    }
    }
    }
    }
    trait Groupable: Sized + Iterator {
    fn groups_of(self, size: usize) -> Groups<Self>;
    }
    impl<I: Sized + Iterator> Groupable for I {
    fn groups_of(self, size: usize) -> Groups<Self> {
    Groups {
    inner: self,
    group_size: size,
    }
    }
    }
  • edit in 2021/Cargo.toml at line 21
    [2.1456]
    [2.1456]
    [[bin]]
    name = "day4"
    path = "day4.rs"