|  | @@ -301,13 +301,12 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |          result
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    /// Display board using unicode box characters.
 | 
	
		
			
				|  |  |      pub fn display(&self) {
 | 
	
		
			
				|  |  |          let line = "═".repeat(self.size as usize);
 | 
	
		
			
				|  |  |          let alpha_display = self.width >= 10;
 | 
	
		
			
				|  |  |          // println!("╔{}╦{}╦{}╗", line, line, line);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        println!("alpha = {}", alpha_display);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |          // Top
 | 
	
		
			
				|  |  |          for i in 0..self.size {
 | 
	
		
			
				|  |  |              if i == 0 {
 | 
	
	
		
			
				|  | @@ -380,6 +379,7 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  // Need to use u32, so 5*5=25, 25 bits can be accessed.
 | 
	
		
			
				|  |  |  // u16 is fine for 3*3=9.
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -395,7 +395,7 @@ impl AnyPossible {
 | 
	
		
			
				|  |  |      pub fn new(board_size: u8) -> Self {
 | 
	
		
			
				|  |  |          let mut initial = GenBits::<u32>(0);
 | 
	
		
			
				|  |  |          let width = board_size * board_size;
 | 
	
		
			
				|  |  | -        initial.set_bits(1..width);
 | 
	
		
			
				|  |  | +        initial.set_bits(0..width);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          Self {
 | 
	
		
			
				|  |  |              size: board_size,
 | 
	
	
		
			
				|  | @@ -408,22 +408,35 @@ impl AnyPossible {
 | 
	
		
			
				|  |  |      pub fn clear(&mut self) {
 | 
	
		
			
				|  |  |          let mut initial = GenBits::<u32>(0);
 | 
	
		
			
				|  |  |          // let width = self.size * self.size;
 | 
	
		
			
				|  |  | -        initial.set_bits(1..self.width);
 | 
	
		
			
				|  |  | +        initial.set_bits(0..self.width);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          self.possible = vec![initial; self.max_index]; 
 | 
	
		
			
				|  |  |          // width as usize * width as usize];
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    // NOTE: values range from 1..width. Bits range from 0..width-1
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  |      #[inline]
 | 
	
		
			
				|  |  |      pub fn set(&mut self, index: usize, value: usize, state: bool) {
 | 
	
		
			
				|  |  | -        self.possible[index].set(value, state);
 | 
	
		
			
				|  |  | +        self.possible[index].set(value -1, state);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    #[inline]
 | 
	
		
			
				|  |  | +    pub fn get(&self, index:usize, value:usize) -> bool {
 | 
	
		
			
				|  |  | +        self.possible[index].get(value -1)
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    pub fn pos(&self, x:u8, y:u8) -> usize {
 | 
	
		
			
				|  |  | +        x as usize + y as usize * self.width as usize
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #[derive(Debug, Clone)]
 | 
	
		
			
				|  |  |  pub struct AnySolver {
 | 
	
		
			
				|  |  |      pub board: AnyBoard,
 | 
	
		
			
				|  |  |      pub possible: AnyPossible,
 | 
	
		
			
				|  |  | +    pub group: AnyGroup,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  impl AnySolver {
 | 
	
	
		
			
				|  | @@ -431,6 +444,7 @@ impl AnySolver {
 | 
	
		
			
				|  |  |          let mut s = AnySolver {
 | 
	
		
			
				|  |  |              board: initial_board.clone(),
 | 
	
		
			
				|  |  |              possible: AnyPossible::new(initial_board.size),
 | 
	
		
			
				|  |  | +            group: AnyGroup::new(initial_board.size),
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |          s.reset_possible();
 | 
	
		
			
				|  |  |          s
 | 
	
	
		
			
				|  | @@ -440,22 +454,48 @@ impl AnySolver {
 | 
	
		
			
				|  |  |      /// - Remove value from rows, columns, and cells.
 | 
	
		
			
				|  |  |      /// - Clear possibles from (x,y) position, it's filled.
 | 
	
		
			
				|  |  |      pub fn process_move(&mut self, x: u8, y: u8, value: u8) {
 | 
	
		
			
				|  |  | -        let mut g = for_row(y);
 | 
	
		
			
				|  |  | +        let mut g = self.group.row(y);
 | 
	
		
			
				|  |  |          let value: usize = value as usize;
 | 
	
		
			
				|  |  | -        for g in g.0 {
 | 
	
		
			
				|  |  | -            self.possible.set(g, value, false);
 | 
	
		
			
				|  |  | +        for g in g {
 | 
	
		
			
				|  |  | +            self.possible.set(*g, value, false);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        g = for_column(x);
 | 
	
		
			
				|  |  | -        for g in g.0 {
 | 
	
		
			
				|  |  | -            self.possible.set(g, value, false);
 | 
	
		
			
				|  |  | +        g = self.group.column(x);
 | 
	
		
			
				|  |  | +        for g in g {
 | 
	
		
			
				|  |  | +            self.possible.set(*g, value, false);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        g = for_cell(which_cell(x, y));
 | 
	
		
			
				|  |  | -        for g in g.0 {
 | 
	
		
			
				|  |  | -            self.possible.set(g, value, false);
 | 
	
		
			
				|  |  | +        g = self.group.cell(self.group.which_cell(x, y));
 | 
	
		
			
				|  |  | +        for g in g {
 | 
	
		
			
				|  |  | +            self.possible.set(*g, value, false);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          self.possible.possible[self.board.pos(x, y)] = GenBits::<u32>(0); // .clear();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    /// Validate the board
 | 
	
		
			
				|  |  | +    /// Reuse reset_possible code, verify the values are possible.
 | 
	
		
			
				|  |  | +    /// - This does not check if the board is completed.
 | 
	
		
			
				|  |  | +    pub fn validate_board(&mut self) -> bool {       
 | 
	
		
			
				|  |  | +        self.possible.clear();
 | 
	
		
			
				|  |  | +        for y in 0..self.board.width {
 | 
	
		
			
				|  |  | +            for x in 0..self.board.width {
 | 
	
		
			
				|  |  | +                let value = self.board.get(x, y);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                if value != 0 {
 | 
	
		
			
				|  |  | +                    if !self.possible.get(self.possible.pos(x,y), value as usize) {
 | 
	
		
			
				|  |  | +                        // I was going to reset_possible, but the board is broken!
 | 
	
		
			
				|  |  | +                        // Leave in a broken state.
 | 
	
		
			
				|  |  | +                        println!("Width: {}, value: {}", self.board.width, value);
 | 
	
		
			
				|  |  | +                        println!("FAILED at ({},{})", x, y);
 | 
	
		
			
				|  |  | +                        self.board.display();
 | 
	
		
			
				|  |  | +                        println!("{:?}", self);
 | 
	
		
			
				|  |  | +                        return false;
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    self.process_move(x, y, value);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        true
 | 
	
		
			
				|  |  | +    } 
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  |      /// Reset the possible
 | 
	
		
			
				|  |  |      /// - For when a new puzzle has been loaded.
 | 
	
		
			
				|  |  |      /// - When something has changed, and the possibles are out of sync.
 | 
	
	
		
			
				|  | @@ -489,15 +529,22 @@ mod tests {
 | 
	
		
			
				|  |  |      #[test]
 | 
	
		
			
				|  |  |      fn display_board() {
 | 
	
		
			
				|  |  |          let mut board: AnyBoard = AnyBoard::new(5);
 | 
	
		
			
				|  |  | -        println!("{:?}", board);
 | 
	
		
			
				|  |  | -        board.load_from_tld('b', '_', "_m_kzg____h_s_n____ftd_u_u_dh_____f_b_t_w_____yg_c_rl_o_tdhy__m__uvig_w_sk_eg___p_q_jikouys_r_d___mlq_t_sb_emcwg_dlzyo_kp_i_ng__ir_b_fp_vhz_ce_y_jm__w__m__o_k_xul_qbt_d_s__e____otv_dhegn___mfkpz_blr____s_dv_n_mjx_ckg_w_bo_p___kqyelwjcz_____nxumoisdh_z__fp_vbi_______dkx_eg__r_y_mlwf_u__q_i__o_chdv_j_i_he_r_____________p_zl_k_d_vbjh_y__e_p__s_tguc_q_s__qj_kpn_______ufw_hx__i_hvntirfxw_____lbckympjg___u_kz_m_bfn_yvx_h_ir_o____rgm_otlnx___ipfes_kwc____p__c_v_ugh_krj_m_w__x__x__ci_j_qk_mpo_dr_u_zb__ht_i_qe_wjvcy_bhkzx_ng_u_syv___u_c_hsfrlqo_t_e___pj_cn_h_slzr__j__mqgp_y_vd_m_bs_____t_o_n_h_____ez_f_e_ufd____p_g_z____cqr_x_");
 | 
	
		
			
				|  |  | -        println!("{:?}", board);
 | 
	
		
			
				|  |  | +        let result = board.load_from_tld('b', '_', "_m_kzg____h_s_n____ftd_u_u_dh_____f_b_t_w_____yg_c_rl_o_tdhy__m__uvig_w_sk_eg___p_q_jikouys_r_d___mlq_t_sb_emcwg_dlzyo_kp_i_ng__ir_b_fp_vhz_ce_y_jm__w__m__o_k_xul_qbt_d_s__e____otv_dhegn___mfkpz_blr____s_dv_n_mjx_ckg_w_bo_p___kqyelwjcz_____nxumoisdh_z__fp_vbi_______dkx_eg__r_y_mlwf_u__q_i__o_chdv_j_i_he_r_____________p_zl_k_d_vbjh_y__e_p__s_tguc_q_s__qj_kpn_______ufw_hx__i_hvntirfxw_____lbckympjg___u_kz_m_bfn_yvx_h_ir_o____rgm_otlnx___ipfes_kwc____p__c_v_ugh_krj_m_w__x__x__ci_j_qk_mpo_dr_u_zb__ht_i_qe_wjvcy_bhkzx_ng_u_syv___u_c_hsfrlqo_t_e___pj_cn_h_slzr__j__mqgp_y_vd_m_bs_____t_o_n_h_____ez_f_e_ufd____p_g_z____cqr_x_");
 | 
	
		
			
				|  |  | +        assert!(result.is_ok());
 | 
	
		
			
				|  |  |          board.display();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        let mut solver = AnySolver::new(&board);
 | 
	
		
			
				|  |  | +        assert!(solver.validate_board());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          board = AnyBoard::new(4);
 | 
	
		
			
				|  |  | -        board.load_from_tld('b', '_', "_bo_j_m_f__dp__ge_h_pcfdo___q__n___qio______df___f__l___hpnm_i___obig_p_qhl__k_m_dq_cn______o_g_p_____bi_kc__jn______fo____gi______eb____jd______jk__ml_bn_____i_m_b______oq_nj_d_n__jck_m_fgbq___i_medp___n__b___dg______qjk___j__p___fgohl_d_qo__mq__g_d_p_le_");
 | 
	
		
			
				|  |  | +        let result = board.load_from_tld('b', '_', "_bo_j_m_f__dp__ge_h_pcfdo___q__n___qio______df___f__l___hpnm_i___obig_p_qhl__k_m_dq_cn______o_g_p_____bi_kc__jn______fo____gi______eb____jd______jk__ml_bn_____i_m_b______oq_nj_d_n__jck_m_fgbq___i_medp___n__b___dg______qjk___j__p___fgohl_d_qo__mq__g_d_p_le_");
 | 
	
		
			
				|  |  | +        assert!(result.is_ok());
 | 
	
		
			
				|  |  |          board.display();
 | 
	
		
			
				|  |  | -        assert!(false);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        board = AnyBoard::new(3);
 | 
	
		
			
				|  |  | +        let result = board.load_from_tld('b', '_', "__c_____e_h__cb___bd___ei_ch_jb__d___________i_eh__b__dg___ij_f_i__jg_____b_____g");
 | 
	
		
			
				|  |  | +        assert!(result.is_ok());
 | 
	
		
			
				|  |  | +        board.display();        
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 |