generated from PlexSheep/rs-base
feat(naive): make it almost work
cargo devel CI / cargo CI (push) Failing after 1m56s
Details
cargo devel CI / cargo CI (push) Failing after 1m56s
Details
This commit is contained in:
parent
f511e158cd
commit
3c44760a2c
|
@ -32,16 +32,12 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for NaiveSolver<'wl, WL> {
|
||||||
/// * Discard all words that don't have the chars that we know from the last guess are in the
|
/// * Discard all words that don't have the chars that we know from the last guess are in the
|
||||||
/// word, but don't know the position of.
|
/// word, but don't know the position of.
|
||||||
fn guess_for(&self, game: &crate::game::Game<WL>) -> WResult<Word> {
|
fn guess_for(&self, game: &crate::game::Game<WL>) -> WResult<Word> {
|
||||||
if game.responses().is_empty() {
|
|
||||||
// TODO: come up with a proper way to make the first guess
|
|
||||||
return Ok(Word::from("which"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut pattern: String = ".".repeat(game.length());
|
let mut pattern: String = ".".repeat(game.length());
|
||||||
// indexes we tried for that char and the number of occurences
|
// indexes we tried for that char and the number of occurences
|
||||||
let mut state: SolverState = SolverState::new();
|
let mut state: SolverState = SolverState::new();
|
||||||
let responses = game.responses().iter().enumerate();
|
let responses = game.responses().iter().enumerate();
|
||||||
for (_idx, response) in responses {
|
for (_idx, response) in responses {
|
||||||
|
let mut already_found_amounts: HashMap<char, usize> = HashMap::new();
|
||||||
let evaluation: &Evaluation = response.evaluation();
|
let evaluation: &Evaluation = response.evaluation();
|
||||||
for (idx, p) in evaluation.clone().into_iter().enumerate() {
|
for (idx, p) in evaluation.clone().into_iter().enumerate() {
|
||||||
match p.1 {
|
match p.1 {
|
||||||
|
@ -53,6 +49,7 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for NaiveSolver<'wl, WL> {
|
||||||
.entry(p.0)
|
.entry(p.0)
|
||||||
.or_insert(CharInfo::new(game.length()))
|
.or_insert(CharInfo::new(game.length()))
|
||||||
.found_at(idx);
|
.found_at(idx);
|
||||||
|
*already_found_amounts.entry(p.0).or_default() += 1;
|
||||||
}
|
}
|
||||||
Status::Exists => {
|
Status::Exists => {
|
||||||
let cinfo = state
|
let cinfo = state
|
||||||
|
@ -60,16 +57,16 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for NaiveSolver<'wl, WL> {
|
||||||
.entry(p.0)
|
.entry(p.0)
|
||||||
.or_insert(CharInfo::new(game.length()));
|
.or_insert(CharInfo::new(game.length()));
|
||||||
cinfo.tried_but_failed(idx);
|
cinfo.tried_but_failed(idx);
|
||||||
cinfo.at_least_n_occurences(
|
*already_found_amounts.entry(p.0).or_default() += 1;
|
||||||
response.guess().chars().filter(|c| *c == p.0).count(),
|
cinfo.min_occurences(already_found_amounts[&p.0]);
|
||||||
)
|
|
||||||
}
|
}
|
||||||
Status::None => state
|
Status::None => state
|
||||||
.char_map_mut()
|
.char_map_mut()
|
||||||
.entry(p.0)
|
.entry(p.0)
|
||||||
.or_insert(CharInfo::new(game.length()))
|
.or_insert(CharInfo::new(game.length()))
|
||||||
.not_in_solution(),
|
.max_occurences(*already_found_amounts.entry(p.0).or_default()),
|
||||||
}
|
}
|
||||||
|
trace!("absolute frequencies: {already_found_amounts:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,9 +87,8 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for NaiveSolver<'wl, WL> {
|
||||||
.char_map_mut()
|
.char_map_mut()
|
||||||
.entry(c)
|
.entry(c)
|
||||||
.or_insert(CharInfo::new(game.length()));
|
.or_insert(CharInfo::new(game.length()));
|
||||||
if !cinfo.part_of_solution()
|
if !cinfo.part_of_solution() || cinfo.has_been_tried(idx)
|
||||||
|| cinfo.has_been_tried(idx)
|
// || !cinfo.occurences_of_char_possible(&solution_candidate.0, c)
|
||||||
|| !cinfo.occurences_of_char_possible(&solution_candidate.0, c)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -108,12 +104,6 @@ impl<'wl, WL: WordList> Solver<'wl, WL> for NaiveSolver<'wl, WL> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'wl, WL: WordList> NaiveSolver<'wl, WL> {
|
|
||||||
fn get_highest_possible_abs_freq(indexes: &[usize], game: &crate::game::Game<WL>) -> usize {
|
|
||||||
game.length() - indexes.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'wl, WL: WordList> From<NaiveSolver<'wl, WL>> for AnyBuiltinSolver<'wl, WL> {
|
impl<'wl, WL: WordList> From<NaiveSolver<'wl, WL>> for AnyBuiltinSolver<'wl, WL> {
|
||||||
fn from(value: NaiveSolver<'wl, WL>) -> Self {
|
fn from(value: NaiveSolver<'wl, WL>) -> Self {
|
||||||
Self::Naive(value)
|
Self::Naive(value)
|
||||||
|
|
|
@ -9,7 +9,7 @@ pub(crate) type CharMap = HashMap<char, CharInfo>;
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub(crate) struct CharInfo {
|
pub(crate) struct CharInfo {
|
||||||
confirmed_indexes: HashSet<usize>,
|
confirmed_indexes: HashSet<usize>,
|
||||||
tried_indexes: HashSet<usize>,
|
bad_indexes: HashSet<usize>,
|
||||||
occurences_amount: Range<usize>,
|
occurences_amount: Range<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,13 +38,12 @@ impl CharInfo {
|
||||||
pub fn new(word_length: usize) -> Self {
|
pub fn new(word_length: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
confirmed_indexes: HashSet::new(),
|
confirmed_indexes: HashSet::new(),
|
||||||
tried_indexes: HashSet::new(),
|
bad_indexes: HashSet::new(),
|
||||||
occurences_amount: 0..word_length,
|
occurences_amount: 0..word_length,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn found_at(&mut self, idx: usize) {
|
pub fn found_at(&mut self, idx: usize) {
|
||||||
self.tried_indexes.insert(idx);
|
|
||||||
self.confirmed_indexes.insert(idx);
|
self.confirmed_indexes.insert(idx);
|
||||||
|
|
||||||
if self.occurences_amount.start < 1 {
|
if self.occurences_amount.start < 1 {
|
||||||
|
@ -54,17 +53,11 @@ impl CharInfo {
|
||||||
|
|
||||||
/// tried to guess a char we know exists at this position, but it was incorrect
|
/// tried to guess a char we know exists at this position, but it was incorrect
|
||||||
pub fn tried_but_failed(&mut self, idx: usize) {
|
pub fn tried_but_failed(&mut self, idx: usize) {
|
||||||
self.tried_indexes.insert(idx);
|
self.bad_indexes.insert(idx);
|
||||||
}
|
|
||||||
|
|
||||||
/// char is not in the solution
|
|
||||||
pub fn not_in_solution(&mut self) {
|
|
||||||
self.occurences_amount.start = 0;
|
|
||||||
self.occurences_amount.end = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_been_tried(&self, idx: usize) -> bool {
|
pub fn has_been_tried(&self, idx: usize) -> bool {
|
||||||
self.tried_indexes.contains(&idx)
|
self.bad_indexes.contains(&idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -72,8 +65,12 @@ impl CharInfo {
|
||||||
self.occurences_amount.end > 0
|
self.occurences_amount.end > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn at_least_n_occurences(&mut self, n: usize) {
|
pub fn min_occurences(&mut self, min: usize) {
|
||||||
self.occurences_amount.start = n;
|
self.occurences_amount.start = min;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn max_occurences(&mut self, max: usize) {
|
||||||
|
self.occurences_amount.end = max
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn confirmed_indexes(&self) -> &HashSet<usize> {
|
pub(crate) fn confirmed_indexes(&self) -> &HashSet<usize> {
|
||||||
|
@ -85,11 +82,11 @@ impl CharInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn tried_indexes(&self) -> &HashSet<usize> {
|
pub(crate) fn tried_indexes(&self) -> &HashSet<usize> {
|
||||||
&self.tried_indexes
|
&self.bad_indexes
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn tried_indexes_mut(&mut self) -> &mut HashSet<usize> {
|
pub(crate) fn tried_indexes_mut(&mut self) -> &mut HashSet<usize> {
|
||||||
&mut self.tried_indexes
|
&mut self.bad_indexes
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn occurences_amount(&self) -> &Range<usize> {
|
pub(crate) fn occurences_amount(&self) -> &Range<usize> {
|
||||||
|
@ -105,12 +102,12 @@ impl CharInfo {
|
||||||
solution_candidate: &str,
|
solution_candidate: &str,
|
||||||
character: char,
|
character: char,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.occurences_amount.contains(
|
let occ = solution_candidate
|
||||||
&solution_candidate
|
|
||||||
.chars()
|
.chars()
|
||||||
.filter(|c| *c == character)
|
.filter(|c| *c == character)
|
||||||
.count(),
|
.count();
|
||||||
)
|
|
||||||
|
self.occurences_amount.start <= occ && occ <= self.occurences_amount.end
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,9 +115,9 @@ impl Debug for CharInfo {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
if self.part_of_solution() {
|
if self.part_of_solution() {
|
||||||
f.debug_struct("CharInfo")
|
f.debug_struct("CharInfo")
|
||||||
.field("indexes", &self.confirmed_indexes)
|
.field("correct_idxs", &self.confirmed_indexes)
|
||||||
.field("amnt_occ", &self.occurences_amount)
|
.field("amnt_occ", &self.occurences_amount)
|
||||||
.field("tried", &self.tried_indexes)
|
.field("bad_idxs", &self.bad_indexes)
|
||||||
.finish()
|
.finish()
|
||||||
} else {
|
} else {
|
||||||
write!(f, "(not in solution)")
|
write!(f, "(not in solution)")
|
||||||
|
|
Loading…
Reference in New Issue