diff --git a/bash/main.sh b/bash/main.sh index 7fcf9de..d5f2336 100755 --- a/bash/main.sh +++ b/bash/main.sh @@ -6,6 +6,9 @@ case "$1" in "day1") "$SCRIPT_DIR/day1.sh" ;; + "day2") + "$SCRIPT_DIR/day2.sh" + ;; *) echo "Invalid day" exit 1 diff --git a/rust/src/day2.rs b/rust/src/day2.rs new file mode 100644 index 0000000..f417d53 --- /dev/null +++ b/rust/src/day2.rs @@ -0,0 +1,170 @@ +use std::io; +use std::io::Read; +use std::str::FromStr; + +pub fn run() { + let mut bytes: Vec = Vec::new(); + let read_result = io::stdin().read_to_end(&mut bytes); + match read_result { + Err(e) => println!("Error while reading input: {}", e), + Ok(_) => { + let input = String::from_utf8(bytes).unwrap(); + match parse_games(&input) { + Err(e) => println!("Parsing input failed: {}", e), + Ok(games) => { + println!("Part 1 Answer: {}", part1(games.clone())); + println!("Part 2 Answer: {}", part2(games)); + } + } + } + } +} + +fn part1(games: Vec) -> u32 { + games + .into_iter() + .filter(|g| is_game_possible(g)) + .map(|g| g.id) + .sum() +} + +fn is_game_possible(game: &Game) -> bool { + let revs: &Vec = game.revelations.as_ref(); + revs.into_iter() + .all(|rev| rev.reds <= 12 && rev.greens <= 13 && rev.blues <= 14) +} + +fn part2(games: Vec) -> u32 { + games.into_iter().map(|g| power(g)).sum() +} + +fn power(game: Game) -> u32 { + let revs: &Vec = game.revelations.as_ref(); + let max_reds = revs + .into_iter() + .max_by(|r1, r2| r1.reds.cmp(&r2.reds)) + .unwrap() + .reds; + let max_greens = revs + .into_iter() + .max_by(|r1, r2| r1.greens.cmp(&r2.greens)) + .unwrap() + .greens; + let max_blues = revs + .into_iter() + .max_by(|r1, r2| r1.blues.cmp(&r2.blues)) + .unwrap() + .blues; + max_reds * max_greens * max_blues +} + +#[derive(Clone)] +struct ColourRevelation { + count: u32, + colour: String, +} + +impl FromStr for ColourRevelation { + type Err = String; + + fn from_str(s: &str) -> Result { + let splits: Vec<&str> = s.split(' ').collect(); + match splits.as_slice() { + [num, colour] => num + .parse() + .map_err(|e| format!("Invalid count: {}", e)) + .and_then(|c| { + Ok(ColourRevelation { + count: c, + colour: String::from_str(colour).unwrap(), + }) + }), + _ => Err(format!("Invalid revelation: {}", s)), + } + } +} + +#[derive(Clone)] +struct Revelation { + reds: u32, + greens: u32, + blues: u32, +} + +impl FromStr for Revelation { + type Err = String; + + fn from_str(s: &str) -> Result { + let revelation_results: Vec<_> = s.split(", ").map(ColourRevelation::from_str).collect(); + let revelations_result = traverse_results(revelation_results); + revelations_result.and_then(|revelations| { + let reds = extract_colour(revelations.clone(), String::from("red")); + let greens = extract_colour(revelations.clone(), String::from("green")); + let blues = extract_colour(revelations, String::from("blue")); + Ok(Revelation { + reds, + greens, + blues, + }) + }) + } +} + +fn extract_colour(revelations: Vec, colour: String) -> u32 { + revelations + .into_iter() + .find(|r| r.colour == colour) + .map(|r| r.count) + .unwrap_or(0) +} + +#[derive(Clone)] +struct Game { + id: u32, + revelations: Vec, +} + +impl FromStr for Game { + type Err = String; + + fn from_str(s: &str) -> Result { + let splits: Vec<&str> = s.split(": ").collect(); + match splits.as_slice() { + [game, revelations_str] => { + let game_id_result: Result = game + .replace("Game ", "") + .parse() + .map_err(|e| format!("Invalid game id: {}", e)); + let revelations_results: Vec> = + revelations_str.split("; ").map(|x| x.parse()).collect(); + game_id_result.and_then(|id| { + traverse_results(revelations_results) + .and_then(|revelations| Ok(Game { id, revelations })) + }) + } + _ => Err(format!("Invalid Game: {}", s)), + } + } +} + +fn parse_games(s: &str) -> Result, String> { + traverse_results(s.split('\n').map(Game::from_str).collect()) +} + +// Me: Mom, can we have travese. +// Mom: We got traverse at home. +// Traverse at home: +fn traverse_results(results: Vec>) -> Result, B> +where + Vec: Clone, +{ + results.into_iter().fold(Ok(Vec::new()), |acc, res| { + acc.and_then(|vec| { + res.and_then(|r| { + let mut vectemp = vec.clone(); + vectemp.push(r); + Ok(vectemp) + }) + }) + }) +} diff --git a/rust/src/main.rs b/rust/src/main.rs index b75fa4c..7bc68ae 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -1,6 +1,7 @@ use std::env; mod day1; +mod day2; fn main() { let mut args = env::args(); @@ -9,6 +10,7 @@ fn main() { match day { Some(x) => match x.as_str() { "day1" => day1::run(), + "day2" => day2::run(), _ => todo!() }, _ => println!("Please provide the day as day"),