fix pattern bug where yellow takes precedence

This commit is contained in:
2026-08-18 21:18:28 +02:00
parent 416ab6beba
commit 715bce656d
5 changed files with 69 additions and 33 deletions
+26 -13
View File
@@ -2,34 +2,47 @@ use std::{env::args, path::Path};
use wordle_solver::{game::Game, solver::Solver, word_list::WordList};
pub fn main() {
let valid_words = WordList::from_file(Path::new("valid-words.txt")).unwrap();
let target_words = WordList::from_file(Path::new("answers.txt")).unwrap();
pub fn do_simulation(valid_words: WordList, target_words: WordList, opener: Option<&str>) -> u64 {
let target_word = target_words.random_word();
println!("Target: {}", target_word);
let mut game = Game::new(target_word);
let mut solver = Solver::new(valid_words, target_words);
if let Some(first_guess) = args().skip(1).next() {
if let Some(pat) = game.guess(&first_guess) {
if let Some(first_guess) = opener {
match game.guess(&first_guess) {
Ok(pat) => {
solver.apply_guess(pat);
println!("{}", solver.tabular_format());
} else {
println!("Found solution: {}", first_guess);
}
Err(n) => {
println!("Found solution at guess {}: {}", n, first_guess);
return n;
}
}
}
loop {
let best_word = &solver.evaluate_all_words().first().unwrap().clone().word;
println!("{}", solver.best_word_format());
let best_word = solver.evaluate_all_words().first().unwrap().word.clone();
println!("{}", solver.best_word_format(5));
if let Some(pat) = game.guess(best_word) {
match game.guess(&best_word) {
Ok(pat) => {
solver.apply_guess(pat);
println!("{}", solver.tabular_format());
} else {
println!("Found solution: {}", best_word);
break;
}
Err(n) => {
println!("Found solution at guess {}: {}", n, best_word);
return n;
}
}
}
}
pub fn main() {
let valid_words = WordList::from_file(Path::new("valid-words.txt")).unwrap();
let target_words = WordList::from_file(Path::new("answers.txt")).unwrap();
do_simulation(valid_words, target_words, args().skip(1).next().as_deref());
}
+3 -3
View File
@@ -9,13 +9,13 @@ pub fn main() {
solver.apply_guess(Pattern::from_guess("CRANE", "CASTS").unwrap());
println!("{}", solver.tabular_format());
println!("{}", solver.best_word_format());
println!("{}", solver.best_word_format(5));
solver.apply_guess(Pattern::from_guess("CRANE", "WORKS").unwrap());
println!("{}", solver.tabular_format());
println!("{}", solver.best_word_format());
println!("{}", solver.best_word_format(5));
solver.apply_guess(Pattern::from_guess("CRANE", "PAPER").unwrap());
println!("{}", solver.tabular_format());
println!("{}", solver.best_word_format());
println!("{}", solver.best_word_format(5));
}
+3 -3
View File
@@ -13,13 +13,13 @@ impl Game {
}
}
pub fn guess(&mut self, word: &str) -> Option<Pattern> {
pub fn guess(&mut self, word: &str) -> Result<Pattern, u64> {
self.score += 1;
if word == self.word {
None
Err(self.score)
} else {
Some(Pattern::from_guess(&self.word, word).unwrap())
Ok(Pattern::from_guess(&self.word, word).unwrap())
}
}
}
+29 -4
View File
@@ -64,8 +64,10 @@ impl Pattern {
}
}
// Yellows
for i in 0..chars.len() {
if stats[i] == CharStatus::GREEN {
continue;
}
if let Some((j, _)) = rest.iter().enumerate().find(|(_, x)| **x == guess[i]) {
stats[i] = CharStatus::YELLOW;
rest[j] = ' ';
@@ -151,7 +153,7 @@ mod tests {
assert_eq!(
Pattern::from_guess("abcde", "eabcd"),
Pattern::try_new(
"abcde",
"eabcd",
vec![
CharStatus::YELLOW,
CharStatus::YELLOW,
@@ -164,7 +166,7 @@ mod tests {
assert_eq!(
Pattern::from_guess("abcde", "fghij"),
Pattern::try_new(
"abcde",
"fghij",
vec![
CharStatus::GREY,
CharStatus::GREY,
@@ -177,7 +179,7 @@ mod tests {
assert_eq!(
Pattern::from_guess("aabbc", "bbaab"),
Pattern::try_new(
"aabbc",
"bbaab",
vec![
CharStatus::YELLOW,
CharStatus::YELLOW,
@@ -189,6 +191,29 @@ mod tests {
);
}
#[test]
fn bug_1() {
let target = "RARER";
let g1 = "RAISE";
let pat = Pattern::from_guess(target, g1).unwrap();
assert_eq!(
pat,
Pattern::try_new(
"RAISE",
vec![
CharStatus::GREEN,
CharStatus::GREEN,
CharStatus::GREY,
CharStatus::GREY,
CharStatus::YELLOW,
],
)
.unwrap()
)
}
#[test]
fn pattern_match_1() {
let p1 = Pattern::try_new(
+4 -6
View File
@@ -80,10 +80,8 @@ impl Solver {
let expected_score_after_guess = score * solution_probability
+ (1.0 - solution_probability)
* (score
+ ((self.valid_words.equal_likelieness_entropy()
- expected_information_gained)
.log2()
+ 1.0));
+ (self.valid_words.equal_likelieness_entropy() - expected_information_gained)
.log2());
WordStats {
word: word.to_string(),
@@ -110,7 +108,7 @@ impl Solver {
self.best_words.clone()
}
pub fn best_word_format(&self) -> String {
pub fn best_word_format(&self, n: usize) -> String {
let mut table = Table::new("#{:<} {:>} | {:<} {:<} {:<}");
table.add_row(
@@ -121,7 +119,7 @@ impl Solver {
.with_cell("E[I]")
.with_cell("E[score]"),
);
for (i, ws) in self.best_words.iter().take(10).enumerate() {
for (i, ws) in self.best_words.iter().take(n).enumerate() {
table.add_row(
Row::new()
.with_cell(i + 1)