[rust] Solve Day 2
This commit is contained in:
parent
0f431e9e3f
commit
a2637587e9
|
@ -6,6 +6,9 @@ case "$1" in
|
||||||
"day1")
|
"day1")
|
||||||
"$SCRIPT_DIR/day1.sh"
|
"$SCRIPT_DIR/day1.sh"
|
||||||
;;
|
;;
|
||||||
|
"day2")
|
||||||
|
"$SCRIPT_DIR/day2.sh"
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Invalid day"
|
echo "Invalid day"
|
||||||
exit 1
|
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;
|
use std::env;
|
||||||
|
|
||||||
mod day1;
|
mod day1;
|
||||||
|
mod day2;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut args = env::args();
|
let mut args = env::args();
|
||||||
|
@ -9,6 +10,7 @@ fn main() {
|
||||||
match day {
|
match day {
|
||||||
Some(x) => match x.as_str() {
|
Some(x) => match x.as_str() {
|
||||||
"day1" => day1::run(),
|
"day1" => day1::run(),
|
||||||
|
"day2" => day2::run(),
|
||||||
_ => todo!()
|
_ => todo!()
|
||||||
},
|
},
|
||||||
_ => println!("Please provide the day as day<n>"),
|
_ => println!("Please provide the day as day<n>"),
|
||||||
|
|
Loading…
Reference in a new issue