Skip to main content

ternary_spreadsheet/
grid.rs

1use crate::cell::{Cell, TernaryValue};
2
3/// A 2D grid of ternary cells.
4#[derive(Debug, Clone)]
5pub struct Grid {
6    cells: Vec<Vec<Cell>>,
7    rows: usize,
8    cols: usize,
9}
10
11impl Grid {
12    /// Create a new grid filled with neutral cells.
13    pub fn new(rows: usize, cols: usize) -> Self {
14        let cells = (0..rows)
15            .map(|_| (0..cols).map(|_| Cell::neutral()).collect())
16            .collect();
17        Grid { cells, rows, cols }
18    }
19
20    /// Grid dimensions as (rows, cols).
21    pub fn dimensions(&self) -> (usize, usize) {
22        (self.rows, self.cols)
23    }
24
25    /// Number of rows.
26    pub fn rows(&self) -> usize {
27        self.rows
28    }
29
30    /// Number of columns.
31    pub fn cols(&self) -> usize {
32        self.cols
33    }
34
35    /// Get a cell reference.
36    pub fn get(&self, row: usize, col: usize) -> Option<&Cell> {
37        self.cells.get(row).and_then(|r| r.get(col))
38    }
39
40    /// Get a mutable cell reference.
41    pub fn get_mut(&mut self, row: usize, col: usize) -> Option<&mut Cell> {
42        self.cells.get_mut(row).and_then(|r| r.get_mut(col))
43    }
44
45    /// Set a cell value directly.
46    pub fn set(&mut self, row: usize, col: usize, value: TernaryValue) {
47        if let Some(cell) = self.get_mut(row, col) {
48            cell.set_value(value);
49        }
50    }
51
52    /// Get a whole row.
53    pub fn row(&self, row: usize) -> Option<&[Cell]> {
54        self.cells.get(row).map(|r| r.as_slice())
55    }
56
57    /// Get a whole column.
58    pub fn col(&self, col: usize) -> Option<Vec<Cell>> {
59        if col >= self.cols {
60            return None;
61        }
62        Some(self.cells.iter().map(|r| r[col].clone()).collect())
63    }
64
65    /// Get all cells flattened.
66    pub fn cells(&self) -> Vec<&Cell> {
67        self.cells.iter().flat_map(|r| r.iter()).collect()
68    }
69
70    /// Get all cells in a range (inclusive).
71    pub fn range(&self, r1: usize, c1: usize, r2: usize, c2: usize) -> Vec<&Cell> {
72        let (r_min, r_max) = (r1.min(r2), r1.max(r2));
73        let (c_min, c_max) = (c1.min(c2), c1.max(c2));
74        self.cells.iter()
75            .enumerate()
76            .filter(|(r, _)| *r >= r_min && *r <= r_max)
77            .flat_map(|(_, row)| {
78                row.iter()
79                    .enumerate()
80                    .filter(|(c, _)| *c >= c_min && *c <= c_max)
81                    .map(|(_, cell)| cell)
82            })
83            .collect()
84    }
85
86    /// Get mutable references to all cells in a range.
87    pub fn range_mut(&mut self, r1: usize, c1: usize, r2: usize, c2: usize) -> Vec<&mut Cell> {
88        let (r_min, r_max) = (r1.min(r2), r1.max(r2));
89        let (c_min, c_max) = (c1.min(c2), c1.max(c2));
90        self.cells.iter_mut()
91            .enumerate()
92            .filter(move |(r, _)| *r >= r_min && *r <= r_max)
93            .flat_map(move |(_, row)| {
94                row.iter_mut()
95                    .enumerate()
96                    .filter(move |(c, _)| *c >= c_min && *c <= c_max)
97                    .map(|(_, cell)| cell)
98            })
99            .collect()
100    }
101
102    /// Apply a function to every cell.
103    pub fn for_each<F: FnMut(&mut Cell)>(&mut self, mut f: F) {
104        for row in &mut self.cells {
105            for cell in row.iter_mut() {
106                f(cell);
107            }
108        }
109    }
110
111    /// Total cell count.
112    pub fn len(&self) -> usize {
113        self.rows * self.cols
114    }
115
116    /// Is the grid empty?
117    pub fn is_empty(&self) -> bool {
118        self.rows == 0 || self.cols == 0
119    }
120
121    /// Compute default fitness for all cells.
122    pub fn compute_all_fitness(&mut self) {
123        for row in &mut self.cells {
124            for cell in row.iter_mut() {
125                cell.set_fitness(cell.compute_default_fitness());
126            }
127        }
128    }
129
130    /// Get mutable access to all rows (for sorting/reordering).
131    pub fn rows_mut(&mut self) -> &mut Vec<Vec<Cell>> {
132        &mut self.cells
133    }
134
135    /// Parse a cell reference like "A1" into (row, col).
136    pub fn parse_cell_ref(s: &str) -> Option<(usize, usize)> {
137        let s = s.trim();
138        let col_end = s.chars().position(|c| c.is_ascii_digit())?;
139        let col_str = &s[..col_end];
140        let row_str = &s[col_end..];
141
142        let mut col: usize = 0;
143        for ch in col_str.chars() {
144            if !ch.is_ascii_alphabetic() {
145                return None;
146            }
147            col = col * 26 + (ch.to_ascii_uppercase() as usize - 'A' as usize + 1);
148        }
149        if col == 0 { return None; }
150        col -= 1;
151
152        let row: usize = row_str.parse().ok()?;
153        if row == 0 { return None; }
154        Some((row - 1, col))
155    }
156}