Skip to main content

ternary_spreadsheet/
autofill.rs

1use crate::cell::TernaryValue;
2use crate::grid::Grid;
3
4/// Configuration for autofill mutation.
5#[derive(Debug, Clone)]
6pub struct MutationConfig {
7    /// Probability of mutation per cell (0.0 - 1.0).
8    pub mutation_rate: f64,
9    /// If true, mutations can flip sign; otherwise they tend toward neutral.
10    pub allow_flip: bool,
11    /// Seed for deterministic behavior (None = use counter).
12    pub seed: Option<u64>,
13}
14
15impl Default for MutationConfig {
16    fn default() -> Self {
17        MutationConfig {
18            mutation_rate: 0.3,
19            allow_flip: true,
20            seed: None,
21        }
22    }
23}
24
25/// Autofill a range with mutation. Takes the source cell's value and propagates it
26/// across the target range, applying random mutations based on the config.
27/// Returns the number of cells mutated.
28pub fn autofill_mutate(
29    grid: &mut Grid,
30    src_row: usize,
31    src_col: usize,
32    dst_r1: usize,
33    dst_c1: usize,
34    dst_r2: usize,
35    dst_c2: usize,
36    config: &MutationConfig,
37) -> usize {
38    let source = grid.get(src_row, src_col)
39        .map(|c| c.value)
40        .unwrap_or(TernaryValue::Neutral);
41
42    let (r_min, r_max) = (dst_r1.min(dst_r2), dst_r1.max(dst_r2));
43    let (c_min, c_max) = (dst_c1.min(dst_c2), dst_c1.max(dst_c2));
44
45    let mut mutated = 0usize;
46    let mut counter: u64 = config.seed.unwrap_or(42);
47
48    for r in r_min..=r_max {
49        for c in c_min..=c_max {
50            // Skip source cell
51            if r == src_row && c == src_col {
52                continue;
53            }
54
55            counter = counter.wrapping_mul(6364136223846793005).wrapping_add(1);
56            let rand_val = (counter >> 33) as f64 / (1u64 << 31) as f64;
57
58            let new_value = if rand_val < config.mutation_rate {
59                mutated += 1;
60                if config.allow_flip {
61                    counter = counter.wrapping_mul(6364136223846793005).wrapping_add(1);
62                    let flip_val = (counter >> 33) as u32;
63                    TernaryValue::from_seed(flip_val)
64                } else {
65                    TernaryValue::Neutral
66                }
67            } else {
68                source
69            };
70
71            if let Some(cell) = grid.get_mut(r, c) {
72                cell.set_value(new_value);
73            }
74        }
75    }
76
77    mutated
78}