|  | @@ -6,14 +6,39 @@ New code -
 | 
	
		
			
				|  |  |  The old code below only handles 3x3 puzzles only!
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// use std::fmt;
 | 
	
		
			
				|  |  | +use strum::EnumIter;
 | 
	
		
			
				|  |  | +use strum::IntoEnumIterator;
 | 
	
		
			
				|  |  | +// use strum_macros::EnumIter;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#[derive(Debug, EnumIter, PartialEq, Copy, Clone)]
 | 
	
		
			
				|  |  | +pub enum Groups {
 | 
	
		
			
				|  |  | +    Row,
 | 
	
		
			
				|  |  | +    Column,
 | 
	
		
			
				|  |  | +    Cell,
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + impl fmt::Display for Groups {
 | 
	
		
			
				|  |  | +    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 | 
	
		
			
				|  |  | +        write!(f, "{:?}", self)
 | 
	
		
			
				|  |  | +        // or, alternatively:
 | 
	
		
			
				|  |  | +        // fmt::Debug::fmt(self, f)
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +*/
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #[derive(Debug, Clone)]
 | 
	
		
			
				|  |  |  pub struct AnyGroup {
 | 
	
		
			
				|  |  |      pub size: u8,
 | 
	
		
			
				|  |  |      pub width: u8,
 | 
	
		
			
				|  |  |      pub max_index: usize,
 | 
	
		
			
				|  |  | +    pub groups: [Vec<usize>; 3],
 | 
	
		
			
				|  |  | +    /*
 | 
	
		
			
				|  |  |      pub row: Vec<usize>,
 | 
	
		
			
				|  |  |      pub column: Vec<usize>,
 | 
	
		
			
				|  |  |      pub cell: Vec<usize>,
 | 
	
		
			
				|  |  | +    */
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /// Find the number of digits needed to display given number.
 | 
	
	
		
			
				|  | @@ -29,14 +54,18 @@ fn find_number_width(mut number: usize) -> usize {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  impl AnyGroup {
 | 
	
		
			
				|  |  |      pub fn new(board_size: u8) -> Self {
 | 
	
		
			
				|  |  | -        let width = board_size as usize * board_size as usize;
 | 
	
		
			
				|  |  | +        let b_width = board_size as usize * board_size as usize;
 | 
	
		
			
				|  |  | +        let size = b_width * b_width;
 | 
	
		
			
				|  |  |          let mut g = AnyGroup {
 | 
	
		
			
				|  |  |              size: board_size,
 | 
	
		
			
				|  |  |              width: board_size * board_size,
 | 
	
		
			
				|  |  | -            max_index: width * width,
 | 
	
		
			
				|  |  | -            row: vec![0; width * width],
 | 
	
		
			
				|  |  | -            column: vec![0; width * width],
 | 
	
		
			
				|  |  | -            cell: vec![0; width * width],
 | 
	
		
			
				|  |  | +            max_index: size,
 | 
	
		
			
				|  |  | +            groups: [vec![0; size], vec![0; size], vec![0; size]],
 | 
	
		
			
				|  |  | +            /*
 | 
	
		
			
				|  |  | +            row: vec![0; b_width * b_width],
 | 
	
		
			
				|  |  | +            column: vec![0; size],
 | 
	
		
			
				|  |  | +            cell: vec![0; size],
 | 
	
		
			
				|  |  | +            */
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |          g.calculate();
 | 
	
		
			
				|  |  |          g
 | 
	
	
		
			
				|  | @@ -51,25 +80,31 @@ impl AnyGroup {
 | 
	
		
			
				|  |  |          ((index % width) as u8, (index / width) as u8)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    pub fn group(&self, g: Groups, row: u8) -> &[usize] {
 | 
	
		
			
				|  |  | +        let width = self.width as usize;
 | 
	
		
			
				|  |  | +        let start = row as usize * width;
 | 
	
		
			
				|  |  | +        &self.groups[g as usize][start..start + width]
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      pub fn row(&self, row: u8) -> &[usize] {
 | 
	
		
			
				|  |  |          // return slice of row:
 | 
	
		
			
				|  |  |          let width = self.width as usize;
 | 
	
		
			
				|  |  |          let start = row as usize * width;
 | 
	
		
			
				|  |  | -        &self.row[start..start + width]
 | 
	
		
			
				|  |  | +        &self.groups[Groups::Row as usize][start..start + width]
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      pub fn column(&self, column: u8) -> &[usize] {
 | 
	
		
			
				|  |  |          // return slice of row:
 | 
	
		
			
				|  |  |          let width = self.width as usize;
 | 
	
		
			
				|  |  |          let start = column as usize * width;
 | 
	
		
			
				|  |  | -        &self.column[start..start + width]
 | 
	
		
			
				|  |  | +        &self.groups[Groups::Column as usize][start..start + width]
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      pub fn cell(&self, cell: u8) -> &[usize] {
 | 
	
		
			
				|  |  |          // return slice of cell:
 | 
	
		
			
				|  |  |          let width = self.width as usize;
 | 
	
		
			
				|  |  |          let start = cell as usize * width;
 | 
	
		
			
				|  |  | -        &self.cell[start..start + width]
 | 
	
		
			
				|  |  | +        &self.groups[Groups::Cell as usize][start..start + width]
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Which cell contains (x,y)?
 | 
	
	
		
			
				|  | @@ -81,8 +116,11 @@ impl AnyGroup {
 | 
	
		
			
				|  |  |          for y in 0..self.width {
 | 
	
		
			
				|  |  |              for x in 0..self.width {
 | 
	
		
			
				|  |  |                  let index = x as usize + y as usize * self.width as usize;
 | 
	
		
			
				|  |  | -                self.row[index] = self.pos(x, y);
 | 
	
		
			
				|  |  | -                self.column[index] = self.pos(y, x);
 | 
	
		
			
				|  |  | +                self.groups[Groups::Row as usize][index] = self.pos(x, y);
 | 
	
		
			
				|  |  | +                self.groups[Groups::Column as usize][index] = self.pos(y, x);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                // self.row[index] = self.pos(x, y);
 | 
	
		
			
				|  |  | +                // self.column[index] = self.pos(y, x);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  let x_off = x / self.size;
 | 
	
		
			
				|  |  |                  let y_off = y / self.size;
 | 
	
	
		
			
				|  | @@ -92,11 +130,15 @@ impl AnyGroup {
 | 
	
		
			
				|  |  |                  //    x_mod + y_mod * self.size;
 | 
	
		
			
				|  |  |                  // y is correct:
 | 
	
		
			
				|  |  |                  //    x_off + y_off * self.size
 | 
	
		
			
				|  |  | -                self.cell[index] = self.pos(
 | 
	
		
			
				|  |  | +                self.groups[Groups::Cell as usize][index] =
 | 
	
		
			
				|  |  | +                    self.pos(x_mod + y_mod * self.size, x_off + y_off * self.size);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                /* self.cell[index] = self.pos(
 | 
	
		
			
				|  |  |                      x_mod + y_mod * self.size,
 | 
	
		
			
				|  |  |                      x_off + y_off * self.size, // x_mod + x_off * self.size,
 | 
	
		
			
				|  |  |                                                 // y_off
 | 
	
		
			
				|  |  |                  );
 | 
	
		
			
				|  |  | +                */
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -124,6 +166,23 @@ impl AnyGroup {
 | 
	
		
			
				|  |  |              println!("");
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        for g in Groups::iter() {
 | 
	
		
			
				|  |  | +            println!("{:?}:", g);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            for i in 0..self.width {
 | 
	
		
			
				|  |  | +                let r = self.group(g, i);
 | 
	
		
			
				|  |  | +                /*
 | 
	
		
			
				|  |  | +                print!("[{:2}]: ", i);
 | 
	
		
			
				|  |  | +                for j in r {
 | 
	
		
			
				|  |  | +                    let xy = self.xy(*j);
 | 
	
		
			
				|  |  | +                    print!("{0:1$}({2:2},{3:2}) ", j, max_index_size, xy.0, xy.1);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                println!("");
 | 
	
		
			
				|  |  | +                */
 | 
	
		
			
				|  |  | +                printer(i, r);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        /*
 | 
	
		
			
				|  |  |          println!("rows:");
 | 
	
		
			
				|  |  |          // println!("{:?}", self.row);
 | 
	
		
			
				|  |  |          for i in 0..self.width {
 | 
	
	
		
			
				|  | @@ -167,56 +226,74 @@ impl AnyGroup {
 | 
	
		
			
				|  |  |              */
 | 
	
		
			
				|  |  |              printer(i, r);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        */
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  #[cfg(test)]
 | 
	
		
			
				|  |  |  mod tests {
 | 
	
		
			
				|  |  |      use crate::group::*;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      #[test]
 | 
	
		
			
				|  |  | +    /// Verify that each index (0..max_index) is defined in each group.
 | 
	
		
			
				|  |  | +    /// - Verify that it is used, and only once.
 | 
	
		
			
				|  |  |      fn check_dynamic() {
 | 
	
		
			
				|  |  | -        // Verify that each index (0..max_index) is defined in each group.
 | 
	
		
			
				|  |  | -        // - Verify that it is used, and only once.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          for size in 3..=5 {
 | 
	
		
			
				|  |  |              let g = AnyGroup::new(size);
 | 
	
		
			
				|  |  | +            // g.display();
 | 
	
		
			
				|  |  |              let mut all = vec![0 as u8; g.max_index];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              // Verify the X,Y values are in the correct cell.
 | 
	
		
			
				|  |  | -            all.fill(0);
 | 
	
		
			
				|  |  | +            for gr in Groups::iter() {
 | 
	
		
			
				|  |  | +                all.fill(0);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            for idx in 0..g.width {
 | 
	
		
			
				|  |  | -                let grp = g.cell(idx);
 | 
	
		
			
				|  |  | -                // g.display();
 | 
	
		
			
				|  |  | -                for indexes in grp {
 | 
	
		
			
				|  |  | -                    let (x, y) = g.xy(*indexes);
 | 
	
		
			
				|  |  | +                for idx in 0..g.width {
 | 
	
		
			
				|  |  | +                    let grp = g.group(gr, idx); // cell(idx);
 | 
	
		
			
				|  |  | +                                                // g.display();
 | 
	
		
			
				|  |  | +                    for indexes in grp {
 | 
	
		
			
				|  |  | +                        let (x, y) = g.xy(*indexes);
 | 
	
		
			
				|  |  | +                        assert!(
 | 
	
		
			
				|  |  | +                            all[*indexes] == 0,
 | 
	
		
			
				|  |  | +                            "{:?} Size {} Index [{}]({},{}) already seen",
 | 
	
		
			
				|  |  | +                            gr,
 | 
	
		
			
				|  |  | +                            size,
 | 
	
		
			
				|  |  | +                            *indexes,
 | 
	
		
			
				|  |  | +                            x + 1,
 | 
	
		
			
				|  |  | +                            y + 1
 | 
	
		
			
				|  |  | +                        );
 | 
	
		
			
				|  |  | +                        all[*indexes] = 1;
 | 
	
		
			
				|  |  | +                        if gr == Groups::Cell {
 | 
	
		
			
				|  |  | +                            assert_eq!(
 | 
	
		
			
				|  |  | +                                g.which_cell(x, y),
 | 
	
		
			
				|  |  | +                                idx,
 | 
	
		
			
				|  |  | +                                "Verify {:?} [{}]({},{}) in cell {}",
 | 
	
		
			
				|  |  | +                                gr,
 | 
	
		
			
				|  |  | +                                *indexes,
 | 
	
		
			
				|  |  | +                                x,
 | 
	
		
			
				|  |  | +                                y,
 | 
	
		
			
				|  |  | +                                idx
 | 
	
		
			
				|  |  | +                            );
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                for indexes in 0..g.max_index {
 | 
	
		
			
				|  |  | +                    let (x, y) = g.xy(indexes);
 | 
	
		
			
				|  |  |                      assert!(
 | 
	
		
			
				|  |  | -                        all[*indexes] == 0,
 | 
	
		
			
				|  |  | -                        "Size {} Index [{}]({},{}) already seen",
 | 
	
		
			
				|  |  | +                        all[indexes] == 1,
 | 
	
		
			
				|  |  | +                        "{:?} Size {} Index [{}]({},{}) not seen",
 | 
	
		
			
				|  |  | +                        gr,
 | 
	
		
			
				|  |  |                          size,
 | 
	
		
			
				|  |  | -                        *indexes,
 | 
	
		
			
				|  |  | +                        indexes,
 | 
	
		
			
				|  |  |                          x + 1,
 | 
	
		
			
				|  |  |                          y + 1
 | 
	
		
			
				|  |  |                      );
 | 
	
		
			
				|  |  | -                    all[*indexes] = 1;
 | 
	
		
			
				|  |  | -                    assert_eq!(g.which_cell(x, y), idx, "Verify [{}]({},{}) in cell {}", *indexes, x, y, idx);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            for indexes in 0..g.max_index {
 | 
	
		
			
				|  |  | -                let (x, y) = g.xy(indexes);
 | 
	
		
			
				|  |  | -                assert!(
 | 
	
		
			
				|  |  | -                    all[indexes] == 1,
 | 
	
		
			
				|  |  | -                    "Size {} Index [{}]({},{}) not seen",
 | 
	
		
			
				|  |  | -                    size,
 | 
	
		
			
				|  |  | -                    indexes,
 | 
	
		
			
				|  |  | -                    x + 1,
 | 
	
		
			
				|  |  | -                    y + 1
 | 
	
		
			
				|  |  | -                );
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +            /* 
 | 
	
		
			
				|  |  |              all.fill(0);
 | 
	
		
			
				|  |  |              for idx in 0..g.width {
 | 
	
		
			
				|  |  |                  let grp = g.row(idx);
 | 
	
	
		
			
				|  | @@ -277,6 +354,7 @@ mod tests {
 | 
	
		
			
				|  |  |                      y + 1
 | 
	
		
			
				|  |  |                  );
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | +            */
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 |