Refactoring

Signed-off-by: TuDatTr <tuan-dat.tran@tudattr.dev>
main
TuDatTr 2022-12-02 00:58:50 +01:00
parent 5b22965ad3
commit 81decee6a9
4 changed files with 87 additions and 85 deletions

View File

@ -1,2 +1,4 @@
# Calorie Counting
Usage: `cargo run --release -- --input <Path to file with inputs` ## Usage
`cargo run --release -- --input <Path to file with inputs>`

View File

@ -1,46 +1,18 @@
use calorie_counting_lib::*; use calorie_counting_lib::{task_1a, task_1b};
use std::path::PathBuf;
use std::collections::BinaryHeap;
use clap::Parser; use clap::Parser;
use tracing::{info, debug}; use tracing::{info, debug};
use crate::cli::Cli;
mod cli; mod cli;
use crate::cli::Cli;
/// Finds the Elf carrying the most Calories.
/// Outputs how many total Calories that Elf is carrying.
fn task_1a(input: &PathBuf) {
debug!("Running task 1a");
let file_path = input;
let content = calorie_counting_lib::read_file(file_path).unwrap();
let splits = content.split("\n\n");
println!("{}", splits.map(|s| Elf::new(s).total_calories()).max().unwrap());
}
/// Finds the top three Elves carrying the most Calories.
/// Outputs how many Calories those Elves are carrying in total.
fn task_1b(input: &PathBuf) {
debug!("Running task 1b");
let file_path = input;
let content = calorie_counting_lib::read_file(file_path).unwrap();
let splits = content.split("\n\n");
let mut heap = splits.map(|s| Elf::new(s).total_calories()).collect::<BinaryHeap<_>>();
let mut top_three = Vec::new();
for _ in 0..3 {
if let Some(c) = heap.pop() {
top_three.push(c);
}
}
println!("{}", top_three.iter().sum::<u64>());
}
pub fn main() { pub fn main() {
tracing_subscriber::fmt::init(); tracing_subscriber::fmt::init();
debug!("Running with debugging level logging"); debug!("Running with DEBUG logging");
info!("Running with INFO logging");
let args = Cli::parse(); let args = Cli::parse();
debug!("{:#?}", args);
task_1a(&args.input); task_1a(&args.input);
task_1b(&args.input); task_1b(&args.input);
} }

View File

@ -0,0 +1,30 @@
use std::fmt;
#[derive(Debug, Clone)]
pub struct Elf {
_input: String,
calories: Vec<u64>,
}
impl Elf {
pub fn new(input: &str) -> Self {
let cal: Vec<u64> = input
.split('\n')
.map(|i| i.parse::<u64>().unwrap())
.collect();
Self {
_input: input.to_string(),
calories: cal,
}
}
pub fn total_calories(self) -> u64 {
self.calories.iter().sum()
}
}
impl fmt::Display for Elf {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Elf: {:?}", self.calories)
}
}

View File

@ -1,52 +1,64 @@
use std::fs::File; use std::fs::File;
use std::io::{Write, Read}; use std::io::{Read, Write};
use std::path::Path; use std::path::{Path, PathBuf};
use std::fmt; use std::collections::BinaryHeap;
use tracing::{info, debug}; use tracing::{debug, info};
mod elf;
use crate::elf::Elf;
#[allow(dead_code)]
fn create_file(path: &Path, content: String) {
info!("Creating file");
debug!("Writing file from: {:?}\nWith:\n{}", path, content);
pub fn create_file(path: &Path, content: String) {
debug!("Creating file");
let mut file = File::create(path).unwrap(); let mut file = File::create(path).unwrap();
let _ = file.write_all(content.as_bytes()); let _ = file.write_all(content.as_bytes());
} }
pub fn read_file(path: &Path) -> std::io::Result<String> { #[allow(dead_code)]
debug!("Reading file"); fn read_file(path: &Path) -> std::io::Result<String> {
info!("Reading file");
debug!("Reading file from: {:?}", path);
let mut file = File::open(path)?; let mut file = File::open(path)?;
let mut contents = String::new(); let mut contents = String::new();
let _ = file.read_to_string(&mut contents)?; let _ = file.read_to_string(&mut contents)?;
Ok(contents.trim().to_string()) Ok(contents.trim().to_string())
} }
#[derive(Debug, Clone)] /// Finds the Elf carrying the most Calories.
pub struct Elf { /// Outputs how many total Calories that Elf is carrying.
_input: String, #[allow(dead_code)]
calories: Vec<u64>, pub fn task_1a(input: &PathBuf) {
debug!("Running task 1a");
info!("Running task 1a with {:?}", input);
let content = read_file(input).unwrap();
let splits = content.split("\n\n");
println!("Result (1a): {}", splits.map(|s| Elf::new(s).total_calories()).max().unwrap());
} }
impl Elf { /// Finds the top three Elves carrying the most Calories.
pub fn new (input: &str) -> Self { /// Outputs how many Calories those Elves are carrying in total.
let cal: Vec<u64> = input.split('\n') #[allow(dead_code)]
.map(|i| i.parse::<u64>().unwrap()) pub fn task_1b(input: &PathBuf) {
.collect(); debug!("Running task 1b");
Self { _input: input.to_string(), calories: cal } info!("Running task 1b with {:?}", input);
}
pub fn total_calories(self) -> u64 { let content = read_file(input).unwrap();
self.calories.iter().sum() let splits = content.split("\n\n");
let mut heap = splits.map(|s| Elf::new(s).total_calories()).collect::<BinaryHeap<_>>();
let mut sum = 0u64;
for _ in 0..3 {
if let Some(c) = heap.pop() {
sum += c;
}
} }
println!("Result (1b): {}", sum);
} }
impl fmt::Display for Elf{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Elf: {:?}", self.calories)
}
}
// pub fn get_calories() -> std::io::Result<Vec<Elf>> {
// let content = read_file(Path::new("input.txt"))?;
// }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -54,7 +66,8 @@ mod tests {
use std::str::from_utf8; use std::str::from_utf8;
const PATH: &str = "input.txt"; const PATH: &str = "input.txt";
const CONTENT: &[u8; 55] = b"1000\n2000\n3000\n\n4000\n\n5000\n6000\n\n7000\n8000\n9000\n\n10000\n"; const CONTENT: &[u8; 55] =
b"1000\n2000\n3000\n\n4000\n\n5000\n6000\n\n7000\n8000\n9000\n\n10000\n";
fn create_test_setup() { fn create_test_setup() {
let file_path = Path::new(PATH); let file_path = Path::new(PATH);
@ -63,29 +76,14 @@ mod tests {
} }
fn cleanup_test_setup() { fn cleanup_test_setup() {
let _ = remove_file(&Path::new(PATH)); let _ = remove_file(Path::new(PATH));
} }
/// Test if we corretly read file input. /// Test if we corretly read file input.
#[test] #[test]
fn file_io() { fn file_io() {
create_test_setup(); create_test_setup();
let content = read_file(&Path::new(PATH)); let content = read_file(Path::new(PATH));
cleanup_test_setup();
assert_eq!(from_utf8(CONTENT).unwrap(), content.unwrap().to_string());
}
/// Test if the calculation of calories each elf is carrying is correct.
#[test]
fn elf_calories() {
create_test_setup();
let content = read_file(&Path::new(PATH)).unwrap();
let file_path = Path::new("input.txt");
let content = calorie_counting_lib::read_file(file_path).unwrap();
let splits = content.split("\n\n");
let result_vec = Vec::<u64>::new();
for elf in splits.map(|s| Elf::new(s)) {
result_vec.push(elf.total_calories());
}
cleanup_test_setup(); cleanup_test_setup();
assert_eq!(from_utf8(CONTENT).unwrap(), content.unwrap());
} }
} }