1 Commits

Author SHA1 Message Date
1d4b9219f4 rust version: old method comparable to method in main 2023-03-27 20:11:29 +02:00
2 changed files with 119 additions and 478 deletions

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 35 KiB

View File

@ -6,8 +6,7 @@ const NUM_FIELDS: usize = SIZE * SIZE;
struct SField { struct SField {
field: Vec<u8>, field: Vec<u8>,
skipf: Vec<u8>, fixed: Vec<bool>,
skipb: Vec<u8>,
pos: usize, pos: usize,
possible_values: Vec<Vec<u8>>, possible_values: Vec<Vec<u8>>,
} }
@ -27,50 +26,18 @@ impl SField {
0,0,8,2,0,0,0,6,0, 0,0,8,2,0,0,0,6,0,
]; ];
fn find_fixed_streak_forward(mut idx: usize, field: &[u8]) -> u8 { let mut fixed = Vec::with_capacity(SIZE * SIZE);
let mut fixed_count = 1; field.iter().for_each(|e| {
idx += 1; if *e == 0 {
fixed.push(false);
while idx < NUM_FIELDS && field[idx] > 0 { } else {
fixed_count += 1; fixed.push(true);
idx += 1;
} }
});
fixed_count
}
fn find_fixed_streak_backward(mut idx: usize, field: &[u8]) -> u8 {
let mut fixed_count = 1;
idx -= 1;
while idx < NUM_FIELDS && field[idx] > 0 {
fixed_count += 1;
idx -= 1;
}
fixed_count
}
let mut skipf = vec![0; NUM_FIELDS + 1];
for (idx, nr) in field.iter().enumerate() {
match nr {
0 => skipf[idx] = *nr,
_ => skipf[idx] = find_fixed_streak_forward(idx, &field),
}
}
let mut skipb = vec![0; NUM_FIELDS + 1];
for (idx, nr) in field.iter().enumerate().rev() {
match nr {
0 => skipb[idx + 1] = *nr,
_ => skipb[idx + 1] = find_fixed_streak_backward(idx, &field),
}
}
SField { SField {
field, field,
skipf, fixed,
skipb,
pos: 0, pos: 0,
possible_values: vec![vec![]; SIZE * SIZE], possible_values: vec![vec![]; SIZE * SIZE],
} }
@ -78,7 +45,7 @@ impl SField {
fn build_possible_values_db(&mut self) { fn build_possible_values_db(&mut self) {
for idx in 0..NUM_FIELDS { for idx in 0..NUM_FIELDS {
if self.field[idx] != 0 { if self.fixed[idx] {
continue; continue;
} }
self.pos = idx; self.pos = idx;
@ -96,51 +63,71 @@ impl SField {
pub fn solve_backtracking(&mut self) -> bool { pub fn solve_backtracking(&mut self) -> bool {
let mut num_solutions = 0; let mut num_solutions = 0;
loop { loop {
if !self.put_valid_nr() { if self.is_end() {
self.clear_current_field();
if !self.prev() {
self.print_clear();
self.print();
println!("Number of solutions: {}", num_solutions);
break;
}
continue;
}
if !self.next() {
num_solutions += 1; num_solutions += 1;
if num_solutions % 10_000 == 0 { if num_solutions % 10_000 == 0 {
self.print_clear(); self.print_clear();
self.print(); self.print();
println!("Number of solutions: {}", num_solutions); println!("Number of solutions: {}", num_solutions);
} }
if self.is_fixed() {
continue;
}
self.clear_current_field(); self.clear_current_field();
self.prev(); self.prev();
self.goto_prev_free_field();
}
if self.is_fixed() {
self.next();
continue;
}
if self.goto_next_free_field() {
if self.put_valid_nr() {
self.next();
continue;
} else {
self.clear_current_field();
if !self.prev() {
println!("Number of solutions: {}", num_solutions);
break;
}
if !self.goto_prev_free_field() {
println!("Number of solutions: {}", num_solutions);
break;
}
}
} }
} }
num_solutions > 0 num_solutions > 0
} }
#[inline(always)]
fn print_gray(&self) { fn print_gray(&self) {
print!("\x1b\x5b\x31\x3b\x33\x30\x6d"); print!("\x1b\x5b\x31\x3b\x33\x30\x6d");
} }
#[inline(always)]
fn print_green(&self) { fn print_green(&self) {
print!("\x1b\x5b\x31\x3b\x33\x32\x6d"); print!("\x1b\x5b\x31\x3b\x33\x32\x6d");
} }
#[inline(always)]
fn print_neutral(&self) { fn print_neutral(&self) {
print!("\x1b\x5b\x31\x3b\x30\x6d"); print!("\x1b\x5b\x31\x3b\x30\x6d");
} }
#[inline(always)]
fn print_clear(&self) { fn print_clear(&self) {
print!("\x1b\x5b\x48\x1b\x5b\x32\x4a"); print!("\x1b\x5b\x48\x1b\x5b\x32\x4a");
} }
#[inline(always)]
fn print(&self) { fn print(&self) {
for i in 0..NUM_FIELDS { for i in 0..NUM_FIELDS {
if i != 0 && i % SIZE == 0 { if i != 0 && i % SIZE == 0 {
@ -162,10 +149,50 @@ impl SField {
println!(); println!();
} }
#[inline(always)]
fn clear_current_field(&mut self) { fn clear_current_field(&mut self) {
self.set(0); self.set(0);
} }
#[inline(always)]
fn goto_prev_free_field(&mut self) -> bool {
while {
if !self.is_fixed() {
return true;
}
self.prev()
} {}
false
}
#[inline(always)]
fn goto_next_free_field(&mut self) -> bool {
while {
if !self.is_fixed() {
return true;
}
self.next()
} {}
false
}
#[inline(always)]
fn _put_valid_nr(&mut self) -> bool {
let current_nr = self.get_field_at_pos(self.pos);
for nr in current_nr..(SIZE + 1) as u8 {
if self.ok(nr) {
self.set(nr);
return true;
}
}
false
}
#[inline(always)]
fn put_valid_nr(&mut self) -> bool { fn put_valid_nr(&mut self) -> bool {
let current_nr = self.get_field_at_pos(self.pos); let current_nr = self.get_field_at_pos(self.pos);
@ -187,10 +214,32 @@ impl SField {
false false
} }
#[inline(always)]
fn is_end(&self) -> bool {
!self.field.contains(&0)
}
#[inline(always)]
fn ok(&self, nr: u8) -> bool { fn ok(&self, nr: u8) -> bool {
self.block_ok(nr) && self.row_ok(nr) && self.col_ok(nr) self.block_ok(nr) && self.row_ok(nr) && self.col_ok(nr)
} }
#[inline(always)]
fn _pos_to_xy(&self) -> (usize, usize) {
let y = self.pos / SIZE;
let x = self.pos % SIZE;
(x + 1, y + 1)
}
#[inline(always)]
fn is_fixed(&self) -> bool {
// safety: self.pos can be used to index the field unchecked
// since the only methods modifying self.pos are
// `next()` and `prev()` and they do bounds checking
unsafe { *self.fixed.get_unchecked(self.pos) }
}
#[inline(always)]
fn get_field_at_pos(&self, pos: usize) -> u8 { fn get_field_at_pos(&self, pos: usize) -> u8 {
// safety: // safety:
// TODO // TODO
@ -199,22 +248,26 @@ impl SField {
unsafe { *self.field.get_unchecked(pos) } unsafe { *self.field.get_unchecked(pos) }
} }
#[inline(always)]
fn set(&mut self, nr: u8) { fn set(&mut self, nr: u8) {
self.field[self.pos] = nr; self.field[self.pos] = nr;
} }
#[inline(always)]
fn get_row(&self, row: &mut [u8; SIZE]) { fn get_row(&self, row: &mut [u8; SIZE]) {
for (idx, row_elem) in row.iter_mut().enumerate() { for (idx, row_elem) in row.iter_mut().enumerate() {
*row_elem = self.get_field_at_pos((self.pos / SIZE) * SIZE + idx); *row_elem = self.get_field_at_pos((self.pos / SIZE) * SIZE + idx);
} }
} }
#[inline(always)]
fn get_col(&self, col: &mut [u8; SIZE]) { fn get_col(&self, col: &mut [u8; SIZE]) {
for (idx, col_elem) in col.iter_mut().enumerate() { for (idx, col_elem) in col.iter_mut().enumerate() {
*col_elem = self.get_field_at_pos(idx * SIZE + self.pos % SIZE); *col_elem = self.get_field_at_pos(idx * SIZE + self.pos % SIZE);
} }
} }
#[inline(always)]
fn get_block(&self, block: &mut [u8; SIZE]) { fn get_block(&self, block: &mut [u8; SIZE]) {
let block_start_row = self.pos / SIZE / BLOCK_SIZE * BLOCK_SIZE; let block_start_row = self.pos / SIZE / BLOCK_SIZE * BLOCK_SIZE;
let block_start_col = self.pos % SIZE / BLOCK_SIZE * BLOCK_SIZE; let block_start_col = self.pos % SIZE / BLOCK_SIZE * BLOCK_SIZE;
@ -227,46 +280,48 @@ impl SField {
} }
} }
#[inline(always)]
fn block_ok(&self, nr: u8) -> bool { fn block_ok(&self, nr: u8) -> bool {
let mut block = [0; SIZE]; let mut block = [0; SIZE];
self.get_block(&mut block); self.get_block(&mut block);
!block.contains(&nr) !block.contains(&nr)
} }
#[inline(always)]
fn row_ok(&self, nr: u8) -> bool { fn row_ok(&self, nr: u8) -> bool {
let mut row = [0; SIZE]; let mut row = [0; SIZE];
self.get_row(&mut row); self.get_row(&mut row);
!row.contains(&nr) !row.contains(&nr)
} }
#[inline(always)]
fn col_ok(&self, nr: u8) -> bool { fn col_ok(&self, nr: u8) -> bool {
let mut col = [0; SIZE]; let mut col = [0; SIZE];
self.get_col(&mut col); self.get_col(&mut col);
!col.contains(&nr) !col.contains(&nr)
} }
#[inline(always)]
fn next(&mut self) -> bool { fn next(&mut self) -> bool {
let new_pos = self.pos + 1 + unsafe { *self.skipf.get_unchecked(self.pos + 1) as usize }; if self.pos == NUM_FIELDS - 1 {
if new_pos >= NUM_FIELDS {
return false; return false;
} }
self.pos = new_pos; self.pos += 1;
true true
} }
#[inline(always)]
fn prev(&mut self) -> bool { fn prev(&mut self) -> bool {
let new_pos = self.pos - 1 - unsafe { *self.skipb.get_unchecked(self.pos) as usize }; if self.pos == 0 {
if new_pos >= NUM_FIELDS {
return false; return false;
} }
self.pos = new_pos; self.pos -= 1;
true true
} }
#[inline(always)]
fn solve(&mut self) { fn solve(&mut self) {
let now = Instant::now(); let now = Instant::now();
if !self.solve_backtracking() { if !self.solve_backtracking() {