<commit_before>use std::collections::HashMap;
use std::io::BufRead;
use std::io::BufReader;
use std::io::Read;
use std::iter::FromIterator;

use common::Solution;

type State = Vec<(i64, bool)>;

#[derive(Default, Debug)]
pub struct Day12 {
    productions: [bool; 32],
}

fn char_bool(c: char) -> bool {
    match c {
        '#' => true,
        '.' => false,
        _ => panic!("Invalid input {}", c)
    }
}

fn print_state(state: &State) -> String {
    let mut buf = String::with_capacity(state.len());
    for &(_, b) in state {
        if b {
            buf.push('#');
        } else {
            buf.push('.');
        }
    }
    buf
}

fn state_from_string(representation: &str, offset: i64) -> State {
    Vec::from_iter(representation.chars()
        .enumerate()
        .map(|(i, c)| (i as i64 + offset, char_bool(c))))
}

impl Day12 {
    pub fn new() -> Self {
        Default::default()
    }

    fn read_input(&mut self, input: &mut Read) -> State {
        let state;
        let mut reader = BufReader::new(input);
        {
            let mut line = String::new();
            reader.read_line(&mut line).unwrap();
            state = state_from_string(&line["initial state:".len()..line.len()].trim(), 0);
        }

        for line in reader.lines() {
            let line = line.unwrap();

            if line.is_empty() {
                continue;
            }

            let mut index = 0;
            for c in line.chars().take(5) {
                index <<= 1;
                if char_bool(c) {
                    index |= 1;
                }
            }

            self.productions[index] = char_bool(line.chars().last().unwrap());
        }
<commit_msg>Make day 12 even more rusty.<commit_after>use std::collections::HashMap;
use std::io::BufRead;
use std::io::BufReader;
use std::io::Read;
use std::iter::FromIterator;

use common::Solution;

type State = Vec<(i64, bool)>;

#[derive(Default, Debug)]
pub struct Day12 {
    productions: [bool; 32],
}

fn char_bool(c: char) -> bool {
    match c {
        '#' => true,
        '.' => false,
        _ => panic!("Invalid input {}", c)
    }
}

fn print_state(state: &State) -> String {
    state.iter().map(|(_, x)| if *x { '#' } else { '.' }).collect()
}

fn state_from_string(representation: &str, offset: i64) -> State {
    representation.chars().enumerate()
        .map(|(i, c)| (i as i64 + offset, char_bool(c)))
        .collect()
}

impl Day12 {
    pub fn new() -> Self {
        Default::default()
    }

    fn read_input(&mut self, input: &mut Read) -> State {
        let state;
        let mut reader = BufReader::new(input);
        let mut line = String::new();
        reader.read_line(&mut line).unwrap();
        state = state_from_string(&line["initial state:".len()..line.len()].trim(), 0);

        for line in reader.lines() {
            let line = line.unwrap();

            if line.is_empty() {
                continue;
            }

            let mut index = 0;
            for c in line.chars().take(5) {
                index = (index << 1) | char_bool(c) as usize;
            }

            self.productions[index] = char_bool(line.chars().last().unwrap());
        }

{'fraction_non_alphanumeric': 0.16807247735082786, 'fraction_numerical': 0.010934083099031553, 'mean_word_length': 1.9758364312267658, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4578811', 'n_tokens_mistral': 1045, 'n_tokens_neox': 1017, 'n_words': 245}