153 lines
3.7 KiB
Rust
153 lines
3.7 KiB
Rust
|
use std::cmp::Ordering;
|
||
|
use std::str::FromStr;
|
||
|
|
||
|
fn main() {
|
||
|
|
||
|
let mut input_file = Some("input".to_string());
|
||
|
let mut args = std::env::args();
|
||
|
while args.len() > 0 {
|
||
|
let arg = args.nth(0);
|
||
|
if arg.unwrap().eq("-f") {
|
||
|
let value = args.nth(0);
|
||
|
if value.is_some() {
|
||
|
input_file = value;
|
||
|
}
|
||
|
else {
|
||
|
println!("No value after argument: '-f'");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
println!("Input file: '{:?}'", input_file);
|
||
|
let mut elves = elves_from_file(&input_file.unwrap()).expect("failed to read file");
|
||
|
elves.sort_by(|a, b| b.cmp_by_calories(a));
|
||
|
println!("[PART 1] Elf with most calories: {}", elves[0].calories());
|
||
|
|
||
|
let p2_elves: std::vec::Vec::<_> = elves.into_iter()
|
||
|
.enumerate()
|
||
|
.filter(|&(i, _)| i < 3 )
|
||
|
.map(|(_, e)| e)
|
||
|
.collect();
|
||
|
let mut p2_calories: u32 = 0;
|
||
|
for x in p2_elves {
|
||
|
p2_calories += x.calories();
|
||
|
}
|
||
|
println!("[PART 2] Top 3 elves have these calories: {}", p2_calories);
|
||
|
}
|
||
|
|
||
|
struct Elf {
|
||
|
items: std::vec::Vec<u32>,
|
||
|
}
|
||
|
|
||
|
impl Elf {
|
||
|
fn calories(&self) -> u32 {
|
||
|
let mut value = 0;
|
||
|
for x in &self.items {
|
||
|
value += x;
|
||
|
}
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
fn cmp_by_calories(&self, b: &Elf) -> Ordering {
|
||
|
return self.calories().cmp(&b.calories());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn elves_from_file(file_name: &String) -> std::result::Result<std::vec::Vec::<Elf>, String> {
|
||
|
let contents = std::fs::read_to_string(file_name).expect("Couldn't read contents of file");
|
||
|
return std::result::Result::Ok(elves_from_string(&contents));
|
||
|
}
|
||
|
|
||
|
fn elves_from_string(contents: &String) -> std::vec::Vec::<Elf> {
|
||
|
let mut elves = std::vec::Vec::<Elf>::new();
|
||
|
let mut current_elf = Elf {
|
||
|
items: std::vec::Vec::<u32>::new(),
|
||
|
};
|
||
|
for line in contents.lines() {
|
||
|
if line.eq("") {
|
||
|
elves.push(current_elf);
|
||
|
current_elf = Elf {
|
||
|
items: std::vec::Vec::<u32>::new(),
|
||
|
};
|
||
|
}
|
||
|
else {
|
||
|
match u32::from_str(&line) {
|
||
|
Ok(v) => {
|
||
|
current_elf.items.push(v);
|
||
|
},
|
||
|
Err(_) => {
|
||
|
println!("WARNING: '{}' does not convert to u32, skipping.", line);
|
||
|
continue;
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if current_elf.items.len() > 0 {
|
||
|
elves.push(current_elf);
|
||
|
}
|
||
|
return elves;
|
||
|
}
|
||
|
|
||
|
#[cfg(test)]
|
||
|
mod tests {
|
||
|
use super::*;
|
||
|
|
||
|
#[test]
|
||
|
fn test_from_empty_string() {
|
||
|
let contents = "".to_string();
|
||
|
let elves = elves_from_string(&contents);
|
||
|
assert_eq!(elves.len(), 0);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_from_string() {
|
||
|
let contents = r#"1000
|
||
|
2000
|
||
|
3000
|
||
|
|
||
|
4000
|
||
|
|
||
|
5000
|
||
|
6000
|
||
|
|
||
|
7000
|
||
|
8000
|
||
|
9000
|
||
|
|
||
|
10000
|
||
|
"#.to_string();
|
||
|
let elves = elves_from_string(&contents);
|
||
|
assert_eq!(elves.len(), 5);
|
||
|
let first = vec![1000, 2000, 3000];
|
||
|
assert!(first.eq(&elves[0].items));
|
||
|
let last = vec![10000];
|
||
|
assert!(last.eq(&elves[4].items));
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_calories() {
|
||
|
let mut elf = Elf {
|
||
|
items: std::vec::Vec::<u32>::new(),
|
||
|
};
|
||
|
assert_eq!(elf.calories(), 0);
|
||
|
|
||
|
elf.items.push(1000);
|
||
|
elf.items.push(10000);
|
||
|
|
||
|
assert_eq!(elf.calories(), 11000);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_sort() {
|
||
|
let mut v = std::vec::Vec::<Elf>::new();
|
||
|
v.push(Elf {
|
||
|
items: vec![5000, 50000],
|
||
|
});
|
||
|
v.push(Elf {
|
||
|
items: vec![1000, 10000],
|
||
|
});
|
||
|
assert_eq!(v[0].calories(), 55000);
|
||
|
v.sort_by(|a, b| a.cmp_by_calories(b));
|
||
|
assert_eq!(v[0].calories(), 11000);
|
||
|
}
|
||
|
}
|