claudiofsr_lib/random.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
use crate::MyResult;
use std::hash::{BuildHasher, Hasher, RandomState};
/**
Shuffle the vector in place with the Fisher-Yates algorithm.
```
use claudiofsr_lib::shuffle;
let mut strings = vec!["abc", "foo", "bar", "baz", "mm nn", "zzz"];
shuffle(&mut strings);
println!("strings: {:?}", strings);
let mut integers: Vec<u32> = (1..=20).collect();
shuffle(&mut integers);
println!("integers: {:?}", integers);
```
<https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle>
<https://stackoverflow.com/questions/26033976/how-do-i-create-a-vec-from-a-range-and-shuffle-it>
*/
pub fn shuffle<T>(vec: &mut [T]) {
let n: usize = vec.len();
for i in 0..(n - 1) {
// Generate random index j, such that: i <= j < n
// The remainder (`%`) after division is always less than the divisor.
let j = (rand() as usize) % (n - i) + i;
vec.swap(i, j);
}
}
/// Generate a random integer value in the given range (min, max) inclusive.
pub fn get_random_integer(min: u64, max: u64) -> u64 {
min + rand() % (max - min + 1)
}
/// Generate a random integer value in the given range (min, max) inclusive.
///
/// Return error if `min > max``
pub fn get_random_integer_v2(min: u64, max: u64) -> MyResult<u64> {
if min > max {
let msg = format!("min ({min}) must be less than or equal to max ({max})");
Err(msg.into())
} else {
// The remainder (`%`) after division is always less than the divisor.
Ok(min + rand() % (max - min + 1))
}
}
/// Generate random numbers without external dependencies
pub fn rand() -> u64 {
RandomState::new().build_hasher().finish()
}
#[cfg(test)]
mod test_random {
use crate::*;
#[test]
/// `cargo test -- --show-output vec_shuffle`
fn vec_shuffle() {
let mut vec: Vec<u32> = (1..=100).collect();
shuffle(&mut vec);
println!("vec: {:?}", vec);
assert_eq!(vec.len(), 100);
}
#[test]
/// `cargo test -- --show-output random_integers_v1`
///
/// <https://stackoverflow.com/questions/48218459/how-do-i-generate-a-vector-of-random-numbers-in-a-range>
fn random_integers_v1() {
// Example: Get a random integer value in the range 1 to 20:
let value: u64 = get_random_integer(1, 20);
println!("integer: {:?}", value);
// Generate a vector of 100 64-bit integer values in the range from 1 to 20,
// allowing duplicates:
let integers: Vec<u64> = (0..100).map(|_| get_random_integer(1, 20)).collect();
println!("integers: {:?}", integers);
let condition_a = integers.iter().min() >= Some(&1);
let condition_b = integers.iter().max() <= Some(&20);
assert!(condition_a);
assert!(condition_b);
assert_eq!(integers.len(), 100);
}
#[test]
/// `cargo test -- --show-output random_integers_v2`
///
/// <https://stackoverflow.com/questions/48218459/how-do-i-generate-a-vector-of-random-numbers-in-a-range>
fn random_integers_v2() -> MyResult<()> {
// Example: Get a random integer value in the range 1 to 20:
let value: u64 = get_random_integer_v2(1, 20)?;
println!("integer: {:?}", value);
// Generate a vector of 100 64-bit integer values in the range from 1 to 20,
// allowing duplicates:
let integers: Vec<u64> = (0..100)
.map(|_| get_random_integer_v2(1, 20))
.collect::<Result<Vec<u64>, _>>()?;
println!("integers: {:?}", integers);
let condition_a = integers.iter().min() >= Some(&1);
let condition_b = integers.iter().max() <= Some(&20);
assert!(condition_a);
assert!(condition_b);
assert_eq!(integers.len(), 100);
Ok(())
}
#[test]
/// `cargo test -- --show-output random_integers_v3`
fn random_integers_v3() -> MyResult<()> {
let result = get_random_integer_v2(21, 20).map_err(|err| {
eprintln!("{err}");
err
});
assert!(result.is_err());
let error = result.unwrap_err();
eprintln!("error: {error:?}");
Ok(())
}
}