|  | @@ -114,6 +114,8 @@ impl error::Error for GameLoadError {}
 | 
	
		
			
				|  |  |  #[derive(Debug, Clone)]
 | 
	
		
			
				|  |  |  pub struct AnyBoard {
 | 
	
		
			
				|  |  |      pub size: u8,
 | 
	
		
			
				|  |  | +    pub width: u8,
 | 
	
		
			
				|  |  | +    pub max_index: usize,
 | 
	
		
			
				|  |  |      pub board: Vec<u8>,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -126,11 +128,14 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |          let n = board_size as usize;
 | 
	
		
			
				|  |  |          let s = AnyBoard {
 | 
	
		
			
				|  |  |              size: board_size,
 | 
	
		
			
				|  |  | +            width: board_size*board_size,
 | 
	
		
			
				|  |  | +            max_index: n*n*n*n,
 | 
	
		
			
				|  |  |              board: vec![0; n * n * n * n],
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |          s
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    /*
 | 
	
		
			
				|  |  |      /// Max board width (size*size)
 | 
	
		
			
				|  |  |      pub fn width(&self) -> u8 {
 | 
	
		
			
				|  |  |          self.size * self.size
 | 
	
	
		
			
				|  | @@ -140,6 +145,7 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |      pub fn max_index(&self) -> usize {
 | 
	
		
			
				|  |  |          self.width() as usize * self.width() as usize
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Clear out the board
 | 
	
		
			
				|  |  |      pub fn clear(&mut self) {
 | 
	
	
		
			
				|  | @@ -148,12 +154,12 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Calculate index position of (x,y)
 | 
	
		
			
				|  |  |      pub fn pos(&self, x: u8, y: u8) -> usize {
 | 
	
		
			
				|  |  | -        x as usize + y as usize * self.width() as usize
 | 
	
		
			
				|  |  | +        x as usize + y as usize * self.width as usize
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Set a position in the board with a value
 | 
	
		
			
				|  |  |      pub fn set(&mut self, x: u8, y: u8, value: u8) {
 | 
	
		
			
				|  |  | -        assert!(value <= self.size * self.size);
 | 
	
		
			
				|  |  | +        assert!(value <= self.width);
 | 
	
		
			
				|  |  |          let index = self.pos(x, y);
 | 
	
		
			
				|  |  |          assert!(index <= self.board.capacity());
 | 
	
		
			
				|  |  |          self.board[index] = value;
 | 
	
	
		
			
				|  | @@ -177,13 +183,13 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |          let mut x: u8 = 0;
 | 
	
		
			
				|  |  |          let mut y: u8 = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        if s.len() != self.max_index() {
 | 
	
		
			
				|  |  | +        if s.len() != self.max_index {
 | 
	
		
			
				|  |  |              // self.size * self.size*self.size*self.size {
 | 
	
		
			
				|  |  |              return Err(Box::new(GameLoadError {
 | 
	
		
			
				|  |  |                  message: format!(
 | 
	
		
			
				|  |  |                      "String exceeds ({}) expected length {}.",
 | 
	
		
			
				|  |  |                      s.len(),
 | 
	
		
			
				|  |  | -                    self.size * self.size
 | 
	
		
			
				|  |  | +                    self.width
 | 
	
		
			
				|  |  |                  ),
 | 
	
		
			
				|  |  |              }));
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -191,20 +197,20 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |          for ch in s.chars() {
 | 
	
		
			
				|  |  |              if ch != blank {
 | 
	
		
			
				|  |  |                  let value = (ch as u8 - start_ch as u8) + 1;
 | 
	
		
			
				|  |  | -                if value == 0 || value > self.width() {
 | 
	
		
			
				|  |  | +                if value == 0 || value > self.width {
 | 
	
		
			
				|  |  |                      return Err(Box::new(GameLoadError {
 | 
	
		
			
				|  |  |                          message: format!(
 | 
	
		
			
				|  |  |                              "String symbol ({}) represents value {}, expecting 1 to {}.",
 | 
	
		
			
				|  |  |                              ch,
 | 
	
		
			
				|  |  |                              value,
 | 
	
		
			
				|  |  | -                            self.size * self.size
 | 
	
		
			
				|  |  | +                            self.width
 | 
	
		
			
				|  |  |                          ),
 | 
	
		
			
				|  |  |                      }));
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |                  self.set(x, y, value);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              y += 1;
 | 
	
		
			
				|  |  | -            if y >= self.size * self.size {
 | 
	
		
			
				|  |  | +            if y >= self.width {
 | 
	
		
			
				|  |  |                  y = 0;
 | 
	
		
			
				|  |  |                  x += 1;
 | 
	
		
			
				|  |  |              }
 | 
	
	
		
			
				|  | @@ -215,12 +221,12 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |      /// Save puzzle to a string (top,left) going down.
 | 
	
		
			
				|  |  |      pub fn save_to_tld(&self, start_ch: char, blank: char) -> String {
 | 
	
		
			
				|  |  |          let mut result = String::new();
 | 
	
		
			
				|  |  | -        result.reserve(self.max_index());
 | 
	
		
			
				|  |  | +        result.reserve(self.max_index);
 | 
	
		
			
				|  |  |          let start_ch = (start_ch as u8 - 1) as char;
 | 
	
		
			
				|  |  |          let mut x: u8 = 0;
 | 
	
		
			
				|  |  |          let mut y: u8 = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        for _i in 0..self.max_index() {
 | 
	
		
			
				|  |  | +        for _i in 0..self.max_index {
 | 
	
		
			
				|  |  |              let value = self.get(x, y);
 | 
	
		
			
				|  |  |              if value == 0 {
 | 
	
		
			
				|  |  |                  result.push(blank);
 | 
	
	
		
			
				|  | @@ -228,7 +234,7 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |                  result.push((start_ch as u8 + value) as char);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              y += 1;
 | 
	
		
			
				|  |  | -            if y >= self.width() {
 | 
	
		
			
				|  |  | +            if y >= self.width {
 | 
	
		
			
				|  |  |                  y = 0;
 | 
	
		
			
				|  |  |                  x += 1;
 | 
	
		
			
				|  |  |              }
 | 
	
	
		
			
				|  | @@ -236,9 +242,68 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |          result
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    /// Load puzzle from string (top,left) going right.
 | 
	
		
			
				|  |  | +    pub fn load_from_tlr(
 | 
	
		
			
				|  |  | +        &mut self,
 | 
	
		
			
				|  |  | +        start_ch: char,
 | 
	
		
			
				|  |  | +        blank: char,
 | 
	
		
			
				|  |  | +        s: &str,
 | 
	
		
			
				|  |  | +    ) -> Result<(), Box<dyn error::Error>> {
 | 
	
		
			
				|  |  | +        self.clear();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if s.len() != self.max_index {
 | 
	
		
			
				|  |  | +            // self.size * self.size*self.size*self.size {
 | 
	
		
			
				|  |  | +            return Err(Box::new(GameLoadError {
 | 
	
		
			
				|  |  | +                message: format!(
 | 
	
		
			
				|  |  | +                    "String exceeds ({}) expected length {}.",
 | 
	
		
			
				|  |  | +                    s.len(),
 | 
	
		
			
				|  |  | +                    self.width
 | 
	
		
			
				|  |  | +                ),
 | 
	
		
			
				|  |  | +            }));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        let mut i: usize = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        for ch in s.chars() {
 | 
	
		
			
				|  |  | +            if ch != blank {
 | 
	
		
			
				|  |  | +                let value = (ch as u8 - start_ch as u8) + 1;
 | 
	
		
			
				|  |  | +                if value == 0 || value > self.width {
 | 
	
		
			
				|  |  | +                    return Err(Box::new(GameLoadError {
 | 
	
		
			
				|  |  | +                        message: format!(
 | 
	
		
			
				|  |  | +                            "String symbol ({}) represents value {}, expecting 1 to {}.",
 | 
	
		
			
				|  |  | +                            ch,
 | 
	
		
			
				|  |  | +                            value,
 | 
	
		
			
				|  |  | +                            self.width
 | 
	
		
			
				|  |  | +                        ),
 | 
	
		
			
				|  |  | +                    }));
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                self.board[i] = value;
 | 
	
		
			
				|  |  | +                i += 1;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        Ok(())
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// Save puzzle to a string (top,left) going right.
 | 
	
		
			
				|  |  | +    pub fn save_to_tlr(&self, start_ch: char, blank: char) -> String {
 | 
	
		
			
				|  |  | +        let mut result = String::new();
 | 
	
		
			
				|  |  | +        result.reserve(self.max_index);
 | 
	
		
			
				|  |  | +        let start_ch = (start_ch as u8 - 1) as char;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        for i in 0..self.max_index {
 | 
	
		
			
				|  |  | +            let value = self.board[i];
 | 
	
		
			
				|  |  | +            if value == 0 {
 | 
	
		
			
				|  |  | +                result.push(blank);
 | 
	
		
			
				|  |  | +            } else {
 | 
	
		
			
				|  |  | +                result.push((start_ch as u8 + value) as char);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        result
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      pub fn display(&self) {
 | 
	
		
			
				|  |  |          let line = "═".repeat(self.size as usize);
 | 
	
		
			
				|  |  | -        let alpha_display = self.width() >= 10;
 | 
	
		
			
				|  |  | +        let alpha_display = self.width >= 10;
 | 
	
		
			
				|  |  |          // println!("╔{}╦{}╦{}╗", line, line, line);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          println!("alpha = {}", alpha_display);
 | 
	
	
		
			
				|  | @@ -253,9 +318,9 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          println!("╗");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        for y in 0..self.width() {
 | 
	
		
			
				|  |  | +        for y in 0..self.width {
 | 
	
		
			
				|  |  |              print!("║");
 | 
	
		
			
				|  |  | -            for x in 0..self.width() {
 | 
	
		
			
				|  |  | +            for x in 0..self.width {
 | 
	
		
			
				|  |  |                  let value = self.get(x, y);
 | 
	
		
			
				|  |  |                  if value == 0 {
 | 
	
		
			
				|  |  |                      print!(" ");
 | 
	
	
		
			
				|  | @@ -272,7 +337,7 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              println!("");
 | 
	
		
			
				|  |  |              if y % self.size == self.size - 1 {
 | 
	
		
			
				|  |  | -                if y + 1 == self.width() {
 | 
	
		
			
				|  |  | +                if y + 1 == self.width {
 | 
	
		
			
				|  |  |                      // Bottom
 | 
	
		
			
				|  |  |                      for i in 0..self.size {
 | 
	
		
			
				|  |  |                          if i == 0 {
 | 
	
	
		
			
				|  | @@ -299,6 +364,20 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// Is the puzzle completed?
 | 
	
		
			
				|  |  | +    /// Have all of the locations been filled with a value?
 | 
	
		
			
				|  |  | +    /// - This does not validate that it is a correct puzzle.
 | 
	
		
			
				|  |  | +    ///   It doesn't check for duplicate digits (for example).
 | 
	
		
			
				|  |  | +    pub fn complete(&self) -> bool {
 | 
	
		
			
				|  |  | +        for i in 0..self.max_index {
 | 
	
		
			
				|  |  | +            if self.board[i] == 0 {
 | 
	
		
			
				|  |  | +                return false;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        true
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // Need to use u32, so 5*5=25, 25 bits can be accessed.
 | 
	
	
		
			
				|  | @@ -307,25 +386,35 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |  #[derive(Debug, Clone)]
 | 
	
		
			
				|  |  |  pub struct AnyPossible {
 | 
	
		
			
				|  |  |      pub size: u8,
 | 
	
		
			
				|  |  | +    pub width: u8,
 | 
	
		
			
				|  |  | +    pub max_index: usize,
 | 
	
		
			
				|  |  |      pub possible: Vec<GenBits<u32>>,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  impl AnyPossible {
 | 
	
		
			
				|  |  |      pub fn new(board_size: u8) -> Self {
 | 
	
		
			
				|  |  |          let mut initial = GenBits::<u32>(0);
 | 
	
		
			
				|  |  | -        initial.set_bits(1..board_size);
 | 
	
		
			
				|  |  | +        let width = board_size * board_size;
 | 
	
		
			
				|  |  | +        initial.set_bits(1..width);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          Self {
 | 
	
		
			
				|  |  |              size: board_size,
 | 
	
		
			
				|  |  | -            possible: vec![initial; board_size as usize * board_size as usize],
 | 
	
		
			
				|  |  | +            width: width,
 | 
	
		
			
				|  |  | +            max_index: width as usize * width as usize,
 | 
	
		
			
				|  |  | +            possible: vec![initial; width as usize * width as usize],
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      pub fn clear(&mut self) {
 | 
	
		
			
				|  |  |          let mut initial = GenBits::<u32>(0);
 | 
	
		
			
				|  |  | -        initial.set_bits(1..self.size);
 | 
	
		
			
				|  |  | -        self.possible = vec![initial; self.size as usize * self.size as usize];
 | 
	
		
			
				|  |  | +        // let width = self.size * self.size;
 | 
	
		
			
				|  |  | +        initial.set_bits(1..self.width);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        self.possible = vec![initial; self.max_index]; 
 | 
	
		
			
				|  |  | +        // width as usize * width as usize];
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    #[inline]
 | 
	
		
			
				|  |  |      pub fn set(&mut self, index: usize, value: usize, state: bool) {
 | 
	
		
			
				|  |  |          self.possible[index].set(value, state);
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -341,7 +430,7 @@ impl AnySolver {
 | 
	
		
			
				|  |  |      pub fn new(initial_board: &AnyBoard) -> Self {
 | 
	
		
			
				|  |  |          let mut s = AnySolver {
 | 
	
		
			
				|  |  |              board: initial_board.clone(),
 | 
	
		
			
				|  |  | -            possible: AnyPossible::new(initial_board.max_index() as u8),
 | 
	
		
			
				|  |  | +            possible: AnyPossible::new(initial_board.size),
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |          s.reset_possible();
 | 
	
		
			
				|  |  |          s
 | 
	
	
		
			
				|  | @@ -372,8 +461,8 @@ impl AnySolver {
 | 
	
		
			
				|  |  |      /// - When something has changed, and the possibles are out of sync.
 | 
	
		
			
				|  |  |      pub fn reset_possible(&mut self) {
 | 
	
		
			
				|  |  |          self.possible.clear();
 | 
	
		
			
				|  |  | -        for y in 0..self.board.width() {
 | 
	
		
			
				|  |  | -            for x in 0..self.board.width() {
 | 
	
		
			
				|  |  | +        for y in 0..self.board.width {
 | 
	
		
			
				|  |  | +            for x in 0..self.board.width {
 | 
	
		
			
				|  |  |                  let value = self.board.get(x, y);
 | 
	
		
			
				|  |  |                  if value != 0 {
 | 
	
		
			
				|  |  |                      self.process_move(x, y, value);
 | 
	
	
		
			
				|  | @@ -381,6 +470,15 @@ impl AnySolver {
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// set (x,y) to value.
 | 
	
		
			
				|  |  | +    /// - This updates the board.
 | 
	
		
			
				|  |  | +    /// - This updates all the possibles (row,column,cell).
 | 
	
		
			
				|  |  | +    /// - Clears the possible for (x,y) [See process_move].
 | 
	
		
			
				|  |  | +    pub fn set(&mut self, x: u8, y: u8, value: u8) {
 | 
	
		
			
				|  |  | +        self.board.set(x, y, value);
 | 
	
		
			
				|  |  | +        self.process_move(x, y, value);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #[cfg(test)]
 |