From 65328e41d00a80b2130b04e4306e3366eabf9ad1 Mon Sep 17 00:00:00 2001 From: Aras14HD Date: Tue, 13 Jan 2026 20:57:36 +0100 Subject: [PATCH 1/6] add tuple names up to 999999 --- factorion-lib/src/calculation_results.rs | 56 +++++++++++++++++++++--- factorion-lib/tests/integration.rs | 4 +- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/factorion-lib/src/calculation_results.rs b/factorion-lib/src/calculation_results.rs index ea4400f..6b35044 100644 --- a/factorion-lib/src/calculation_results.rs +++ b/factorion-lib/src/calculation_results.rs @@ -435,7 +435,31 @@ impl Calculation { "", "mill", "bill", "trill", "quadrill", "quintill", "sextill", "septill", "octill", "nonill", ]; - const BINDING_T: [[bool; 10]; 4] = [ + const TEN_THOUSANDS: [&str; 10] = [ + "", + "decill", + "vigintill", + "trigintill", + "quadragintill", + "quinquagintill", + "sexagintill", + "septuagintill", + "octogintill", + "nonagintill", + ]; + const HUNDRED_THOUSANDS: [&str; 10] = [ + "", + "centill", + "ducentill", + "tricentill", + "quadringentill", + "quingentill", + "sescentill", + "septingentill", + "octingentill", + "nongentill", + ]; + const BINDING_T: [[bool; 10]; 6] = [ // Singles [ false, false, false, false, false, false, false, false, false, false, @@ -448,6 +472,14 @@ impl Calculation { [ false, false, false, false, false, false, false, false, false, false, ], + // Tenthousands + [ + false, false, false, false, false, false, false, false, false, false, + ], + // Hundredthousands + [ + false, false, false, false, false, false, false, false, false, false, + ], ]; if let Some(s) = locale.num_overrides().get(&level) { return s.as_ref().into(); @@ -455,7 +487,7 @@ impl Calculation { match level { 0 => locale.sub().as_ref().into(), 1 => "{factorial}".into(), - ..=9999 if !locale.force_num() => { + ..=999999 if !locale.force_num() => { let singles = if level < 10 { SINGLES_LAST } else { SINGLES }; let mut acc = String::new(); let mut n = level; @@ -469,9 +501,15 @@ impl Calculation { n /= 10; acc.write_str(HUNDREDS[h as usize]).unwrap(); let th = n % 10; + n /= 10; acc.write_str(THOUSANDS[th as usize]).unwrap(); + let tth = n % 10; + n /= 10; + acc.write_str(TEN_THOUSANDS[tth as usize]).unwrap(); + let hth = n % 10; + acc.write_str(HUNDRED_THOUSANDS[hth as usize]).unwrap(); // Check if we need tuple not uple - let last_written = [s, t, h, th] + let last_written = [s, t, h, th, tth, hth] .iter() .cloned() .enumerate() @@ -724,8 +762,16 @@ mod tests { "unvigintricenquadrilluple-{factorial}" ); assert_eq!( - Calculation::get_factorial_level_string(10000, &en.format()), - "10000-{factorial}" + Calculation::get_factorial_level_string(89342, &en.format()), + "duoquadragintricennonilloctogintilluple-{factorial}" + ); + assert_eq!( + Calculation::get_factorial_level_string(654321, &en.format()), + "unvigintricenquadrillquinquagintillsescentilluple-{factorial}" + ); + assert_eq!( + Calculation::get_factorial_level_string(1000000, &en.format()), + "1000000-{factorial}" ); let de = locale::get_de(); assert_eq!( diff --git a/factorion-lib/tests/integration.rs b/factorion-lib/tests/integration.rs index 6642b4a..5e5c67a 100644 --- a/factorion-lib/tests/integration.rs +++ b/factorion-lib/tests/integration.rs @@ -1024,7 +1024,7 @@ fn test_get_reply_for_high_multifactorial() { meta: (), calculation_list: vec![Calculation { value: 10.into(), - steps: vec![(12345, false)], + steps: vec![(1234567, false)], result: CalculationResult::Exact(Integer::from(10)), }], notify: None, @@ -1037,7 +1037,7 @@ fn test_get_reply_for_high_multifactorial() { let reply = comment.get_reply(&consts); assert_eq!( reply, - "12345-factorial of 10 is 10 \n\n\n*^(This action was performed by a bot | [Source code](http://f.r0.fyi))*" + "1234567-factorial of 10 is 10 \n\n\n*^(This action was performed by a bot | [Source code](http://f.r0.fyi))*" ); } From f7c1121e0061c73b7cd8b4dd615d8936823a70d2 Mon Sep 17 00:00:00 2001 From: Aras14HD Date: Fri, 27 Feb 2026 19:27:51 +0100 Subject: [PATCH 2/6] bump version minor --- Cargo.lock | 6 +++--- factorion-bot-discord/Cargo.toml | 4 ++-- factorion-bot-reddit/Cargo.toml | 4 ++-- factorion-lib/Cargo.toml | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 44a0500..97f87dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -399,7 +399,7 @@ dependencies = [ [[package]] name = "factorion-bot-discord" -version = "2.3.0" +version = "2.4.0" dependencies = [ "anyhow", "dotenvy", @@ -414,7 +414,7 @@ dependencies = [ [[package]] name = "factorion-bot-reddit" -version = "5.4.0" +version = "5.5.0" dependencies = [ "anyhow", "base64 0.22.1", @@ -434,7 +434,7 @@ dependencies = [ [[package]] name = "factorion-lib" -version = "4.3.0" +version = "4.4.0" dependencies = [ "arbtest", "chrono", diff --git a/factorion-bot-discord/Cargo.toml b/factorion-bot-discord/Cargo.toml index ade4151..dc3805d 100644 --- a/factorion-bot-discord/Cargo.toml +++ b/factorion-bot-discord/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "factorion-bot-discord" -version = "2.3.0" +version = "2.4.0" edition = "2024" description = "factorion-bot (for factorials and related) on Discord" license = "MIT" @@ -10,7 +10,7 @@ keywords = ["factorial", "termial", "bot", "math", "discord"] categories = ["mathematics", "web-programming", "parser-implementations"] [dependencies] -factorion-lib = { path = "../factorion-lib", version = "4.3.0", features = ["serde", "influxdb"] } +factorion-lib = { path = "../factorion-lib", version = "4.4.0", features = ["serde", "influxdb"] } serenity = { version = "0.12", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "cache"] } tokio = { version = "1.48.0", features = ["macros", "rt-multi-thread", "time"] } dotenvy = "^0.15.7" diff --git a/factorion-bot-reddit/Cargo.toml b/factorion-bot-reddit/Cargo.toml index 5efe316..e9e7f72 100644 --- a/factorion-bot-reddit/Cargo.toml +++ b/factorion-bot-reddit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "factorion-bot-reddit" -version = "5.4.0" +version = "5.5.0" edition = "2024" description = "factorion-bot (for factorials and related) on Reddit" license = "MIT" @@ -10,7 +10,7 @@ keywords = ["factorial", "termial", "bot", "math"] categories = ["mathematics", "web-programming", "parser-implementations"] [dependencies] -factorion-lib = {path = "../factorion-lib", version = "4.3.0", features = ["serde", "influxdb"]} +factorion-lib = {path = "../factorion-lib", version = "4.4.0", features = ["serde", "influxdb"]} reqwest = { version = "0.12.28", features = ["json", "native-tls"], default-features = false } serde = { version = "1.0.219", default-features = false, features = ["derive"] } serde_json = "1.0.140" diff --git a/factorion-lib/Cargo.toml b/factorion-lib/Cargo.toml index 2c2a65a..f40cb22 100644 --- a/factorion-lib/Cargo.toml +++ b/factorion-lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "factorion-lib" -version = "4.3.0" +version = "4.4.0" edition = "2024" description = "A library used to create bots to recognize and calculate factorials and related concepts" license = "MIT" From 8a6d3a42d1715bf4d2311454af648c586a57b9cc Mon Sep 17 00:00:00 2001 From: Aras14HD Date: Wed, 14 Jan 2026 16:54:22 +0100 Subject: [PATCH 3/6] print number as word --- factorion-lib/src/calculation_results.rs | 407 ++++++++++++++--------- 1 file changed, 256 insertions(+), 151 deletions(-) diff --git a/factorion-lib/src/calculation_results.rs b/factorion-lib/src/calculation_results.rs index 6b35044..a48d3db 100644 --- a/factorion-lib/src/calculation_results.rs +++ b/factorion-lib/src/calculation_results.rs @@ -362,7 +362,7 @@ impl Calculation { acc, start, "{factorial}", - &Self::get_factorial_level_string(level.abs(), locale), + &get_factorial_level_string(level.abs(), locale), ); replace( @@ -397,139 +397,235 @@ impl Calculation { Ok(()) } +} +const SINGLES: [&str; 10] = [ + "", "un", "duo", "tre", "quattuor", "quin", "sex", "septen", "octo", "novem", +]; +const SINGLES_LAST: [&str; 10] = [ + "", "un", "du", "tr", "quadr", "quint", "sext", "sept", "oct", "non", +]; +const TENS: [&str; 10] = [ + "", + "dec", + "vigin", + "trigin", + "quadragin", + "quinquagin", + "sexagin", + "septuagin", + "octogin", + "nonagin", +]; +const HUNDREDS: [&str; 10] = [ + "", + "cen", + "ducen", + // Note this differs from the wikipedia list to disambiguate from 103, which continuing the pattern should be trecentuple + "tricen", + "quadringen", + "quingen", + "sescen", + "septingen", + "octingen ", + "nongen", +]; +// Note that other than milluple, these are not found in a list, but continue the pattern from mill with different starts +const THOUSANDS: [&str; 10] = [ + "", "mill", "bill", "trill", "quadrill", "quintill", "sextill", "septill", "octill", "nonill", +]; +const TEN_THOUSANDS: [&str; 10] = [ + "", + "decill", + "vigintill", + "trigintill", + "quadragintill", + "quinquagintill", + "sexagintill", + "septuagintill", + "octogintill", + "nonagintill", +]; +const HUNDRED_THOUSANDS: [&str; 10] = [ + "", + "centill", + "ducentill", + "tricentill", + "quadringentill", + "quingentill", + "sescentill", + "septingentill", + "octingentill", + "nongentill", +]; +const BINDING_T: [[bool; 10]; 6] = [ + // Singles + [ + false, false, false, false, false, false, false, false, false, false, + ], + // Tens + [false, false, true, true, true, true, true, true, true, true], + // Hundreds + [false, true, true, true, true, true, true, true, true, true], + // Thousands + [ + false, false, false, false, false, false, false, false, false, false, + ], + // Tenthousands + [ + false, false, false, false, false, false, false, false, false, false, + ], + // Hundredthousands + [ + false, false, false, false, false, false, false, false, false, false, + ], +]; +fn get_factorial_level_string<'a>(level: i32, locale: &'a locale::Format<'a>) -> Cow<'a, str> { + if let Some(s) = locale.num_overrides().get(&level) { + return s.as_ref().into(); + } + match level { + 0 => locale.sub().as_ref().into(), + 1 => "{factorial}".into(), + ..=999999 if !locale.force_num() => { + let singles = if level < 10 { SINGLES_LAST } else { SINGLES }; + let mut acc = String::new(); + let mut n = level; + let s = n % 10; + n /= 10; + acc.write_str(singles[s as usize]).unwrap(); + let t = n % 10; + n /= 10; + acc.write_str(TENS[t as usize]).unwrap(); + let h = n % 10; + n /= 10; + acc.write_str(HUNDREDS[h as usize]).unwrap(); + let th = n % 10; + n /= 10; + acc.write_str(THOUSANDS[th as usize]).unwrap(); + let tth = n % 10; + n /= 10; + acc.write_str(TEN_THOUSANDS[tth as usize]).unwrap(); + let hth = n % 10; + acc.write_str(HUNDRED_THOUSANDS[hth as usize]).unwrap(); + // Check if we need tuple not uple + let last_written = [s, t, h, th, tth, hth] + .iter() + .cloned() + .enumerate() + .rev() + .find(|(_, n)| *n != 0) + .unwrap(); + if BINDING_T[last_written.0][last_written.1 as usize] { + acc.write_str("t").unwrap(); + } + acc.write_str(locale.uple()).unwrap(); - fn get_factorial_level_string<'a>(level: i32, locale: &'a locale::Format<'a>) -> Cow<'a, str> { - const SINGLES: [&str; 10] = [ - "", "un", "duo", "tre", "quattuor", "quin", "sex", "septen", "octo", "novem", - ]; - const SINGLES_LAST: [&str; 10] = [ - "", "un", "du", "tr", "quadr", "quint", "sext", "sept", "oct", "non", - ]; - const TENS: [&str; 10] = [ - "", - "dec", - "vigin", - "trigin", - "quadragin", - "quinquagin", - "sexagin", - "septuagin", - "octogin", - "nonagin", - ]; - const HUNDREDS: [&str; 10] = [ - "", - "cen", - "ducen", - // Note this differs from the wikipedia list to disambiguate from 103, which continuing the pattern should be trecentuple - "tricen", - "quadringen", - "quingen", - "sescen", - "septingen", - "octingen", - "nongen", - ]; - // Note that other than milluple, these are not found in a list, but continue the pattern from mill with different starts - const THOUSANDS: [&str; 10] = [ - "", "mill", "bill", "trill", "quadrill", "quintill", "sextill", "septill", "octill", - "nonill", - ]; - const TEN_THOUSANDS: [&str; 10] = [ - "", - "decill", - "vigintill", - "trigintill", - "quadragintill", - "quinquagintill", - "sexagintill", - "septuagintill", - "octogintill", - "nonagintill", - ]; - const HUNDRED_THOUSANDS: [&str; 10] = [ - "", - "centill", - "ducentill", - "tricentill", - "quadringentill", - "quingentill", - "sescentill", - "septingentill", - "octingentill", - "nongentill", - ]; - const BINDING_T: [[bool; 10]; 6] = [ - // Singles - [ - false, false, false, false, false, false, false, false, false, false, - ], - // Tens - [false, false, true, true, true, true, true, true, true, true], - // Hundreds - [false, true, true, true, true, true, true, true, true, true], - // Thousands - [ - false, false, false, false, false, false, false, false, false, false, - ], - // Tenthousands - [ - false, false, false, false, false, false, false, false, false, false, - ], - // Hundredthousands - [ - false, false, false, false, false, false, false, false, false, false, - ], - ]; - if let Some(s) = locale.num_overrides().get(&level) { - return s.as_ref().into(); + acc.into() + } + _ => { + let mut suffix = String::new(); + write!(&mut suffix, "{level}-{{factorial}}").unwrap(); + suffix.into() + } + } +} +const EN_SINGLES: [&str; 10] = [ + "", "one ", "two ", "three ", "four ", "five ", "six ", "seven ", "eight ", "nine ", +]; +const EN_TENS: [&str; 10] = [ + "", "ten ", "twenty ", "thirty ", "fourty ", "fivety ", "sixty ", "seventy ", "eighty ", + "ninety ", +]; +const EN_TENS_SINGLES: [&str; 10] = [ + "ten ", + "eleven ", + "twelve ", + "thirteen ", + "fourteen ", + "fiveteen ", + "sixteen ", + "seventeen ", + "eighteen ", + "nineteen ", +]; +const SINGLES_LAST_ILLION: [&str; 10] = [ + "", "m", "b", "tr", "quadr", "quint", "sext", "sept", "oct", "non", +]; +fn write_out_number(acc: &mut String, num: &Integer, consts: &Consts) -> std::fmt::Result { + let num = Float::with_val(consts.float_precision, num); + let ten = Float::with_val(consts.float_precision, 10); + let digit_blocks = num + .clone() + .log10() + .to_u32_saturating_round(factorion_math::rug::float::Round::Down) + .unwrap() + / 3; + dbg!(digit_blocks); + for digit_blocks_left in (digit_blocks.saturating_sub(5)..=digit_blocks).rev() { + dbg!(digit_blocks_left); + let current_digits = Float::to_u32_saturating_round( + &((num.clone() / ten.clone().pow(digit_blocks_left * 3)) % 1000), + factorion_math::rug::float::Round::Down, + ) + .unwrap(); + dbg!(current_digits); + let mut n = current_digits; + let s = n % 10; + n /= 10; + let t = n % 10; + n /= 10; + let h = n % 10; + acc.write_str(EN_SINGLES[h as usize])?; + if h != 0 { + acc.write_str("hundred ")?; + } + if t == 1 { + acc.write_str(EN_TENS_SINGLES[s as usize])?; + } else { + acc.write_str(EN_TENS[t as usize])?; + acc.write_str(EN_SINGLES[s as usize])?; } - match level { - 0 => locale.sub().as_ref().into(), - 1 => "{factorial}".into(), - ..=999999 if !locale.force_num() => { - let singles = if level < 10 { SINGLES_LAST } else { SINGLES }; - let mut acc = String::new(); - let mut n = level; - let s = n % 10; - n /= 10; - acc.write_str(singles[s as usize]).unwrap(); - let t = n % 10; - n /= 10; - acc.write_str(TENS[t as usize]).unwrap(); - let h = n % 10; - n /= 10; - acc.write_str(HUNDREDS[h as usize]).unwrap(); - let th = n % 10; - n /= 10; - acc.write_str(THOUSANDS[th as usize]).unwrap(); - let tth = n % 10; - n /= 10; - acc.write_str(TEN_THOUSANDS[tth as usize]).unwrap(); - let hth = n % 10; - acc.write_str(HUNDRED_THOUSANDS[hth as usize]).unwrap(); - // Check if we need tuple not uple - let last_written = [s, t, h, th, tth, hth] - .iter() - .cloned() - .enumerate() - .rev() - .find(|(_, n)| *n != 0) - .unwrap(); - if BINDING_T[last_written.0][last_written.1 as usize] { - acc.write_str("t").unwrap(); - } - acc.write_str(locale.uple()).unwrap(); - acc.into() - } - _ => { - let mut suffix = String::new(); - write!(&mut suffix, "{level}-{{factorial}}").unwrap(); - suffix.into() + if digit_blocks_left > 0 && current_digits != 0 { + let singles = if digit_blocks_left < 10 { + SINGLES_LAST_ILLION + } else { + SINGLES + }; + let mut n = digit_blocks_left; + let s = n % 10; + n /= 10; + acc.write_str(singles[s as usize]).unwrap(); + let t = n % 10; + n /= 10; + acc.write_str(TENS[t as usize]).unwrap(); + let h = n % 10; + n /= 10; + acc.write_str(HUNDREDS[h as usize]).unwrap(); + let th = n % 10; + n /= 10; + acc.write_str(THOUSANDS[th as usize]).unwrap(); + let tth = n % 10; + n /= 10; + acc.write_str(TEN_THOUSANDS[tth as usize]).unwrap(); + let hth = n % 10; + acc.write_str(HUNDRED_THOUSANDS[hth as usize]).unwrap(); + // Check if we need tuple not uple + let last_written = [s, t, h, th, tth, hth] + .iter() + .cloned() + .enumerate() + .rev() + .find(|(_, n)| *n != 0) + .unwrap(); + if BINDING_T[last_written.0][last_written.1 as usize] { + acc.write_str("t").unwrap(); } + acc.write_str("illion ")?; } } + acc.pop(); + Ok(()) } /// Rounds a base 10 number string. \ /// Uses the last digit to decide the rounding direction. \ @@ -721,77 +817,86 @@ mod tests { #[test] fn test_factorial_level_string() { let en = locale::get_en(); + assert_eq!(get_factorial_level_string(1, &en.format()), "{factorial}"); assert_eq!( - Calculation::get_factorial_level_string(1, &en.format()), - "{factorial}" - ); - assert_eq!( - Calculation::get_factorial_level_string(2, &en.format()), + get_factorial_level_string(2, &en.format()), "double-{factorial}" ); assert_eq!( - Calculation::get_factorial_level_string(3, &en.format()), + get_factorial_level_string(3, &en.format()), "triple-{factorial}" ); assert_eq!( - Calculation::get_factorial_level_string(10, &en.format()), + get_factorial_level_string(10, &en.format()), "decuple-{factorial}" ); assert_eq!( - Calculation::get_factorial_level_string(45, &en.format()), + get_factorial_level_string(45, &en.format()), "quinquadragintuple-{factorial}" ); assert_eq!( - Calculation::get_factorial_level_string(50, &en.format()), + get_factorial_level_string(50, &en.format()), "quinquagintuple-{factorial}" ); assert_eq!( - Calculation::get_factorial_level_string(100, &en.format()), + get_factorial_level_string(100, &en.format()), "centuple-{factorial}" ); assert_eq!( - Calculation::get_factorial_level_string(521, &en.format()), + get_factorial_level_string(521, &en.format()), "unviginquingentuple-{factorial}" ); assert_eq!( - Calculation::get_factorial_level_string(1000, &en.format()), + get_factorial_level_string(1000, &en.format()), "milluple-{factorial}" ); assert_eq!( - Calculation::get_factorial_level_string(4321, &en.format()), + get_factorial_level_string(4321, &en.format()), "unvigintricenquadrilluple-{factorial}" ); assert_eq!( - Calculation::get_factorial_level_string(89342, &en.format()), + get_factorial_level_string(89342, &en.format()), "duoquadragintricennonilloctogintilluple-{factorial}" ); assert_eq!( - Calculation::get_factorial_level_string(654321, &en.format()), + get_factorial_level_string(654321, &en.format()), "unvigintricenquadrillquinquagintillsescentilluple-{factorial}" ); assert_eq!( - Calculation::get_factorial_level_string(1000000, &en.format()), + get_factorial_level_string(1000000, &en.format()), "1000000-{factorial}" ); let de = locale::get_de(); + assert_eq!(get_factorial_level_string(1, &de.format()), "{factorial}"); assert_eq!( - Calculation::get_factorial_level_string(1, &de.format()), - "{factorial}" - ); - assert_eq!( - Calculation::get_factorial_level_string(2, &de.format()), + get_factorial_level_string(2, &de.format()), "doppel{factorial}" ); assert_eq!( - Calculation::get_factorial_level_string(3, &de.format()), + get_factorial_level_string(3, &de.format()), "trippel{factorial}" ); assert_eq!( - Calculation::get_factorial_level_string(45, &de.format()), + get_factorial_level_string(45, &de.format()), "quinquadragintupel{factorial}" ); } + #[test] + fn test_write_out_number() { + let consts = Consts::default(); + let mut acc = String::new(); + write_out_number( + &mut acc, + &"1234567890123456789000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + .parse() + .unwrap(), + &consts, + ) + .unwrap(); + assert_eq!(acc, ""); + } + #[test] fn test_truncate() { let consts = Consts::default(); From aab06be06084cc861e1a23547364bf521237a2f6 Mon Sep 17 00:00:00 2001 From: Aras14HD Date: Mon, 9 Feb 2026 09:39:18 +0100 Subject: [PATCH 4/6] add write out command --- factorion-lib/README.md | 4 +- factorion-lib/src/calculation_results.rs | 252 +++++++++++++---------- factorion-lib/src/comment.rs | 48 ++++- factorion-lib/tests/integration.rs | 14 ++ 4 files changed, 199 insertions(+), 119 deletions(-) diff --git a/factorion-lib/README.md b/factorion-lib/README.md index a4c18d0..817c6e9 100644 --- a/factorion-lib/README.md +++ b/factorion-lib/README.md @@ -29,7 +29,7 @@ assert_eq!(reply, "Hey @you!\n\nTermial of factorial of 5 is 7260 \n\n\n*^(This ``` Or manually do the steps: ```rust -use factorion_lib::{parse::parse, calculation_tasks::{CalculationJob, CalculationBase}, calculation_results::{Calculation, CalculationResult, Number}, Consts}; +use factorion_lib::{parse::parse, calculation_tasks::{CalculationJob, CalculationBase}, calculation_results::{Calculation, CalculationResult, Number, FormatOptions}, Consts}; // You need to define constants first let consts = Consts::default(); @@ -61,6 +61,6 @@ assert_eq!(results, [ let result = results.remove(0); let mut formatted = String::new(); // Write the formatted result to a string (for efficiency). We don't want to shorten anything below that huge number -result.format(&mut formatted, false, false, &10000000000000000000u128.into(), &consts, &locale.format()).unwrap(); +result.format(&mut formatted, FormatOptions::NONE, &10000000000000000000u128.into(), &consts, &locale.format()).unwrap(); assert_eq!(formatted, "Factorial of 4 is 24 \n\n"); ``` diff --git a/factorion-lib/src/calculation_results.rs b/factorion-lib/src/calculation_results.rs index a48d3db..0502026 100644 --- a/factorion-lib/src/calculation_results.rs +++ b/factorion-lib/src/calculation_results.rs @@ -1,7 +1,14 @@ //! This module handles the formatting of the calculations (`The factorial of Subfactorial of 5 is`, etc.) +use crate::impl_all_bitwise; +use crate::impl_bitwise; +use factorion_math::length; #[cfg(any(feature = "serde", test))] use serde::{Deserialize, Serialize}; +use std::ops::BitAnd; +use std::ops::BitOr; +use std::ops::BitXor; +use std::ops::Not; use crate::rug::float::OrdFloat; use crate::rug::ops::{NegAssign, NotAssign, Pow}; @@ -110,17 +117,47 @@ impl From for Number { Number::Float(value.into()) } } - +#[non_exhaustive] +#[derive(Debug, Clone, Default)] +pub struct FormatOptions { + pub force_shorten: bool, + pub agressive_shorten: bool, + pub write_out: bool, +} +impl_all_bitwise!(FormatOptions { + force_shorten, + agressive_shorten, + write_out, +}); +#[allow(dead_code)] +impl FormatOptions { + pub const NONE: Self = Self { + force_shorten: false, + agressive_shorten: false, + write_out: false, + }; + pub const FORCE_SHORTEN: Self = Self { + force_shorten: true, + ..Self::NONE + }; + pub const AGRESSIVE_SHORTEN: Self = Self { + agressive_shorten: true, + ..Self::NONE + }; + pub const WRITE_OUT: Self = Self { + write_out: true, + ..Self::NONE + }; +} impl CalculationResult { /// Formats a number. \ /// Shorten turns integers into scientific notation if that makes them shorter. \ /// Aggressive enables tertation for towers. - fn format( + pub fn format( &self, acc: &mut String, rough: &mut bool, - shorten: bool, - agressive: bool, + opts: FormatOptions, is_value: bool, consts: &Consts, locale: &locale::NumFormat, @@ -128,7 +165,9 @@ impl CalculationResult { let mut start = acc.len(); match &self { CalculationResult::Exact(factorial) => { - if shorten { + if opts.write_out && length(factorial, consts.float_precision) < 3000000 { + write_out_number(acc, factorial, consts)?; + } else if opts.force_shorten { let (s, r) = truncate(factorial, consts); *rough = r; acc.write_str(&s)?; @@ -140,7 +179,7 @@ impl CalculationResult { let base = base.as_float(); format_float(acc, base, consts)?; acc.write_str(" × 10^")?; - if shorten { + if opts.force_shorten { acc.write_str("(")?; acc.write_str(&truncate(exponent, consts).0)?; acc.write_str(")")?; @@ -152,7 +191,7 @@ impl CalculationResult { if is_value { acc.write_str("10^(")?; } - if shorten { + if opts.force_shorten { acc.write_str(&truncate(digits, consts).0)?; } else { write!(acc, "{digits}")?; @@ -170,7 +209,8 @@ impl CalculationResult { acc.write_str(if *negative { "-" } else { "" })?; // If we have a one on top, we gain no information by printing the whole tower. // If depth is one, it is nicer to write 10¹ than ¹10. - if !agressive && depth <= usize::MAX && (depth <= 1 || exponent != &1) { + if !opts.agressive_shorten && depth <= usize::MAX && (depth <= 1 || exponent != &1) + { if depth > 0 { acc.write_str("10^(")?; } @@ -179,7 +219,7 @@ impl CalculationResult { acc.write_str(&"10\\^".repeat(depth.to_usize().unwrap() - 1))?; acc.write_str("(")?; } - if shorten { + if opts.force_shorten { acc.write_str(&truncate(exponent, consts).0)?; } else { write!(acc, "{exponent}")?; @@ -276,6 +316,13 @@ impl Calculation { pub fn is_too_long(&self, too_big_number: &Integer) -> bool { self.result.is_too_long(too_big_number) || self.value.is_too_long(too_big_number) } + pub fn can_write_out(&self, prec: u32) -> bool { + let CalculationResult::Exact(n) = &self.result else { + return false; + }; + + length(n, prec) <= 3000000 + } } impl Calculation { @@ -286,8 +333,7 @@ impl Calculation { pub fn format( &self, acc: &mut String, - force_shorten: bool, - agressive_shorten: bool, + options: FormatOptions, too_big_number: &Integer, consts: &Consts, locale: &locale::Format<'_>, @@ -297,7 +343,7 @@ impl Calculation { match ( &self.value, &self.result, - agressive_shorten && self.steps.len() > 1, + options.agressive_shorten && self.steps.len() > 1, ) { // All that (_, _, true) => locale.all_that(), @@ -320,8 +366,12 @@ impl Calculation { self.value.format( &mut number, &mut rough, - force_shorten || self.result.is_too_long(too_big_number) || agressive_shorten, - agressive_shorten, + FormatOptions { + force_shorten: options.force_shorten + || self.result.is_too_long(too_big_number) + || options.agressive_shorten, + ..options + }, true, consts, &locale.number_format(), @@ -336,8 +386,12 @@ impl Calculation { self.result.format( &mut number, &mut rough, - force_shorten || self.result.is_too_long(too_big_number) || agressive_shorten, - agressive_shorten, + FormatOptions { + force_shorten: options.force_shorten + || self.result.is_too_long(too_big_number) + || options.agressive_shorten, + ..options + }, false, consts, &locale.number_format(), @@ -426,7 +480,7 @@ const HUNDREDS: [&str; 10] = [ "quingen", "sescen", "septingen", - "octingen ", + "octingen", "nongen", ]; // Note that other than milluple, these are not found in a list, but continue the pattern from mill with different starts @@ -551,6 +605,7 @@ const EN_TENS_SINGLES: [&str; 10] = [ const SINGLES_LAST_ILLION: [&str; 10] = [ "", "m", "b", "tr", "quadr", "quint", "sext", "sept", "oct", "non", ]; +// TODO: localize (illion, illiard, type of scale, numbers, digit order, thousand) fn write_out_number(acc: &mut String, num: &Integer, consts: &Consts) -> std::fmt::Result { let num = Float::with_val(consts.float_precision, num); let ten = Float::with_val(consts.float_precision, 10); @@ -560,15 +615,12 @@ fn write_out_number(acc: &mut String, num: &Integer, consts: &Consts) -> std::fm .to_u32_saturating_round(factorion_math::rug::float::Round::Down) .unwrap() / 3; - dbg!(digit_blocks); for digit_blocks_left in (digit_blocks.saturating_sub(5)..=digit_blocks).rev() { - dbg!(digit_blocks_left); let current_digits = Float::to_u32_saturating_round( &((num.clone() / ten.clone().pow(digit_blocks_left * 3)) % 1000), factorion_math::rug::float::Round::Down, ) .unwrap(); - dbg!(current_digits); let mut n = current_digits; let s = n % 10; n /= 10; @@ -592,36 +644,40 @@ fn write_out_number(acc: &mut String, num: &Integer, consts: &Consts) -> std::fm } else { SINGLES }; - let mut n = digit_blocks_left; - let s = n % 10; - n /= 10; - acc.write_str(singles[s as usize]).unwrap(); - let t = n % 10; - n /= 10; - acc.write_str(TENS[t as usize]).unwrap(); - let h = n % 10; - n /= 10; - acc.write_str(HUNDREDS[h as usize]).unwrap(); - let th = n % 10; - n /= 10; - acc.write_str(THOUSANDS[th as usize]).unwrap(); - let tth = n % 10; - n /= 10; - acc.write_str(TEN_THOUSANDS[tth as usize]).unwrap(); - let hth = n % 10; - acc.write_str(HUNDRED_THOUSANDS[hth as usize]).unwrap(); - // Check if we need tuple not uple - let last_written = [s, t, h, th, tth, hth] - .iter() - .cloned() - .enumerate() - .rev() - .find(|(_, n)| *n != 0) - .unwrap(); - if BINDING_T[last_written.0][last_written.1 as usize] { - acc.write_str("t").unwrap(); + let mut n = digit_blocks_left - 1; + if n > 0 { + let s = n % 10; + n /= 10; + acc.write_str(singles[s as usize]).unwrap(); + let t = n % 10; + n /= 10; + acc.write_str(TENS[t as usize]).unwrap(); + let h = n % 10; + n /= 10; + acc.write_str(HUNDREDS[h as usize]).unwrap(); + let th = n % 10; + n /= 10; + acc.write_str(THOUSANDS[th as usize]).unwrap(); + let tth = n % 10; + n /= 10; + acc.write_str(TEN_THOUSANDS[tth as usize]).unwrap(); + let hth = n % 10; + acc.write_str(HUNDRED_THOUSANDS[hth as usize]).unwrap(); + // Check if we need tuple not uple + let last_written = [s, t, h, th, tth, hth] + .iter() + .cloned() + .enumerate() + .rev() + .find(|(_, n)| *n != 0) + .unwrap(); + if BINDING_T[last_written.0][last_written.1 as usize] { + acc.write_str("t").unwrap(); + } + acc.write_str("illion ")?; + } else { + acc.write_str("thousand ")?; } - acc.write_str("illion ")?; } } acc.pop(); @@ -894,7 +950,16 @@ mod tests { &consts, ) .unwrap(); - assert_eq!(acc, ""); + assert_eq!( + acc, + "one tredeccentillion two hundred thirty four duodeccentillion five hundred sixty seven undeccentillion eight hundred ninety deccentillion one hundred twenty three novemcentillion four hundred fivety six octocentillion" + ); + let mut acc = String::new(); + write_out_number(&mut acc, &"123456789".parse().unwrap(), &consts).unwrap(); + assert_eq!( + acc, + "one hundred twenty three million four hundred fivety six thousand seven hundred eighty nine" + ); } #[test] @@ -965,8 +1030,7 @@ mod tests { factorial .format( &mut acc, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -983,8 +1047,7 @@ mod tests { factorial .format( &mut acc, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1004,8 +1067,7 @@ mod tests { factorial .format( &mut acc, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1022,8 +1084,7 @@ mod tests { factorial .format( &mut acc, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1040,8 +1101,7 @@ mod tests { factorial .format( &mut acc, - true, - false, + FormatOptions::FORCE_SHORTEN, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1076,8 +1136,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1096,8 +1155,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1116,8 +1174,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - true, - false, + FormatOptions::FORCE_SHORTEN, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1138,8 +1195,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1163,8 +1219,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1186,8 +1241,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1206,8 +1260,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1229,8 +1282,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1249,8 +1301,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1269,8 +1320,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1289,8 +1339,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1312,8 +1361,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1335,8 +1383,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - false, - true, + FormatOptions::AGRESSIVE_SHORTEN, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1359,8 +1406,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1383,8 +1429,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1411,8 +1456,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - true, - false, + FormatOptions::FORCE_SHORTEN, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1439,8 +1483,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - true, - false, + FormatOptions::FORCE_SHORTEN, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1469,8 +1512,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - true, - false, + FormatOptions::FORCE_SHORTEN, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1496,8 +1538,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1520,8 +1561,7 @@ mod test { let mut s = String::new(); fact.format( &mut s, - false, - false, + FormatOptions::NONE, &TOO_BIG_NUMBER, &consts, &consts.locales.get("en").unwrap().format(), @@ -1605,8 +1645,7 @@ mod test { .format( &mut acc, &mut false, - true, - false, + FormatOptions::FORCE_SHORTEN, false, &consts, &locale::NumFormat::V1(&locale::v1::NumFormat { decimal: '.' }), @@ -1621,8 +1660,7 @@ mod test { .format( &mut acc, &mut false, - true, - false, + FormatOptions::FORCE_SHORTEN, false, &consts, &locale::NumFormat::V1(&locale::v1::NumFormat { decimal: '.' }), @@ -1637,8 +1675,7 @@ mod test { .format( &mut acc, &mut false, - true, - false, + FormatOptions::FORCE_SHORTEN, false, &consts, &locale::NumFormat::V1(&locale::v1::NumFormat { decimal: '.' }), @@ -1657,8 +1694,7 @@ mod test { .format( &mut acc, &mut false, - true, - false, + FormatOptions::FORCE_SHORTEN, false, &consts, &locale::NumFormat::V1(&locale::v1::NumFormat { decimal: '.' }), diff --git a/factorion-lib/src/comment.rs b/factorion-lib/src/comment.rs index e3227a7..98c6107 100644 --- a/factorion-lib/src/comment.rs +++ b/factorion-lib/src/comment.rs @@ -7,12 +7,13 @@ use crate::rug::integer::IntegerExt64; use crate::rug::{Complete, Integer}; use crate::Consts; -use crate::calculation_results::Calculation; +use crate::calculation_results::{Calculation, FormatOptions, Number}; use crate::calculation_tasks::{CalculationBase, CalculationJob}; use crate::parse::parse; use std::fmt::Write; use std::ops::*; +#[macro_export] macro_rules! impl_bitwise { ($s_name:ident {$($s_fields:ident),*}, $t_name:ident, $fn_name:ident) => { impl $t_name for $s_name { @@ -25,6 +26,7 @@ macro_rules! impl_bitwise { } }; } +#[macro_export] macro_rules! impl_all_bitwise { ($s_name:ident {$($s_fields:ident,)*}) => {impl_all_bitwise!($s_name {$($s_fields),*});}; ($s_name:ident {$($s_fields:ident),*}) => { @@ -152,6 +154,9 @@ pub struct Commands { /// Disable the beginning note. #[cfg_attr(any(feature = "serde", test), serde(default))] pub no_note: bool, + /// Write out the number as a word if possible. + #[cfg_attr(any(feature = "serde", test), serde(default))] + pub write_out: bool, } impl_all_bitwise!(Commands { shorten, @@ -159,6 +164,7 @@ impl_all_bitwise!(Commands { nested, termial, no_note, + write_out, }); #[allow(dead_code)] impl Commands { @@ -168,6 +174,7 @@ impl Commands { nested: false, termial: false, no_note: false, + write_out: false, }; pub const SHORTEN: Self = Self { shorten: true, @@ -189,6 +196,10 @@ impl Commands { no_note: true, ..Self::NONE }; + pub const WRITE_OUT: Self = Self { + write_out: true, + ..Self::NONE + }; } impl Commands { @@ -211,6 +222,8 @@ impl Commands { || Self::contains_command_format(text, "triangle"), no_note: Self::contains_command_format(text, "no note") || Self::contains_command_format(text, "no_note"), + write_out: Self::contains_command_format(text, "write_out") + || Self::contains_command_format(text, "write_num"), } } pub fn overrides_from_comment_text(text: &str) -> Self { @@ -223,6 +236,8 @@ impl Commands { termial: !(Self::contains_command_format(text, "no termial") || Self::contains_command_format(text, "no_termial")), no_note: !Self::contains_command_format(text, "note"), + write_out: !(Self::contains_command_format(text, "dont_write_out") + || Self::contains_command_format(text, "normal_num")), } } } @@ -570,6 +585,11 @@ impl CommentCalculated { .calculation_list .iter() .any(|c| c.is_too_long(too_big_number)) + && !(self.commands.write_out + && self + .calculation_list + .iter() + .all(|c| c.can_write_out(consts.float_precision))) { if multiple { let _ = note.write_str(locale.notes().too_big_mult()); @@ -588,8 +608,11 @@ impl CommentCalculated { .fold(note.clone(), |mut acc, factorial| { let _ = factorial.format( &mut acc, - self.commands.shorten, - false, + FormatOptions { + force_shorten: self.commands.shorten, + write_out: self.commands.write_out, + ..FormatOptions::NONE + }, too_big_number, consts, &locale.format(), @@ -619,8 +642,10 @@ impl CommentCalculated { .fold(note, |mut acc, factorial| { let _ = factorial.format( &mut acc, - true, - false, + FormatOptions { + write_out: self.commands.write_out, + ..FormatOptions::FORCE_SHORTEN + }, too_big_number, consts, &locale.format(), @@ -640,8 +665,10 @@ impl CommentCalculated { .fold(note, |mut acc, factorial| { let _ = factorial.format( &mut acc, - true, - true, + FormatOptions { + write_out: self.commands.write_out, + ..{ FormatOptions::FORCE_SHORTEN | FormatOptions::AGRESSIVE_SHORTEN } + }, too_big_number, consts, &locale.format(), @@ -660,8 +687,11 @@ impl CommentCalculated { let mut res = String::new(); let _ = fact.format( &mut res, - true, - !self.commands.steps, + FormatOptions { + agressive_shorten: !self.commands.steps, + write_out: self.commands.write_out, + ..FormatOptions::FORCE_SHORTEN + }, too_big_number, consts, &locale.format(), diff --git a/factorion-lib/tests/integration.rs b/factorion-lib/tests/integration.rs index 5e5c67a..3491cb3 100644 --- a/factorion-lib/tests/integration.rs +++ b/factorion-lib/tests/integration.rs @@ -1732,6 +1732,20 @@ fn test_all_that_on_multiple_calcs() { ) } +#[test] +fn test_command_write_out() { + let consts = Consts::default(); + let comment = Comment::new("176902! !write_out", (), Commands::NONE, MAX_LENGTH, "en") + .extract(&consts) + .calc(&consts); + + let reply = comment.get_reply(&consts); + assert_eq!( + reply, + "Factorial of one hundred seventy six thousand nine hundred two is seventy five quintriginoctingentrilloctogintillducentillillion five hundred fourty five quattuortriginoctingentrilloctogintillducentillillion seven hundred sixty six tretriginoctingentrilloctogintillducentillillion three hundred five duotriginoctingentrilloctogintillducentillillion fourty seven untriginoctingentrilloctogintillducentillillion one hundred fourty three triginoctingentrilloctogintillducentillillion \n\n\n*^(This action was performed by a bot | [Source code](http://f.r0.fyi))*" + ) +} + #[test] fn test_arbitrary_comment() { let consts = Consts::default(); From e6d7baf9977fcd4b177df9e8f2068a202c20f42f Mon Sep 17 00:00:00 2001 From: Aras14HD Date: Fri, 27 Feb 2026 19:34:04 +0100 Subject: [PATCH 5/6] bump version minor (semver major for lib) --- Cargo.lock | 6 +++--- factorion-bot-discord/Cargo.toml | 4 ++-- factorion-bot-reddit/Cargo.toml | 4 ++-- factorion-lib/Cargo.toml | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 97f87dd..c0c2e26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -399,7 +399,7 @@ dependencies = [ [[package]] name = "factorion-bot-discord" -version = "2.4.0" +version = "2.5.0" dependencies = [ "anyhow", "dotenvy", @@ -414,7 +414,7 @@ dependencies = [ [[package]] name = "factorion-bot-reddit" -version = "5.5.0" +version = "5.6.0" dependencies = [ "anyhow", "base64 0.22.1", @@ -434,7 +434,7 @@ dependencies = [ [[package]] name = "factorion-lib" -version = "4.4.0" +version = "5.0.0" dependencies = [ "arbtest", "chrono", diff --git a/factorion-bot-discord/Cargo.toml b/factorion-bot-discord/Cargo.toml index dc3805d..960c09c 100644 --- a/factorion-bot-discord/Cargo.toml +++ b/factorion-bot-discord/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "factorion-bot-discord" -version = "2.4.0" +version = "2.5.0" edition = "2024" description = "factorion-bot (for factorials and related) on Discord" license = "MIT" @@ -10,7 +10,7 @@ keywords = ["factorial", "termial", "bot", "math", "discord"] categories = ["mathematics", "web-programming", "parser-implementations"] [dependencies] -factorion-lib = { path = "../factorion-lib", version = "4.4.0", features = ["serde", "influxdb"] } +factorion-lib = { path = "../factorion-lib", version = "5.0.0", features = ["serde", "influxdb"] } serenity = { version = "0.12", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "cache"] } tokio = { version = "1.48.0", features = ["macros", "rt-multi-thread", "time"] } dotenvy = "^0.15.7" diff --git a/factorion-bot-reddit/Cargo.toml b/factorion-bot-reddit/Cargo.toml index e9e7f72..2cec897 100644 --- a/factorion-bot-reddit/Cargo.toml +++ b/factorion-bot-reddit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "factorion-bot-reddit" -version = "5.5.0" +version = "5.6.0" edition = "2024" description = "factorion-bot (for factorials and related) on Reddit" license = "MIT" @@ -10,7 +10,7 @@ keywords = ["factorial", "termial", "bot", "math"] categories = ["mathematics", "web-programming", "parser-implementations"] [dependencies] -factorion-lib = {path = "../factorion-lib", version = "4.4.0", features = ["serde", "influxdb"]} +factorion-lib = {path = "../factorion-lib", version = "5.0.0", features = ["serde", "influxdb"]} reqwest = { version = "0.12.28", features = ["json", "native-tls"], default-features = false } serde = { version = "1.0.219", default-features = false, features = ["derive"] } serde_json = "1.0.140" diff --git a/factorion-lib/Cargo.toml b/factorion-lib/Cargo.toml index f40cb22..d2c12f9 100644 --- a/factorion-lib/Cargo.toml +++ b/factorion-lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "factorion-lib" -version = "4.4.0" +version = "5.0.0" edition = "2024" description = "A library used to create bots to recognize and calculate factorials and related concepts" license = "MIT" From 0618c6957b22c9086279cc78d9915e20a9ee6b29 Mon Sep 17 00:00:00 2001 From: Aras14HD Date: Sun, 1 Mar 2026 17:12:20 +0100 Subject: [PATCH 6/6] add write out support warning --- factorion-lib/src/comment.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/factorion-lib/src/comment.rs b/factorion-lib/src/comment.rs index 98c6107..cfa1547 100644 --- a/factorion-lib/src/comment.rs +++ b/factorion-lib/src/comment.rs @@ -598,6 +598,10 @@ impl CommentCalculated { let _ = note.write_str(locale.notes().too_big()); let _ = note.write_str("\n\n"); } + } else if self.commands.write_out && self.locale != "en" { + let _ = + note.write_str("I can only write out numbers in english, so I will do that."); + let _ = note.write_str("\n\n"); } } @@ -869,4 +873,17 @@ mod tests { "I have repeated myself enough, I won't do that calculation again.\n\n\n*^(This action was performed by a bot | [Source code](http://f.r0.fyi))*" ); } + + #[test] + fn test_write_out_unsupported_note() { + let consts = Consts::default(); + let comment = Comment::new("1!", (), Commands::WRITE_OUT, MAX_LENGTH, "de") + .extract(&consts) + .calc(&consts); + let reply = comment.get_reply(&consts); + assert_eq!( + reply, + "I can only write out numbers in english, so I will do that.\n\nFakultät von one ist one \n\n\n*^(Dieser Kommentar wurde automatisch geschrieben | [Quelltext](http://f.r0.fyi))*" + ); + } }