main.rs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. use std::fs;
  2. use std::env;
  3. use nom::IResult;
  4. use nom::multi::separated_list0;
  5. use nom::branch::alt;
  6. use nom::bytes::complete::tag;
  7. use nom::character::complete::i32;
  8. use nom::character::complete::space1;
  9. use nom::character::complete::space0;
  10. use nom::combinator::value;
  11. use nom::sequence::tuple;
  12. use nom::sequence::preceded;
  13. use nom::sequence::separated_pair;
  14. use nom::sequence::terminated;
  15. #[derive(Clone, Debug, PartialEq, Eq)]
  16. enum Color {
  17. Red,
  18. Green,
  19. Blue,
  20. }
  21. #[derive(Clone, Debug, PartialEq, Eq)]
  22. struct Draw {
  23. red_count: i32,
  24. green_count: i32,
  25. blue_count: i32,
  26. }
  27. #[derive(Clone, Debug, PartialEq, Eq)]
  28. struct Game {
  29. id: i32,
  30. draws: Vec<Draw>,
  31. }
  32. fn parse_color(input: &str) -> IResult<&str, Color> {
  33. alt((
  34. value(Color::Red, tag("red")),
  35. value(Color::Green, tag("green")),
  36. value(Color::Blue, tag("blue")),
  37. ))(input)
  38. }
  39. fn parse_game_id(input: &str) -> IResult<&str, i32> {
  40. terminated(
  41. preceded(
  42. tuple((space0, tag("Game"),space1)),
  43. i32,
  44. ),
  45. space0,
  46. )(input)
  47. }
  48. fn parse_number_of_cubes(input: &str) -> IResult<&str, (i32, Color)> {
  49. preceded(
  50. space0,
  51. separated_pair(
  52. i32,
  53. space1,
  54. parse_color,
  55. )
  56. )(input)
  57. }
  58. fn parse_draw(input: &str) -> IResult<&str, Vec<(i32, Color)>> {
  59. separated_list0(
  60. tag(","),
  61. parse_number_of_cubes
  62. )(input)
  63. }
  64. fn parse_game_draws(input: &str) -> IResult<&str, Vec<Vec<(i32, Color)>>> {
  65. separated_list0(
  66. tag(";"),
  67. parse_draw
  68. )(input)
  69. }
  70. fn parse_input_line(input: &str) -> IResult<&str, (i32, Vec<Vec<(i32, Color)>>)> {
  71. separated_pair(
  72. parse_game_id,
  73. tag(":"),
  74. parse_game_draws,
  75. )(input)
  76. }
  77. fn create_game_from_data(data: (i32, Vec<Vec<(i32, Color)>>)) -> Game {
  78. let (id, draws_data) = data;
  79. let mut draws: Vec<Draw> = Vec::new();
  80. for draw_data in draws_data {
  81. let mut draw = Draw{
  82. red_count: 0,
  83. green_count: 0,
  84. blue_count: 0,
  85. };
  86. for color_count in draw_data {
  87. let (count, color) = color_count;
  88. match color {
  89. Color::Red => draw.red_count += count,
  90. Color::Green => draw.green_count += count,
  91. Color::Blue => draw.blue_count += count,
  92. }
  93. }
  94. draws.push(draw);
  95. }
  96. Game{
  97. id,
  98. draws,
  99. }
  100. }
  101. fn parse_game(input: &str) -> Result<Game, String> {
  102. match parse_input_line(input) {
  103. Ok((rest, data)) => if rest == "" {
  104. Ok(create_game_from_data(data))
  105. } else {
  106. Err(format!("Incomplete parse, remaining: {}", rest))
  107. },
  108. Err(error) => Err(error.to_string()),
  109. }
  110. }
  111. fn main() {
  112. let mut result = 0;
  113. let args: Vec<String> = env::args().collect();
  114. let file_path = &args[1];
  115. let input_data = fs::read_to_string(file_path).unwrap_or_else(
  116. |_|{panic!("Can't read file {}", file_path)});
  117. for line in input_data.lines() {
  118. let game = parse_game(line).unwrap_or_else(|e|panic!("Failed to parse line: {}", e));
  119. let mut max_red = 0;
  120. let mut max_green = 0;
  121. let mut max_blue = 0;
  122. for draw in &game.draws {
  123. if draw.red_count > max_red {
  124. max_red = draw.red_count;
  125. }
  126. if draw.green_count > max_green {
  127. max_green = draw.green_count;
  128. }
  129. if draw.blue_count > max_blue {
  130. max_blue = draw.blue_count;
  131. }
  132. }
  133. result += max_red * max_green * max_blue;
  134. }
  135. println!("{}", result);
  136. }