Shrink those chars

This commit is contained in:
Luke Hubmayer-Werner 2022-02-04 19:01:00 +10:30
parent 6715cf64ce
commit 32d29baa7f
1 changed files with 25 additions and 17 deletions

View File

@ -4,19 +4,25 @@ use bitintr::{Lzcnt, Tzcnt};
use regex::Regex; use regex::Regex;
use rayon::prelude::*; use rayon::prelude::*;
const WORD_LENGTH: usize = 5;
type Charmask = i32; type Charmask = i32;
type Achar = i8; // ASCII char
const WORD_LENGTH: usize = 5;
const WORD_LENGTH_P: usize = 8; // Padded for SIMD shenanigans
const A: Achar = 'A' as Achar;
const Z: Achar = 'Z' as Achar;
#[derive(Copy, Clone, Default)] #[derive(Copy, Clone, Default)]
struct SimState { struct SimState {
banned_chars: [Charmask; WORD_LENGTH], // Alphabetical bitmask banned_chars: [Charmask; WORD_LENGTH_P], // Alphabetical bitmask
required_chars: Charmask required_chars: Charmask
} }
#[derive(Copy, Clone, Default)] #[derive(Copy, Clone, Default)]
struct Word { struct Word {
letters: [char; WORD_LENGTH], charbits: [Charmask; WORD_LENGTH_P], // Each letter in bitmask form
charmask: Charmask // All of the characters contained charmask: Charmask, // All of the characters contained
letters: [Achar; WORD_LENGTH]
} }
type WordCache = HashMap<Charmask, Vec<Word>>; type WordCache = HashMap<Charmask, Vec<Word>>;
@ -25,9 +31,11 @@ fn str2word(s: &str) -> Word {
let mut word = Word::default(); let mut word = Word::default();
let mut iter = s.chars(); let mut iter = s.chars();
for i in 0..WORD_LENGTH { for i in 0..WORD_LENGTH {
let c = iter.next().unwrap(); let c = iter.next().unwrap() as Achar;
let cb = char2bit(c);
word.charbits[i] = cb;
word.letters[i] = c; word.letters[i] = c;
word.charmask |= char2bit(c); word.charmask |= cb;
} }
word word
} }
@ -63,17 +71,17 @@ fn load_dictionary(filename: &str) -> Vec<Word> {
} */ } */
fn char2bit(c: char) -> Charmask { fn char2bit(c: Achar) -> Charmask {
debug_assert!(('A'..='Z').contains(&c)); debug_assert!((A..=Z).contains(&c));
1 << (c as u8 - 'A' as u8) 1 << (c - A)
} }
fn cm2char(cm: Charmask, offset: i8) -> char { fn cm2char(cm: Charmask, offset: i8) -> Achar {
(((31 - cm.lzcnt() as i8) + 'A' as i8 + offset) as u8) as char (((31 - cm.lzcnt() as i8) + A + offset) as u8) as Achar
} }
fn _generate_wordcache_nested(cache: &mut WordCache, subcache: &[Word], key: Charmask, depth: u8) { fn _generate_wordcache_nested(cache: &mut WordCache, subcache: &[Word], key: Charmask, depth: u8) {
for c in cm2char(key, 1)..='Z' { for c in cm2char(key, 1)..=Z {
let cb = char2bit(c); let cb = char2bit(c);
let sc2: Vec<Word> = subcache.iter().filter(|w| (w.charmask & cb) == cb).cloned().collect(); let sc2: Vec<Word> = subcache.iter().filter(|w| (w.charmask & cb) == cb).cloned().collect();
if !sc2.is_empty() { if !sc2.is_empty() {
@ -88,18 +96,18 @@ fn _generate_wordcache_nested(cache: &mut WordCache, subcache: &[Word], key: Cha
fn generate_wordcache(words: Vec<Word>) -> WordCache { fn generate_wordcache(words: Vec<Word>) -> WordCache {
let mut cache: WordCache = HashMap::new(); let mut cache: WordCache = HashMap::new();
let subcache: Vec<Word> = words.iter().cloned().collect(); let subcache: Vec<Word> = words.to_vec();
_generate_wordcache_nested(&mut cache, &subcache, 0, 5); _generate_wordcache_nested(&mut cache, &subcache, 0, 5);
cache.insert(0, words); cache.insert(0, words);
cache cache
} }
fn filter_word(w: &Word, banned_chars: &[Charmask; 5], required_chars: Charmask) -> bool { fn filter_word(w: &Word, banned_chars: &[Charmask; WORD_LENGTH_P], required_chars: Charmask) -> bool {
if w.charmask & required_chars != required_chars { if w.charmask & required_chars != required_chars {
return false; return false;
} }
for (c, bans) in w.letters.iter().zip(banned_chars.iter()) { for (cb, bans) in w.charbits.iter().zip(banned_chars.iter()) {
if char2bit(*c) & bans != 0 { if cb & bans != 0 {
return false; return false;
} }
} }
@ -140,7 +148,7 @@ fn find_worstcase(word: &Word, wordcache: &WordCache) -> (String, usize) {
let remaining = simulate(word, target, ss, &wordcache).0.len(); let remaining = simulate(word, target, ss, &wordcache).0.len();
if remaining > worst {worst = remaining}; if remaining > worst {worst = remaining};
} }
let wordstr: String = word.letters.iter().collect(); let wordstr: String = word.letters.iter().map(|x| (*x as u8) as char).collect();
let output = format!("{} - {}", wordstr, worst); let output = format!("{} - {}", wordstr, worst);
println!("{}", output); println!("{}", output);
(output, worst) (output, worst)