[rust] Solve Day 2
This commit is contained in:
parent
0f431e9e3f
commit
a2637587e9
|
@ -6,6 +6,9 @@ case "$1" in
|
|||
"day1")
|
||||
"$SCRIPT_DIR/day1.sh"
|
||||
;;
|
||||
"day2")
|
||||
"$SCRIPT_DIR/day2.sh"
|
||||
;;
|
||||
*)
|
||||
echo "Invalid day"
|
||||
exit 1
|
||||
|
|
170
rust/src/day2.rs
Normal file
170
rust/src/day2.rs
Normal file
|
@ -0,0 +1,170 @@
|
|||
use std::io;
|
||||
use std::io::Read;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub fn run() {
|
||||
let mut bytes: Vec<u8> = 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<Game>) -> 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<Revelation> = game.revelations.as_ref();
|
||||
revs.into_iter()
|
||||
.all(|rev| rev.reds <= 12 && rev.greens <= 13 && rev.blues <= 14)
|
||||
}
|
||||
|
||||
fn part2(games: Vec<Game>) -> u32 {
|
||||
games.into_iter().map(|g| power(g)).sum()
|
||||
}
|
||||
|
||||
fn power(game: Game) -> u32 {
|
||||
let revs: &Vec<Revelation> = 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<Self, Self::Err> {
|
||||
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<Self, Self::Err> {
|
||||
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<ColourRevelation>, 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<Revelation>,
|
||||
}
|
||||
|
||||
impl FromStr for Game {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let splits: Vec<&str> = s.split(": ").collect();
|
||||
match splits.as_slice() {
|
||||
[game, revelations_str] => {
|
||||
let game_id_result: Result<u32, _> = game
|
||||
.replace("Game ", "")
|
||||
.parse()
|
||||
.map_err(|e| format!("Invalid game id: {}", e));
|
||||
let revelations_results: Vec<Result<Revelation, _>> =
|
||||
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<Vec<Game>, 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<A, B>(results: Vec<Result<A, B>>) -> Result<Vec<A>, B>
|
||||
where
|
||||
Vec<A>: 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)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
|
@ -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<n>"),
|
||||
|
|
Loading…
Reference in a new issue