Преглед на файлове

Fixed AnyPossible get/set.

Values are 1..=width, bits are 0..width.
Found in the validate_board routine.
Steve Thielemann преди 4 месеца
родител
ревизия
20d179c3f3
променени са 2 файла, в които са добавени 66 реда и са изтрити 27 реда
  1. 0 8
      sudoku/src/group.rs
  2. 66 19
      sudoku/src/sudoku.rs

+ 0 - 8
sudoku/src/group.rs

@@ -103,13 +103,6 @@ impl AnyGroup {
                 );
             }
         }
-        /*
-                for i in 0..self.width {
-                    println!("row {}: {:?}", i, self.row(i));
-                    println!("col {}: {:?}", i, self.column(i));
-                    println!("cel {}: {:?}", i, self.cell(i));
-                }
-        */
     }
 
     pub fn display(&self) {
@@ -566,7 +559,6 @@ mod tests {
         g.display();
         let g = AnyGroup::new(4);
         g.display();
-        assert!(false);
     }
 }
 

+ 66 - 19
sudoku/src/sudoku.rs

@@ -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();        
     }
 }