Advertisement
ChrisIsSoFun

Wordle Solver written in Rust

Feb 12th, 2022
1,994
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 6.40 KB | None | 0 0
  1. use radix_fmt::radix_3;
  2. use std::{
  3.     error::Error,
  4.     fs::File,
  5.     io::{BufRead, BufReader},
  6.     iter::Iterator,
  7.     result::Result, cmp::Ordering,
  8. };
  9.  
  10. pub struct WordleBase {
  11.     pub words: Vec<String>,
  12.     pub guesses: Vec<String>,
  13. }
  14.  
  15. impl WordleBase {
  16.     pub fn new(
  17.         words: Vec<String>,
  18.         guesses: Vec<String>,
  19.     ) -> WordleBase {
  20.         WordleBase {
  21.             words,
  22.             guesses,
  23.         }
  24.     }
  25.  
  26.     pub fn load(
  27.         words_path: &str,
  28.         guesses_path: &str,
  29.     ) -> Result<WordleBase, Box<dyn Error>> {
  30.         let words = WordleBase::read_lines(words_path)?;
  31.         let guesses = WordleBase::read_lines(guesses_path)?;
  32.  
  33.         Ok(WordleBase::new(words, guesses))
  34.     }
  35.  
  36.     pub fn read_lines(path: &str) -> std::io::Result<Vec<String>> {
  37.         let f = File::open(path)?;
  38.         let reader = BufReader::new(f);
  39.  
  40.         let r = reader
  41.             .lines()
  42.             .take_while(Result::is_ok)
  43.             .map(|s| s.unwrap())
  44.             .collect();
  45.  
  46.         Ok(r)
  47.     }
  48. }
  49.  
  50. pub struct Char {
  51.     character: char,
  52.     char_type: CharType,
  53. }
  54.  
  55. impl Char {
  56.     pub fn new(character: char, char_type: CharType) -> Char {
  57.         Char {
  58.             character,
  59.             char_type,
  60.         }
  61.     }
  62. }
  63.  
  64. pub enum CharType {
  65.     Gray,
  66.     Yellow,
  67.     Green,
  68. }
  69.  
  70. pub struct Guess {
  71.     pub chars: Vec<Char>,
  72. }
  73.  
  74. impl Guess {
  75.     pub fn matches(&self, word: &String) -> bool {
  76.         let chars: Vec<char> = word.chars().collect();
  77.  
  78.         if chars.len() != self.len() {
  79.             return false;
  80.         }
  81.  
  82.         for (i, s) in self.chars.iter().enumerate() {
  83.             match &s.char_type {
  84.                 CharType::Gray => {
  85.                     if word.contains(s.character) {
  86.                         return false;
  87.                     }
  88.                 }
  89.                 CharType::Yellow => {
  90.                     if !word.contains(s.character) {
  91.                         return false;
  92.                     }
  93.                 }
  94.                 CharType::Green => {
  95.                     if chars.get(i) != Some(&s.character) {
  96.                         return false;
  97.                     }
  98.                 }
  99.             }
  100.         }
  101.  
  102.         true
  103.     }
  104.  
  105.     pub fn compare(&self, word_list : &Vec<String>) -> u16 {
  106.         let mut r = 0;
  107.  
  108.         for word in word_list {
  109.             if self.matches(word) {
  110.                 r += 1;
  111.             }
  112.         }
  113.  
  114.         r
  115.     }
  116.  
  117.     pub fn new(words: Vec<Char>) -> Guess {
  118.         Guess { chars: words }
  119.     }
  120.  
  121.     #[allow(dead_code)]
  122.     pub fn len(&self) -> usize {
  123.         self.chars.len()
  124.     }
  125. }
  126.  
  127. pub struct WordleEngine<'a> {
  128.    base: &'a WordleBase,
  129.     // There are 6 columns, therefore the max value would be 5
  130.     current_column: u8,
  131.     current_words: Vec<String>,
  132.     probablistic_distribution: Vec<(&'a str, f64)>,
  133. }
  134.  
  135. impl<'a> WordleEngine<'a> {
  136.    pub fn base(&self) -> &'a WordleBase {
  137.         &self.base
  138.     }
  139.  
  140.     #[allow(dead_code)]
  141.     pub fn current_column(&self) -> u8 {
  142.         self.current_column
  143.     }
  144.  
  145.     pub fn current_words(&self) -> &Vec<String> {
  146.         &self.current_words
  147.     }
  148.     pub fn distribution(&self) -> &Vec<(&'a str, f64)> {
  149.        &self.probablistic_distribution
  150.    }
  151.  
  152.    pub fn new(base: &'a WordleBase) -> WordleEngine {
  153.         let current_words = base.words.clone();
  154.         let probablistic_distribution = Vec::<(&str, f64)>::new();
  155.  
  156.         WordleEngine {
  157.             base,
  158.             current_column: 0,
  159.             current_words,
  160.             probablistic_distribution
  161.         }
  162.     }
  163.  
  164.     pub fn input_guess(&mut self, guess : &Guess) -> &Vec<String> {
  165.         self.current_column += 1;
  166.         let vec = self.current_words();
  167.         let mut new_vec : Vec<String> = Vec::with_capacity(vec.len());
  168.  
  169.         for word in vec {
  170.             if guess.matches(&word) {
  171.                 new_vec.push(word.to_string());
  172.             }
  173.         }
  174.  
  175.         self.current_words = new_vec;
  176.  
  177.         &self.current_words
  178.     }
  179.    
  180.     pub fn change_distribution(&mut self) {
  181.         self.probablistic_distribution = WordleEngine::calculate_distribution(self.current_words(), &self.base().guesses)
  182.     }
  183.  
  184.     pub fn calculate_score(guess : &String, words : &Vec<String>) -> u16 {
  185.         let guesses = WordleEngine::create_guess_list(guess);
  186.         let mut score = 0u16;
  187.        
  188.         for guess in guesses {
  189.             score += guess.compare(words);
  190.         }
  191.  
  192.         score
  193.     }
  194.  
  195.     pub fn calculate_distribution<'b>(
  196.        words: &Vec<String>,
  197.        guesses: &'b Vec<String>,
  198.     ) -> Vec<(&'b str, f64)> {
  199.        let mut orders : Vec<(&str, f64)> = Vec::new();
  200.  
  201.        for guess in guesses {
  202.            let score = WordleEngine::calculate_score(guess, words);
  203.  
  204.            orders.push((guess, score as f64));
  205.        }
  206.  
  207.        orders.sort_by(|a, b| {
  208.            if a.1 == b.1 {
  209.                return Ordering::Greater;
  210.            }
  211.  
  212.            if a.1 < b.1 {
  213.                return Ordering::Greater;
  214.            }
  215.            
  216.            return Ordering::Less;
  217.        });
  218.  
  219.        orders
  220.    }
  221.  
  222.    pub fn create_guess_list(word: &String) -> Vec<Guess> {
  223.        let num = 3u32.pow(word.len() as u32); // For a 5 letter word this would be equal to 243
  224.        let mut guesses: Vec<Guess> = Vec::with_capacity(num as usize);
  225.  
  226.        for n in 0..num {
  227.            guesses.push(WordleEngine::create_guess(n, word));
  228.        }
  229.  
  230.        guesses
  231.    }
  232.  
  233.    pub fn create_guess(num: u32, value: &String) -> Guess {
  234.        let r = radix_3(num).to_string();
  235.        let chars: Vec<char> = value.chars().collect();
  236.        let count = chars.len();
  237.  
  238.        let diff = count - r.chars().count();
  239.        let zeroes_string: String = std::iter::repeat("0").take(diff).collect();
  240.        let string = zeroes_string + &r;
  241.  
  242.        let mut r: Vec<Char> = Vec::with_capacity(value.len());
  243.  
  244.        for (i, s) in string.chars().enumerate() {
  245.            match s {
  246.                '0' => r.push(Char::new(chars[i], CharType::Gray)),
  247.                '1' => r.push(Char::new(chars[i], CharType::Yellow)),
  248.                '2' => r.push(Char::new(chars[i], CharType::Green)),
  249.                _ => {
  250.                    // It shouldn't be possible to end up here
  251.                     panic!()
  252.                 }
  253.             }
  254.         }
  255.  
  256.         return Guess::new(r);
  257.     }
  258. }
  259.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement