diff --git a/src/dictionary.rs b/src/dictionary.rs new file mode 100644 index 0000000..6f72579 --- /dev/null +++ b/src/dictionary.rs @@ -0,0 +1,68 @@ +use regex::Regex; +use std::collections::HashSet; +use std::fs::{read_dir, File, OpenOptions}; +use std::io::{BufRead, BufReader, Write}; + +pub fn generate_wordle_dictionary() -> HashSet { + let existing_path = "./dictionaries/output/five_letter_words.txt"; + let existing = File::open(&existing_path); + let paths: Vec<_> = read_dir("./dictionaries") + .unwrap() + .map(|p| p.unwrap()) + .filter(|p| p.file_type().unwrap().is_file()) + .collect(); + + // Only regenerate five letter word dictionary if there are new or changed dictionaries + let regenerate = existing.map_or(true, |e| { + let modified = e.metadata().unwrap().modified().unwrap(); + paths + .iter() + .any(|dict| dict.metadata().unwrap().modified().unwrap().gt(&modified)) + }); + + println!("Regenerating five letter word dictionary: {}", regenerate); + let mut five_letter_words = HashSet::new(); + if regenerate { + let _ = File::create(&existing_path); // create if not exist + let mut f_writer = OpenOptions::new() + .write(true) + .truncate(true) + .open(&existing_path) + .unwrap(); + + let five_re = Regex::new(r"^(\w{5})(?:\s|$)").unwrap(); + paths.iter().for_each(|p| { + println!("Loading five letter words from: {}", p.path().display()); + + let f = File::open(p.path()).unwrap(); + let f = BufReader::new(f); + f.lines().map(|l| l.unwrap()).for_each(|line| { + match five_re.captures(&line) { + Some(x) => { + let word = x.get(1).unwrap().as_str().to_uppercase(); + // println!("Capture: {} from {}", word, line); + five_letter_words.insert(word.clone()); + f_writer.write(format!("{}\n", &word).as_ref()).unwrap(); + } + None => (), + } + }) + }); + + f_writer.flush().unwrap(); + } else { + println!( + "Loading five letter word dictionary from: {}", + &existing_path + ); + let dictionary_f = File::open(&existing_path).unwrap(); + let dictionary_f = BufReader::new(dictionary_f); + dictionary_f.lines().for_each(|l| { + five_letter_words.insert(l.unwrap()); + }); + } + + println!("five_letter_words size: {}", five_letter_words.len()); + + five_letter_words +} diff --git a/src/main.rs b/src/main.rs index 85f4198..f11c46e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,102 +1,26 @@ use rand::seq::SliceRandom; -use regex::Regex; -use std::collections::HashSet; -use std::fs::{read_dir, File, OpenOptions}; -use std::io::{stdin, BufRead, BufReader, Write}; +mod dictionary; mod utils; mod wordle; -use utils::str_unique_by_characters; -use wordle::{worlde_game_make_guess, WordleState}; -use crate::utils::clear_screen; - -fn generate_wordle_dictionary() -> HashSet { - let existing_path = "./dictionaries/output/five_letter_words.txt"; - let existing = File::open(&existing_path); - let paths: Vec<_> = read_dir("./dictionaries") - .unwrap() - .map(|p| p.unwrap()) - .filter(|p| p.file_type().unwrap().is_file()) - .collect(); - - // Only regenerate five letter word dictionary if there are new or changed dictionaries - let regenerate = existing.map_or(true, |e| { - let modified = e.metadata().unwrap().modified().unwrap(); - paths - .iter() - .any(|dict| dict.metadata().unwrap().modified().unwrap().gt(&modified)) - }); - - println!("Regenerating five letter word dictionary: {}", regenerate); - let mut five_letter_words = HashSet::new(); - if regenerate { - let _ = File::create(&existing_path); // create if not exist - let mut f_writer = OpenOptions::new() - .write(true) - .truncate(true) - .open(&existing_path) - .unwrap(); - - let five_re = Regex::new(r"^(\w{5})(?:\s|$)").unwrap(); - paths.iter().for_each(|p| { - println!("Loading five letter words from: {}", p.path().display()); - - let f = File::open(p.path()).unwrap(); - let f = BufReader::new(f); - f.lines().map(|l| l.unwrap()).for_each(|line| { - match five_re.captures(&line) { - Some(x) => { - let word = x.get(1).unwrap().as_str().to_uppercase(); - // println!("Capture: {} from {}", word, line); - five_letter_words.insert(word.clone()); - f_writer.write(format!("{}\n", &word).as_ref()).unwrap(); - } - None => (), - } - }) - }); - - f_writer.flush().unwrap(); - } else { - println!( - "Loading five letter word dictionary from: {}", - &existing_path - ); - let dictionary_f = File::open(&existing_path).unwrap(); - let dictionary_f = BufReader::new(dictionary_f); - dictionary_f.lines().for_each(|l| { - five_letter_words.insert(l.unwrap()); - }); - } - - five_letter_words -} - -fn get_input(prompt: &str) -> String { - let mut input = String::new(); - println!("{prompt}"); - stdin() - .read_line(&mut input) - .expect("Failed to read input."); - input.trim().to_string() -} +use crate::dictionary::generate_wordle_dictionary; +use crate::utils::{clear_screen, get_input, str_unique_by_characters}; +use crate::wordle::{worlde_game_make_guess, WordleState}; fn main() { let wordle_dict = generate_wordle_dictionary(); - // println!("Wordle dict size: {}", wordle_dict.len()); let unique_words: Vec<_> = wordle_dict .iter() .filter(|x| str_unique_by_characters(x)) .map(|w| w) .collect(); - let worlde_answer = String::from("EXAMS"); //unique_words.choose(&mut rand::thread_rng()).unwrap(); + let worlde_answer = unique_words.choose(&mut rand::thread_rng()).unwrap(); let mut wordle_game_state = WordleState::new(worlde_answer.as_str()); - - clear_screen(); + clear_screen(); loop { let mut input; @@ -127,72 +51,3 @@ fn main() { false => println!("YOU LOST!"), } } - -/* -use std::fs::File; -use std::io::{BufWriter, Write}; - -fn main() { - let data = "Some data!"; - let f = File::create("/tmp/foo").expect("Unable to create file"); - let mut f = BufWriter::new(f); - f.write_all(data.as_bytes()).expect("Unable to write data"); -} - */ - -/* -use lazy_static::lazy_static; - -use regex::Regex; - -fn extract_login(input: &str) -> Option<&str> { - lazy_static! { - static ref RE: Regex = Regex::new(r"(?x) - ^(?P[^@\s]+)@ - ([[:word:]]+\.)* - [[:word:]]+$ - ").unwrap(); - } - RE.captures(input).and_then(|cap| { - cap.name("login").map(|login| login.as_str()) - }) -} - -fn main() { - assert_eq!(extract_login(r"I❤email@example.com"), Some(r"I❤email")); - assert_eq!( - extract_login(r"sdf+sdsfsd.as.sdsd@jhkk.d.rl"), - Some(r"sdf+sdsfsd.as.sdsd") - ); - assert_eq!(extract_login(r"More@Than@One@at.com"), None); - assert_eq!(extract_login(r"Not an email@email"), None); -} - */ - -/* -use std::fs::File; -use std::io::{BufRead, BufReader}; - -fn main() { - let f = File::open("/etc/hosts").expect("Unable to open file"); - let f = BufReader::new(f); - - for line in f.lines() { - let line = line.expect("Unable to read line"); - println!("Line: {}", line); - } -} - */ - -/* -use std::fs; - -fn main() { - let paths = fs::read_dir("./").unwrap(); - - for path in paths { - println!("Name: {}", path.unwrap().path().display()) - } -} - - */ diff --git a/src/utils.rs b/src/utils.rs index e21d934..2e984e4 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,3 +1,5 @@ +use std::io::stdin; + pub fn str_unique_by_characters(s: &str) -> bool { s.chars() .enumerate() @@ -24,3 +26,12 @@ pub fn str_to_five_char(s: &str) -> [char; 5] { pub fn clear_screen() { print!("\x1B[2J\x1B[1;1H"); } + +pub fn get_input(prompt: &str) -> String { + let mut input = String::new(); + println!("{prompt}"); + stdin() + .read_line(&mut input) + .expect("Failed to read input."); + input.trim().to_string() +}