diff --git a/README.md b/README.md index 6028cbe..464d6b2 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ We encourage you to share your progress and ask questions in the Discussions sec | Day #63 | [The Rabbit Problem](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-09/Day-63_The-Rabbit-Problem) | :white_check_mark: | | Day #64 | [First Recurring Character](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-10/Day-64_First-Recurring-Character) | :white_check_mark: | | Day #65 | [ISBN Validator](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-10/Day-65_ISBN-Validator) | :white_check_mark: | -| Day #66 | [ISBN Generator](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-10/Day-66_ISBN-Generator) | :white_large_square: | +| Day #66 | [ISBN Generator](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-10/Day-66_ISBN-Generator) | :white_check_mark: | | Day #67 | [Color Maze](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-10/Day-67_Color-Maze) | :white_large_square: | | Day #68 | [Clarence The Slow Typist](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-10/Day-68_Clarence-The-Slow-Typist) | :white_large_square: | | Day #69 | [Garage Door Opener](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-10/Day-69-Garage-Door-Opener) | :white_large_square: | diff --git a/Week-10/Day-66_ISBN-Generator/day66/Cargo.toml b/Week-10/Day-66_ISBN-Generator/day66/Cargo.toml new file mode 100644 index 0000000..c408a85 --- /dev/null +++ b/Week-10/Day-66_ISBN-Generator/day66/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "day66" +version = "0.1.0" +edition = "2021" + +[dependencies] +lazy_static = "1.5.0" diff --git a/Week-10/Day-66_ISBN-Generator/day66/src/lib.rs b/Week-10/Day-66_ISBN-Generator/day66/src/lib.rs new file mode 100644 index 0000000..48d1984 --- /dev/null +++ b/Week-10/Day-66_ISBN-Generator/day66/src/lib.rs @@ -0,0 +1,83 @@ +use std::sync::{Arc, Mutex}; +use std::time::{SystemTime, UNIX_EPOCH}; + +lazy_static::lazy_static! { + static ref RNG: Arc> = Arc::new(Mutex::new(Rng::new())); +} + +pub fn isbn_generator() -> String { + let mut rng = RNG.lock().unwrap(); + let mut partial_isbn = rng.random_number(1e8 as u128, 1e9 as u128); + let mut isbn = partial_isbn.to_string(); + + let mut val = 0; + let mut counter = 1; + while partial_isbn > 0 { + counter += 1; + val += partial_isbn % 10 * counter; + partial_isbn /= 10; + } + + isbn.push(if (val + 10) % 11 == 0 { + 'X' + } else if val % 11 == 0 { + '0' + } else { + (11 - val % 11).to_string().chars().last().unwrap() + }); + + isbn +} + +pub fn isbn_validator(digits: &str) -> Result { + if digits.len() != 10 { + return Err("Invalid length for the ISBN".to_owned()); + } + let mut val: usize = 0; + for (i, digit) in digits[..digits.len() - 1].chars().enumerate() { + if !digit.is_ascii_digit() { + return Err("Only digits allowed".to_owned()); + } + val += (digit as u8 - b'0') as usize * (10 - i); + } + let digit = digits.chars().last().unwrap(); + if digit == 'X' { + val += 10; + } else { + val += (digit as u8 - b'0') as usize; + } + Ok(val % 11 == 0) +} + +pub struct Rng { + seed: u128, +} + +impl Rng { + pub fn new() -> Rng { + let time_since_epoch = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Error in getting time") + .as_millis(); + Rng { + seed: time_since_epoch, + } + } + + fn linear_congruent_generator(&mut self, a: u128, c: u128, m: u128) -> u128 { + let result = (a * self.seed + c) % m; + self.seed = result; + result + } + + pub fn random_number(&mut self, from: u128, to: u128) -> u128 { + let random_number = self.linear_congruent_generator(1103515245, 12345, 2u128.pow(31)); + (random_number % (to - from)) + from + } +} + +impl Default for Rng { + fn default() -> Self { + Self::new() + } +} diff --git a/Week-10/Day-66_ISBN-Generator/day66/src/main.rs b/Week-10/Day-66_ISBN-Generator/day66/src/main.rs new file mode 100644 index 0000000..fbf2cd2 --- /dev/null +++ b/Week-10/Day-66_ISBN-Generator/day66/src/main.rs @@ -0,0 +1,14 @@ +use std::io::{self, Write}; + +use day66::isbn_generator; + +fn main() { + let mut _buffer = String::new(); + println!("Press to generate a new ISBN, or to exit the program"); + loop { + let isbn = isbn_generator(); + print!("{isbn}"); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut _buffer).unwrap(); + } +} diff --git a/Week-10/Day-66_ISBN-Generator/day66/tests/checker.rs b/Week-10/Day-66_ISBN-Generator/day66/tests/checker.rs new file mode 100644 index 0000000..2407027 --- /dev/null +++ b/Week-10/Day-66_ISBN-Generator/day66/tests/checker.rs @@ -0,0 +1,27 @@ +#[cfg(test)] +mod checker { + use day66::*; + + fn check() { + assert!(isbn_validator(isbn_generator().trim()).unwrap()); + } + + #[test] + fn gen1() { + check(); + } + + #[test] + fn gen10() { + for _ in 0..10 { + check(); + } + } + + #[test] + fn gen100() { + for _ in 0..100 { + check(); + } + } +}