use druid::im::Vector;
use druid::{Color, Data, Lens, WidgetId};
use crate::*;
use rustoku::SudError;
use std::collections::HashSet;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
#[derive(Clone, Data, Lens)]
pub struct AppState {
pub squares: Vector<Square>,
pub hint_name: Arc<String>,
pub original_string: Arc<String>,
pub error_msg: Arc<String>,
#[data(ignore)]
pub multi_select: bool,
#[data(ignore)]
pub selected_pairs: HashSet<CandidateInfo>,
#[data(ignore)]
pub active_hint: Option<Hint>,
#[data(ignore)]
pub sud: Sudoku,
#[data(ignore)]
pub solver: HumanSolver,
}
impl AppState {
pub(crate) fn new(input: &str) -> Self {
if let Ok(sudoku) = Sudoku::new(input) {
if let Err(error) = sudoku.unique_solution() {
match error {
SudError::MultipleSolution(_) => (), _ => return AppState::default(), }
}
let squares = sudoku
.value_iter()
.enumerate()
.map(|(i, v)| {
let p = sudoku.possibilities(i).unwrap();
let mut vec: Vector<IndCand> = Vector::new();
for x in 1..=9u16 {
let ind = if p.contains(&x) {
IndCand {
value: x,
status: Status::Active,
square_index: i,
}
} else {
IndCand {
value: x,
status: Status::Inactive,
square_index: i,
}
};
vec.push_back(ind);
}
Square {
value: if v != 0 {
v.to_string()
} else {
"".to_string()
},
cands: vec,
}
})
.collect();
AppState {
squares,
sud: sudoku,
original_string: Arc::new(String::default()),
error_msg: Arc::new(String::default()),
selected_pairs: HashSet::new(),
multi_select: false,
active_hint: None,
hint_name: String::default().into(),
solver: HumanSolver::new(),
}
} else {
AppState::default()
}
}
}
impl Default for AppState {
fn default() -> Self {
AppState::new(
"1.85..2345..3.2178...8..5698..6.5793..59..4813....865298.2.631.......8.....78.9.."
)
}
}
#[derive(Clone, Data, Debug, PartialEq, Eq)]
pub struct CandidateInfo {
pub index: usize,
pub value: u16,
#[data(ignore)]
pub id: WidgetId,
}
#[allow(clippy::derive_hash_xor_eq)]
impl Hash for CandidateInfo {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl CandidateInfo {
pub fn new(index: usize, value: u16, id: WidgetId) -> CandidateInfo {
CandidateInfo { index, value, id }
}
}
#[derive(Clone, Data, Lens)]
pub struct Square {
pub value: String,
pub cands: Vector<IndCand>,
}
#[derive(Clone, Data, Lens)]
pub struct IndCand {
pub value: u16,
pub status: Status,
pub square_index: usize,
}
#[derive(Clone, PartialEq, Data, Debug)]
pub enum Status {
Active,
Inactive,
Selected,
Involved,
Removable,
}
impl Status {
pub fn color(&self) -> Color {
match self {
Status::Active => Color::BLACK,
Status::Inactive => Color::BLACK,
Status::Selected => Color::BLUE,
Status::Involved => Color::GREEN,
Status::Removable => Color::RED,
}
}
}