From d2e0a5cd913983d5a54de0df231f50de207be0d4 Mon Sep 17 00:00:00 2001 From: newt Date: Wed, 9 Oct 2024 18:10:11 +0100 Subject: [PATCH] feat: 17 - number letter counts added phf_map for constant hashmap like structures --- Cargo.lock | 45 ++++++++++++++++++++- Cargo.toml | 1 + readme.md | 4 +- src/bin/16.rs | 8 +++- src/bin/17.rs | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 161 insertions(+), 5 deletions(-) create mode 100644 src/bin/17.rs diff --git a/Cargo.lock b/Cargo.lock index b683006..516b588 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -253,6 +253,7 @@ dependencies = [ "html-escape", "num-bigint", "owo-colors", + "phf 0.11.1", "regex", "requestty", "reqwest", @@ -858,7 +859,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" dependencies = [ - "phf_macros", + "phf_macros 0.8.0", "phf_shared 0.8.0", "proc-macro-hack", ] @@ -872,6 +873,16 @@ dependencies = [ "phf_shared 0.10.0", ] +[[package]] +name = "phf" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" +dependencies = [ + "phf_macros 0.11.1", + "phf_shared 0.11.1", +] + [[package]] name = "phf_codegen" version = "0.8.0" @@ -912,6 +923,16 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "phf_generator" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" +dependencies = [ + "phf_shared 0.11.1", + "rand 0.8.5", +] + [[package]] name = "phf_macros" version = "0.8.0" @@ -926,6 +947,19 @@ dependencies = [ "syn", ] +[[package]] +name = "phf_macros" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" +dependencies = [ + "phf_generator 0.11.1", + "phf_shared 0.11.1", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "phf_shared" version = "0.8.0" @@ -944,6 +978,15 @@ dependencies = [ "siphasher", ] +[[package]] +name = "phf_shared" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.9" diff --git a/Cargo.toml b/Cargo.toml index eb902f3..963ae16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ tokio = { version = "1.23", features = ["full"] } regex = "1" html-escape = "0.2.13" num-bigint = "0.4.3" +phf = { version = "0.11.1", features = ["macros"] } [profile.release] opt-level = "z" diff --git a/readme.md b/readme.md index c908a11..d154587 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,7 @@ I originally started the challenge in [the-honk](https://github.com/newtykins/th ## Challenge Completion -### 20 out of 100 public challenges completed. +### 21 out of 100 public challenges completed. - [x] 1 - [Multiples of 3 or 5](src/bin/1.rs) - [x] 2 - [Even Fibonacci numbers](src/bin/2.rs) @@ -29,7 +29,7 @@ I originally started the challenge in [the-honk](https://github.com/newtykins/th - [x] 14 - [Longest Collatz sequence](src/bin/14.rs) - [x] 15 - [Lattice paths](src/bin/15.rs) - [x] 16 - [Power digit sum](src/bin/16.rs) -- [ ] 17 - Number letter counts +- [x] 17 - [Number letter counts](src/bin/17.rs) - [ ] 18 - Maximum path sum I - [ ] 19 - Counting Sundays - [ ] 20 - Factorial digit sum diff --git a/src/bin/16.rs b/src/bin/16.rs index 3896ac4..a95db11 100644 --- a/src/bin/16.rs +++ b/src/bin/16.rs @@ -15,13 +15,17 @@ fn get_digits(number: usize) -> Vec { } fn power_digit_sum(base: usize, power: u32) -> usize { - let answer = BigUint::new(get_digits(base)).pow(power).to_string().chars().collect::>(); + let answer = BigUint::new(get_digits(base)) + .pow(power) + .to_string() + .chars() + .collect::>(); let mut sum = 0; for i in 0..answer.len() { let number = answer[i].to_string().parse::().unwrap(); - + sum += number; } diff --git a/src/bin/17.rs b/src/bin/17.rs new file mode 100644 index 0000000..b842a02 --- /dev/null +++ b/src/bin/17.rs @@ -0,0 +1,108 @@ +/* +Problem 17 - Number letter counts + +If the numbers 1 to 5 are written out in words: one, two, three, four, five, then there are 3 + 3 + 5 + 4 + 4 = 19 letters used in total. +If all the numbers from 1 to 1000 (one thousand) inclusive were written out in words, how many letters would be used? +NOTE: Do not count spaces or hyphens. For example, 342 (three hundred and forty-two) contains 23 letters and 115 (one hundred and fifteen) contains 20 letters. The use of "and" when writing out numbers is in compliance with British usage. +*/ + +use std::ops::Div; + +use phf::phf_map; + +const TRANSLATIONS: phf::Map = phf_map! { + 0u16 => "", + 1u16 => "one", + 2u16 => "two", + 3u16 => "three", + 4u16 => "four", + 5u16 => "five", + 6u16 => "six", + 7u16 => "seven", + 8u16 => "eight", + 9u16 => "nine", + 10u16 => "ten", + 11u16 => "eleven", + 12u16 => "twelve", + 13u16 => "thirteen", + 14u16 => "fourteen", + 15u16 => "fifteen", + 16u16 => "sixteen", + 17u16 => "seventeen", + 18u16 => "eighteen", + 19u16 => "nineteen", + 20u16 => "twenty", + 30u16 => "thirty", + 40u16 => "forty", + 50u16 => "fifty", + 60u16 => "sixty", + 70u16 => "seventy", + 80u16 => "eighty", + 90u16 => "ninety" +}; + +fn number_to_words(number: usize) -> String { + let mut n = number.clone(); + let mut out = String::new(); + + // Thousands + let thousands = n.div(1000); + n -= thousands * 1000; + + if thousands > 0 { + out = format!("{}thousand", TRANSLATIONS.get(&(thousands as u16)).unwrap()); + } + + // Hundreds + let hundreds = n.div(100); + n -= hundreds * 100; + + if hundreds > 0 { + out = format!("{out}{}hundred", TRANSLATIONS.get(&(hundreds as u16)).unwrap()); + } + + // Tens + let tens = n.div(10); + n -= tens * 10; + + if tens > 0 { + let translation: &str; + let and = if hundreds > 0 {"and"} else {""}; + + if n % 10 > 0 && tens == 1 { + translation = TRANSLATIONS.get(&((10 + (n % 10)) as u16)).unwrap(); + + n -= n % 10; + } else { + translation = TRANSLATIONS.get(&(tens as u16 * 10)).unwrap(); + } + + out = format!("{out}{and}{}", translation); + } + + // Remainder + if n > 0 { + let and = if hundreds > 0 && tens <= 0 {"and"} else {""}; + out = format!("{out}{and}{}", TRANSLATIONS.get(&(n as u16)).unwrap()); + } + + out +} + +fn letter_count(upper_bound: usize) -> usize { + let mut sum = 0; + + for i in 1..(upper_bound + 1) { + println!("{} {}", number_to_words(i), number_to_words(i).len()); + + sum += number_to_words(i).len(); + } + + sum +} + +fn main() { + let sum = letter_count(1000); + + println!("{} letters would be used to write out all of the numbers from 1 to 1000!", sum); +}