| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- use std::fs;
- use std::env;
- use nom::IResult;
- use nom::multi::separated_list0;
- use nom::branch::alt;
- use nom::bytes::complete::tag;
- use nom::character::complete::i32;
- use nom::character::complete::space1;
- use nom::character::complete::space0;
- use nom::combinator::value;
- use nom::sequence::tuple;
- use nom::sequence::preceded;
- use nom::sequence::separated_pair;
- use nom::sequence::terminated;
- #[derive(Clone, Debug, PartialEq, Eq)]
- enum Color {
- Red,
- Green,
- Blue,
- }
- #[derive(Clone, Debug, PartialEq, Eq)]
- struct Draw {
- red_count: i32,
- green_count: i32,
- blue_count: i32,
- }
- #[derive(Clone, Debug, PartialEq, Eq)]
- struct Game {
- id: i32,
- draws: Vec<Draw>,
- }
- fn parse_color(input: &str) -> IResult<&str, Color> {
- alt((
- value(Color::Red, tag("red")),
- value(Color::Green, tag("green")),
- value(Color::Blue, tag("blue")),
- ))(input)
- }
- fn parse_game_id(input: &str) -> IResult<&str, i32> {
- terminated(
- preceded(
- tuple((space0, tag("Game"),space1)),
- i32,
- ),
- space0,
- )(input)
- }
- fn parse_number_of_cubes(input: &str) -> IResult<&str, (i32, Color)> {
- preceded(
- space0,
- separated_pair(
- i32,
- space1,
- parse_color,
- )
- )(input)
- }
- fn parse_draw(input: &str) -> IResult<&str, Vec<(i32, Color)>> {
- separated_list0(
- tag(","),
- parse_number_of_cubes
- )(input)
- }
- fn parse_game_draws(input: &str) -> IResult<&str, Vec<Vec<(i32, Color)>>> {
- separated_list0(
- tag(";"),
- parse_draw
- )(input)
- }
- fn parse_input_line(input: &str) -> IResult<&str, (i32, Vec<Vec<(i32, Color)>>)> {
- separated_pair(
- parse_game_id,
- tag(":"),
- parse_game_draws,
- )(input)
- }
- fn create_game_from_data(data: (i32, Vec<Vec<(i32, Color)>>)) -> Game {
- let (id, draws_data) = data;
- let mut draws: Vec<Draw> = Vec::new();
- for draw_data in draws_data {
- let mut draw = Draw{
- red_count: 0,
- green_count: 0,
- blue_count: 0,
- };
- for color_count in draw_data {
- let (count, color) = color_count;
- match color {
- Color::Red => draw.red_count += count,
- Color::Green => draw.green_count += count,
- Color::Blue => draw.blue_count += count,
- }
- }
- draws.push(draw);
- }
- Game{
- id,
- draws,
- }
- }
- fn parse_game(input: &str) -> Result<Game, String> {
- match parse_input_line(input) {
- Ok((rest, data)) => if rest == "" {
- Ok(create_game_from_data(data))
- } else {
- Err(format!("Incomplete parse, remaining: {}", rest))
- },
- Err(error) => Err(error.to_string()),
- }
- }
- fn main() {
- let mut result = 0;
- let args: Vec<String> = env::args().collect();
- let file_path = &args[1];
- let input_data = fs::read_to_string(file_path).unwrap_or_else(
- |_|{panic!("Can't read file {}", file_path)});
- for line in input_data.lines() {
- let game = parse_game(line).unwrap_or_else(|e|panic!("Failed to parse line: {}", e));
- let mut max_red = 0;
- let mut max_green = 0;
- let mut max_blue = 0;
- for draw in &game.draws {
- if draw.red_count > max_red {
- max_red = draw.red_count;
- }
- if draw.green_count > max_green {
- max_green = draw.green_count;
- }
- if draw.blue_count > max_blue {
- max_blue = draw.blue_count;
- }
- }
- result += max_red * max_green * max_blue;
- }
- println!("{}", result);
- }
|