use crate::models::config::Distribution;
use rand::{Rng, SeedableRng};
use rand::rngs::StdRng;
#[derive(Debug)]
pub struct ArrayGenerator {
seed: u64,
}
impl ArrayGenerator {
pub fn new(seed: u64) -> Self {
Self { seed }
}
pub fn generate(&self, size: usize, distribution: &Distribution) -> Vec<i32> {
if size == 0 {
return Vec::new();
}
match distribution {
Distribution::Shuffled => self.generate_shuffled(size),
Distribution::NearlySorted => self.generate_nearly_sorted(size),
Distribution::Reversed => self.generate_reversed(size),
Distribution::FewUnique => self.generate_few_unique(size),
Distribution::Sorted => self.generate_sorted(size),
Distribution::WithDuplicates => self.generate_with_duplicates(size),
}
}
fn generate_shuffled(&self, size: usize) -> Vec<i32> {
let mut rng = StdRng::seed_from_u64(self.seed);
let mut array: Vec<i32> = (1..=size as i32).collect();
for i in (1..size).rev() {
let j = rng.random_range(0..=i);
array.swap(i, j);
}
array
}
fn generate_nearly_sorted(&self, size: usize) -> Vec<i32> {
let mut rng = StdRng::seed_from_u64(self.seed);
let mut array: Vec<i32> = (1..=size as i32).collect();
let swaps = (size / 10).max(1);
for _ in 0..swaps {
let i = rng.random_range(0..size);
let j = rng.random_range(0..size);
array.swap(i, j);
}
array
}
fn generate_reversed(&self, size: usize) -> Vec<i32> {
(1..=size as i32).rev().collect()
}
fn generate_few_unique(&self, size: usize) -> Vec<i32> {
let mut rng = StdRng::seed_from_u64(self.seed);
let unique_count = (size / 10).max(3).min(size); let values: Vec<i32> = (1..=unique_count as i32).collect();
let mut array = Vec::with_capacity(size);
for _ in 0..size {
let idx = rng.random_range(0..values.len());
array.push(values[idx]);
}
array
}
fn generate_sorted(&self, size: usize) -> Vec<i32> {
(1..=size as i32).collect()
}
fn generate_with_duplicates(&self, size: usize) -> Vec<i32> {
let mut rng = StdRng::seed_from_u64(self.seed);
let mut array = Vec::with_capacity(size);
for i in 0..size {
if i < size / 2 {
array.push((i + 1) as i32);
} else {
let idx = rng.random_range(0..size / 2);
array.push((idx + 1) as i32);
}
}
for i in (1..size).rev() {
let j = rng.random_range(0..=i);
array.swap(i, j);
}
array
}
pub fn validate_array(array: &[i32], size: usize, distribution: &Distribution) -> bool {
if array.len() != size {
return false;
}
if size == 0 {
return true;
}
match distribution {
Distribution::Sorted => {
array.windows(2).all(|w| w[0] <= w[1])
}
Distribution::Reversed => {
array.windows(2).all(|w| w[0] >= w[1])
}
_ => {
array.iter().all(|&x| x > 0 && x <= size as i32 * 2)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_deterministic_generation() {
let gen1 = ArrayGenerator::new(42);
let gen2 = ArrayGenerator::new(42);
let array1 = gen1.generate(10, &Distribution::Shuffled);
let array2 = gen2.generate(10, &Distribution::Shuffled);
assert_eq!(array1, array2);
}
#[test]
fn test_different_seeds() {
let gen1 = ArrayGenerator::new(42);
let gen2 = ArrayGenerator::new(43);
let array1 = gen1.generate(10, &Distribution::Shuffled);
let array2 = gen2.generate(10, &Distribution::Shuffled);
assert_ne!(array1, array2);
}
#[test]
fn test_sorted_distribution() {
let generator = ArrayGenerator::new(42);
let array = generator.generate(10, &Distribution::Sorted);
assert_eq!(array, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
}
#[test]
fn test_reversed_distribution() {
let generator = ArrayGenerator::new(42);
let array = generator.generate(10, &Distribution::Reversed);
assert_eq!(array, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 1]);
}
#[test]
fn test_empty_array() {
let generator = ArrayGenerator::new(42);
let array = generator.generate(0, &Distribution::Shuffled);
assert!(array.is_empty());
}
#[test]
fn test_array_validation() {
let generator = ArrayGenerator::new(42);
let sorted = generator.generate(5, &Distribution::Sorted);
assert!(ArrayGenerator::validate_array(&sorted, 5, &Distribution::Sorted));
let reversed = generator.generate(5, &Distribution::Reversed);
assert!(ArrayGenerator::validate_array(&reversed, 5, &Distribution::Reversed));
let shuffled = generator.generate(5, &Distribution::Shuffled);
assert!(ArrayGenerator::validate_array(&shuffled, 5, &Distribution::Shuffled));
}
}