diff --git a/Cargo.lock b/Cargo.lock index 3712aab..9929827 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,8 +8,15 @@ version = "0.1.0" dependencies = [ "colored", "figlet-rs", + "tabled", ] +[[package]] +name = "bytecount" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" + [[package]] name = "colored" version = "2.1.0" @@ -26,12 +33,129 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4742a071cd9694fc86f9fa1a08fa3e53d40cc899d7ee532295da2d085639fbc5" +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "papergrid" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7419ad52a7de9b60d33e11085a0fe3df1fbd5926aa3f93d3dd53afbc9e86725" +dependencies = [ + "bytecount", + "fnv", + "unicode-width", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tabled" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c9303ee60b9bedf722012ea29ae3711ba13a67c9b9ae28993838b63057cb1b" +dependencies = [ + "papergrid", + "tabled_derive", +] + +[[package]] +name = "tabled_derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf0fb8bfdc709786c154e24a66777493fb63ae97e3036d914c8666774c477069" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index ea1939b..3b84382 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] figlet-rs = "0.1.5" colored = "2" +tabled = "0.16.0" [package.metadata.generate-rpm] name = "betting_odds_converter" diff --git a/src/betting_odds_calculator.rs b/src/betting_odds_calculator.rs index 7e2d4e5..01fbf2f 100644 --- a/src/betting_odds_calculator.rs +++ b/src/betting_odds_calculator.rs @@ -1,8 +1,8 @@ use std::io; use colored::* ; -use crate::prob_functions; +use crate::{prob_functions, utils}; -pub fn decimal_prob_calc() { +pub fn decimal_prob_calc(wager: f64) { println!("{}", "Enter the Decimal Odds: ".blue()); let mut user_entered_decimal_value = String::new(); @@ -13,9 +13,12 @@ pub fn decimal_prob_calc() { match user_entered_decimal_value.trim().parse::() { Ok(value) => { - println!("{}", "Calculating the Odds...".green()); + println!("{}", "Calculating the Values...".green()); let prob : f32 = prob_functions::decimal_prob(value); - println!("{}", format!("The Implied Probability is {}%", prob).green()); + let payout : f64 = prob_functions::calculate_payout(prob, wager); + let return_on_bet : f64 = prob_functions::calculate_percentage_return(payout, wager); + + utils::display_metrics_table(prob as f64, payout, return_on_bet); } Err(_) => { @@ -24,7 +27,7 @@ pub fn decimal_prob_calc() { } } -pub fn money_prob_calc() { +pub fn money_prob_calc(wager: f64) { println!("{}", "Enter the Moneyline: ".blue()); let mut user_entered_moneyline_value: String = String::new(); @@ -35,9 +38,12 @@ pub fn money_prob_calc() { match user_entered_moneyline_value.trim().parse::() { Ok(value) => { - println!("{}", "Calculating the Odds...".green()); + println!("{}", "Calculating the Values...".green()); let prob : f32 = prob_functions::moneyline_prob(value); - println!("{}", format!("The Implied Probability is {}%", prob).green()); + let payout : f64 = prob_functions::calculate_payout(prob, wager); + let return_on_bet : f64 = prob_functions::calculate_percentage_return(payout, wager); + + utils::display_metrics_table(prob as f64, payout, return_on_bet); } Err(_) => { @@ -46,7 +52,7 @@ pub fn money_prob_calc() { } } -pub fn fraction_prob_calc() { +pub fn fraction_prob_calc(wager: f64) { println!("{}", "Enter the Fractional Odds (e.g., 3/4): ".blue()); let mut user_entered_fraction = String::new(); @@ -62,9 +68,13 @@ pub fn fraction_prob_calc() { if parts.len() == 2 { match (parts[0].trim().parse::(), parts[1].trim().parse::()) { (Ok(numerator), Ok(denominator)) if denominator != 0.0 => { + println!("{}", "Calculating the Values...".green()); let value = numerator / denominator; let prob: f32 = prob_functions::fraction_prob(value); - println!("{}", format!("The Implied Probability is {}%", prob).green()); + let payout : f64 = prob_functions::calculate_payout(prob, wager); + let return_on_bet : f64 = prob_functions::calculate_percentage_return(payout, wager); + + utils::display_metrics_table(prob as f64, payout, return_on_bet); } _ => { println!("{}", "Invalid fraction entered. Please try again.".red()); diff --git a/src/main.rs b/src/main.rs index b63db86..2c30264 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,10 +15,12 @@ fn main() { print!("{}", welcome_note.unwrap()); println!("{}", "Calculates Implied Probability".blue()); + let mut wager = utils::get_wager(); + let mut exit: bool = false; while !exit { - + let mut num = String::new(); utils::display_main_menu(); @@ -27,9 +29,19 @@ fn main() { .read_line(&mut num) .expect("Failed to read the number"); - utils::which_calc_decider(&num.trim().parse::()); + let parsed_num = num.trim().parse::(); + + match parsed_num { + Ok(value) => { + utils::which_calc_decider(value, wager); + }, + Err(_) => { + println!("Invalid number! Please try again."); + } + + }; - println!("Press 'x' to exit or any other key to continue: "); + println!("Press 'x' to exit, 'c' to change the wager or any other key to continue: "); let mut final_call = String::new(); io::stdin() @@ -38,6 +50,8 @@ fn main() { if final_call.trim().eq_ignore_ascii_case("x") { exit = true; - } + } else if final_call.trim().eq_ignore_ascii_case("c") { + wager = utils::get_wager(); + } } } \ No newline at end of file diff --git a/src/prob_functions.rs b/src/prob_functions.rs index 4f5721e..26b31fd 100644 --- a/src/prob_functions.rs +++ b/src/prob_functions.rs @@ -23,6 +23,16 @@ pub fn fraction_prob(fractions: f32) -> f32 { calculate_prob(fractions) } +pub fn calculate_payout(implied_prob : f32, wager: f64) -> f64 { + let odds : f64 = (1.0 / (implied_prob as f64)) * 100.0 ; + + odds * wager +} + +pub fn calculate_percentage_return(payout: f64, wager: f64) -> f64 { + let return_percentage = ((payout - wager) / wager) * 100.0; + return return_percentage +} #[cfg(test)] diff --git a/src/utils.rs b/src/utils.rs index 8dfda73..ae1e07b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,19 +1,19 @@ use crate::betting_odds_calculator; -use std::num::ParseIntError; use colored::*; +use std::io; +use tabled::{ settings::{style::Style, themes::Theme, Color}, + Tabled, Table}; -pub fn which_calc_decider(choice: &Result) { +pub fn which_calc_decider(choice: i32, wager: f64) { match choice { - Ok(value) => match value { - 1 => betting_odds_calculator::money_prob_calc(), - 2 => betting_odds_calculator::decimal_prob_calc(), - 3 => betting_odds_calculator::fraction_prob_calc(), - _ => println!("Please choose a valid option between 1-3."), - }, - Err(_) => println!("Invalid number! Please try again."), + 1 => betting_odds_calculator::money_prob_calc(wager), + 2 => betting_odds_calculator::decimal_prob_calc(wager), + 3 => betting_odds_calculator::fraction_prob_calc(wager), + _ => println!("Please choose a valid option between 1-3."), } } + pub fn display_main_menu() { let odds = vec![ "Moneyline to Implied probability", @@ -25,4 +25,54 @@ pub fn display_main_menu() { for (index, odd) in odds.iter().enumerate() { println!("{}. {}", index + 1, odd); } +} + +pub fn get_wager() -> f64 { + println!("Enter your wager (Default is 100): "); + + let mut wager = String::new(); + io::stdin().read_line(&mut wager).expect("Failed to read the number"); + + match wager.trim().parse::() { + Ok(value) => value, + Err(_) => { + println!("Invalid input, using default wager of 100"); + 100.0 + } + } +} + +#[derive(Tabled)] +struct MetricRow { + metric: &'static str, + value: String, +} + +pub fn display_metrics_table(implied_prob: f64, payout: f64, return_percentage: f64) { + let metrics = vec![ + MetricRow { metric: "Implied Probability (%)", value: format!("{:.2}",implied_prob) }, + MetricRow { metric: "Payout", value: format!("{:.2}", payout) }, + MetricRow { metric: "Return (%)", value: format!("{:.2}", return_percentage) }, + ]; + + let mut style = Theme::from(Style::extended()); + style.set_colors_top(Color::FG_RED); + style.set_colors_bottom(Color::FG_CYAN); + style.set_colors_left(Color::FG_BLUE); + style.set_colors_right(Color::FG_GREEN); + style.set_colors_corner_top_left(Color::FG_BLUE); + style.set_colors_corner_top_right(Color::FG_RED); + style.set_colors_corner_bottom_left(Color::FG_CYAN); + style.set_colors_corner_bottom_right(Color::FG_GREEN); + style.set_colors_intersection_bottom(Color::FG_CYAN); + style.set_colors_intersection_top(Color::FG_RED); + style.set_colors_intersection_right(Color::FG_GREEN); + style.set_colors_intersection_left(Color::FG_BLUE); + style.set_colors_intersection(Color::FG_MAGENTA); + style.set_colors_horizontal(Color::FG_MAGENTA); + style.set_colors_vertical(Color::FG_MAGENTA); + + let table = Table::new(metrics).with(style).to_string(); + + println!("{table}") } \ No newline at end of file