<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::collections::HashMap;

pub fn balance_bots_1(file: &str) -> usize {
    parse_cmds(file)
}

pub fn balance_bots_2(file: &str) -> usize {
    parse_cmds(file)
}

fn parse_cmds(file: &str) -> usize {
    let input = File::open(file).expect("File open fail.");
    let reader = BufReader::new(input);

    let lines = reader.lines()
        .filter_map(Result::ok);

    let mut bots = HashMap::new();
    let mut out_bins = HashMap::new();

    let (transfer_tokens, input_tokens): (Vec<Vec<Token>>, Vec<Vec<Token>>) = lines.map(|line| {
            let mut words = line.split_whitespace();
            let mut tokens = Vec::new();
            loop {
                if let Some(w) = words.next() {
                    match w {
                        "value" => {
                            if let Some(v) = words.next() {
                                if let Ok(n) = v.parse::<usize>() {
                                    tokens.push(Token::Value(n))
                                }
                            }
                        }
                        "bot" => {
                            if let Some(v) = words.next() {
                                if let Ok(n) = v.parse::<usize>() {
                                    tokens.push(Token::Bot(n))
                                }
                            }
                        }
                        "output" => {
                            if let Some(v) = words.next() {
                                if let Ok(n) = v.parse::<usize>() {
                                    tokens.push(Token::Output(n))
                                }
                            }
                        }
                        _ => {}
                    };
                } else {
                    return tokens;
                }
            }
        })
        .partition(|ref t| t.len() > 2);

    // Load MicroChips from input bins
    input_tokens.iter().map(|tokens| {
        let val;
        match tokens[0] {
            Token::Value(n) => val = MicroChip(n),
            Token::Bot(_) => unreachable!(),
            Token::Output(_) => unreachable!(),
        }
        match tokens[1] {
            Token::Bot(n) => {
                bots.insert(n, Bot { chips: vec![val] });
            }
            Token::Output(_) => unreachable!(),
            Token::Value(_) => unreachable!(),
        }
    });

    // Process transfers
    transfer_tokens.iter().map(|tokens| {
        let low;
        let high;
        match tokens[0] {
            Token::Bot(n) => {
                let bot = bots.entry(n).or_insert(Bot { chips: Vec::new() });
                low = bot.low();
                high = bot.high();
            }
            Token::Value(_) => unreachable!(),
            Token::Output(_) => unreachable!(),
        }
        if let Some(low) = low {
            match tokens[1] {
                Token::Bot(n) => {
                    let mut to = bots.entry(n).or_insert(Bot { chips: Vec::new() });
                    if to.chips.len() > 0 {
                        to.chips.push(low);
                    }
                }
                Token::Output(n) => {
                    let mut to = out_bins.entry(n).or_insert(OutputBin { chip: None });
                    to.chip = Some(low);
                }
                Token::Value(_) => unreachable!(),
            }
        }
        if let Some(high) = high {
            match tokens[2] {
                Token::Bot(n) => {
                    let mut to = bots.entry(n).or_insert(Bot { chips: Vec::new() });
                    if to.chips.len() > 0 {
                        to.chips.push(high);
                    }
                }
                Token::Output(n) => {
                    let mut to = out_bins.entry(n).or_insert(OutputBin { chip: None });
                    to.chip = Some(high);
                }
                Token::Value(_) => unreachable!(),
            }
        }
    });

    42
}

#[derive(Debug)]
enum Token {
    Value(usize),
    Bot(usize),
    Output(usize),
}

#[derive(Eq, PartialEq, PartialOrd, Ord, Clone)]
struct MicroChip(usize);

struct Bot {
    chips: Vec<MicroChip>,
}

impl Bot {
    fn low(&mut self) -> Option<MicroChip> {
        self.chips.iter().min().cloned()
    }

    fn high(&mut self) -> Option<MicroChip> {
        self.chips.iter().max().cloned()
    }
}

struct OutputBin {
    chip: Option<MicroChip>,
}

trait Entity {}

impl Entity for Bot {}
impl Entity for OutputBin {}<commit_msg>Update day 10 2016 with a better model.<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::collections::HashMap;

pub fn balance_bots_1(file: &str) -> usize {
    parse_cmds(file)
}

pub fn balance_bots_2(file: &str) -> usize {
    parse_cmds(file)
}

fn parse_cmds(file: &str) -> usize {
    let input = File::open(file).expect("File open fail.");
    let reader = BufReader::new(input);

    let lines = reader.lines()
        .filter_map(Result::ok);

    let mut bots = HashMap::new();
    let mut output_bins = HashMap::new();
    let mut input_bins = HashMap::new();
    for line in lines {
        let mut words = line.split_whitespace();
        loop {
            if let Some(word) = words.next() {
                match word {
                    "value" => {
                        if let Some(value) = words.next() {
                            if let Ok(value) = value.parse::<usize>() {
                                if let Some(id) = words.nth(3) {
                                    if let Ok(id) = id.parse::<usize>() {
                                        let input_bin = input_bins.entry(value).or_insert(InputBin::new());
                                        input_bin.chip = Some(Microchip(value));
                                        let bot = bots.entry(id).or_insert(Bot::new());
                                        bot.get = GetInstruction {
                                            from: Some(Entity::InputBin(value)),
                                        };
                                    }
                                }
                            }
                        }
                    },
                    "bot" => {
                        if let Some(bot_id) = words.next() {
                            if let Ok(bot_id) = bot_id.parse::<usize>() {
                                if let Some(low) = words.nth(3) {
                                    if let Some(low_id) = words.next() {
                                        if let Ok(low_id) = low_id.parse::<usize>() {
                                            if let Some(high) = words.nth(3) {
                                                if let Some(high_id) = words.next() {
                                                    if let Ok(high_id) = high_id.parse::<usize>() {
                                                        match low {
                                                            "bot" => {
                                                                let bot = bots.entry(bot_id).or_insert(Bot::new());
                                                                bot.put.low = Some(Entity::Bot(low_id));
                                                            }
                                                            "output" => {
                                                                output_bins.entry(low_id).or_insert(OutputBin::new());
                                                                let bot = bots.entry(bot_id).or_insert(Bot::new());
                                                                bot.put.low = Some(Entity::OutputBin(low_id));
                                                            }
                                                            _ => {},
                                                        };
                                                        match high {
                                                            "bot" => {
                                                                let bot = bots.entry(bot_id).or_insert(Bot::new());
                                                                bot.put.high = Some(Entity::Bot(high_id));
                                                            }
                                                            "output" => {
                                                                output_bins.entry(high_id).or_insert(OutputBin::new());
                                                                let bot = bots.entry(bot_id).or_insert(Bot::new());
                                                                bot.put.high = Some(Entity::OutputBin(high_id));
                                                            }
                                                            _ => {},
                                                        };
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    _ => {},
                }
            } else {
                break
            }
        }
    }
    println!("{:?}", bots);
    println!("{:?}", output_bins);
    println!("{:?}", input_bins);

    42
}

#[derive(Eq, PartialEq, PartialOrd, Ord, Clone, Debug)]
struct Microchip(usize);

#[derive(Debug)]
struct Bot {
    chips: Vec<Microchip>,
    get: GetInstruction,
    put: PutInstruction,
}

#[derive(Debug)]
struct GetInstruction {
    from: Option<Entity>,
}

#[derive(Debug)]
struct PutInstruction {
    low: Option<Entity>,
    high: Option<Entity>,
}

#[derive(Debug)]
struct InputBin {
    chip: Option<Microchip>,
}

#[derive(Debug)]
struct OutputBin {
    chip: Option<Microchip>,
}

#[derive(Debug)]
enum Entity {
    Bot(usize),
    OutputBin(usize),
    InputBin(usize),
}

impl Bot {
    fn new() -> Self {
        Bot {
            chips: Vec::new(),
            get: GetInstruction {
                from: None,
            },
            put: PutInstruction {
                low: None,
                high: None,
            },
        }
    }

    fn low(&mut self) -> Option<Microchip> {
        self.chips.iter().min().cloned()
    }

    fn high(&mut self) -> Option<Microchip> {
        self.chips.iter().max().cloned()
    }
}

impl InputBin {
    fn new() -> Self {
        InputBin {
            chip: None,
        }
    }
}

impl OutputBin {
    fn new() -> Self {
        OutputBin {
            chip: None,
        }
    }
}
{'fraction_non_alphanumeric': 0.12237762237762238, 'fraction_numerical': 0.0023003312476996686, 'mean_word_length': 0.8850156087408949, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 71, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 93, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3902020', 'n_tokens_mistral': 2715, 'n_tokens_neox': 2635, 'n_words': 513}