1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
#[macro_use]
extern crate lazy_static;
use std::collections::{HashMap, HashSet};
use input::clean_input;
pub mod cache;
pub mod cli;
pub mod input;
pub mod loading;
pub mod solve;
#[derive(Debug, Clone)]
pub struct Word {
pub word: String,
pub candidates: HashSet<String>,
pub letter_map: HashMap<char, HashSet<char>>,
}
impl Word {
pub fn new(s: &str, candidates: &HashSet<String>) -> Self {
let mut letter_map = HashMap::new();
for word in candidates {
for (i, j) in s.chars().zip(word.chars()) {
letter_map.entry(i).or_insert(HashSet::new()).insert(j);
}
}
Word {
word: s.to_string(),
candidates: candidates.clone(),
letter_map,
}
}
}
/// Convert word to uppercase, and substitute all characters to be in alphabetical order.
/// This makes words equivalent if they have the same charactaristics
///
/// ```rust
/// use sub_solver::normalize;
///
/// assert_eq!(normalize("example"), "ABCDEFA"); // "example" has 2 'a's at the start and end
/// assert_eq!(normalize("example"), normalize("squares")); // "example" and "squares" have the same repeated character positions
/// assert_eq!(normalize("testing"), "ABCADEF"); // "testing" does not have repeated characters at the start and end
/// ```
pub fn normalize(s: &str) -> String {
let mut result = s.chars().collect::<Vec<char>>();
let mut replacement = b'A';
for i in 0..result.len() {
if result[i].is_ascii_uppercase() {
continue;
}
// Replace all instances of the character with the replacement
result = result
.iter()
.map(|&c| {
if c == result[i] {
replacement as char
} else {
c
}
})
.collect();
replacement += 1;
}
result.into_iter().collect()
}
/// Load a wordlist from a file into a dictionary with normalized words
pub fn load_wordlist(contents: &str) -> HashMap<String, HashSet<String>> {
let mut map = HashMap::new();
for word in contents.lines() {
let word = clean_input(word);
map.entry(normalize(&word))
.or_insert(HashSet::new())
.insert(word.to_string());
}
map
}