|
@@ -301,13 +301,12 @@ impl AnyBoard {
|
|
result
|
|
result
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// Display board using unicode box characters.
|
|
pub fn display(&self) {
|
|
pub fn display(&self) {
|
|
let line = "═".repeat(self.size as usize);
|
|
let line = "═".repeat(self.size as usize);
|
|
let alpha_display = self.width >= 10;
|
|
let alpha_display = self.width >= 10;
|
|
// println!("╔{}╦{}╦{}╗", line, line, line);
|
|
// println!("╔{}╦{}╦{}╗", line, line, line);
|
|
|
|
|
|
- println!("alpha = {}", alpha_display);
|
|
|
|
-
|
|
|
|
// Top
|
|
// Top
|
|
for i in 0..self.size {
|
|
for i in 0..self.size {
|
|
if i == 0 {
|
|
if i == 0 {
|
|
@@ -380,6 +379,7 @@ impl AnyBoard {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
// Need to use u32, so 5*5=25, 25 bits can be accessed.
|
|
// Need to use u32, so 5*5=25, 25 bits can be accessed.
|
|
// u16 is fine for 3*3=9.
|
|
// u16 is fine for 3*3=9.
|
|
|
|
|
|
@@ -395,7 +395,7 @@ impl AnyPossible {
|
|
pub fn new(board_size: u8) -> Self {
|
|
pub fn new(board_size: u8) -> Self {
|
|
let mut initial = GenBits::<u32>(0);
|
|
let mut initial = GenBits::<u32>(0);
|
|
let width = board_size * board_size;
|
|
let width = board_size * board_size;
|
|
- initial.set_bits(1..width);
|
|
|
|
|
|
+ initial.set_bits(0..width);
|
|
|
|
|
|
Self {
|
|
Self {
|
|
size: board_size,
|
|
size: board_size,
|
|
@@ -408,22 +408,35 @@ impl AnyPossible {
|
|
pub fn clear(&mut self) {
|
|
pub fn clear(&mut self) {
|
|
let mut initial = GenBits::<u32>(0);
|
|
let mut initial = GenBits::<u32>(0);
|
|
// let width = self.size * self.size;
|
|
// 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];
|
|
self.possible = vec![initial; self.max_index];
|
|
// width as usize * width as usize];
|
|
// width as usize * width as usize];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // NOTE: values range from 1..width. Bits range from 0..width-1
|
|
|
|
+
|
|
#[inline]
|
|
#[inline]
|
|
pub fn set(&mut self, index: usize, value: usize, state: bool) {
|
|
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)]
|
|
#[derive(Debug, Clone)]
|
|
pub struct AnySolver {
|
|
pub struct AnySolver {
|
|
pub board: AnyBoard,
|
|
pub board: AnyBoard,
|
|
pub possible: AnyPossible,
|
|
pub possible: AnyPossible,
|
|
|
|
+ pub group: AnyGroup,
|
|
}
|
|
}
|
|
|
|
|
|
impl AnySolver {
|
|
impl AnySolver {
|
|
@@ -431,6 +444,7 @@ impl AnySolver {
|
|
let mut s = AnySolver {
|
|
let mut s = AnySolver {
|
|
board: initial_board.clone(),
|
|
board: initial_board.clone(),
|
|
possible: AnyPossible::new(initial_board.size),
|
|
possible: AnyPossible::new(initial_board.size),
|
|
|
|
+ group: AnyGroup::new(initial_board.size),
|
|
};
|
|
};
|
|
s.reset_possible();
|
|
s.reset_possible();
|
|
s
|
|
s
|
|
@@ -440,22 +454,48 @@ impl AnySolver {
|
|
/// - Remove value from rows, columns, and cells.
|
|
/// - Remove value from rows, columns, and cells.
|
|
/// - Clear possibles from (x,y) position, it's filled.
|
|
/// - Clear possibles from (x,y) position, it's filled.
|
|
pub fn process_move(&mut self, x: u8, y: u8, value: u8) {
|
|
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;
|
|
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();
|
|
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
|
|
/// Reset the possible
|
|
/// - For when a new puzzle has been loaded.
|
|
/// - For when a new puzzle has been loaded.
|
|
/// - When something has changed, and the possibles are out of sync.
|
|
/// - When something has changed, and the possibles are out of sync.
|
|
@@ -489,15 +529,22 @@ mod tests {
|
|
#[test]
|
|
#[test]
|
|
fn display_board() {
|
|
fn display_board() {
|
|
let mut board: AnyBoard = AnyBoard::new(5);
|
|
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();
|
|
board.display();
|
|
|
|
|
|
|
|
+ let mut solver = AnySolver::new(&board);
|
|
|
|
+ assert!(solver.validate_board());
|
|
|
|
+
|
|
board = AnyBoard::new(4);
|
|
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();
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|