$ cargo add getchar
OYPAXSUZX AX UBXS SPTRG OYPAXSUZX JYVF JV OVRVNPZSV AS NG CADAFC SYV RACYS BQ RBDV SB SYBXV JYB FVVL AS UBXS. -- PTSY OZPSVP XSZERVSBF
use getchar::getchar; use std::env::args; use std::io::{stdout, Write}; use std::process::exit; const SET_FG_RED: &str = "\x1b[31m"; const SET_FG_YELLOW: &str = "\x1b[33m"; const SET_FG_RESET: &str = "\x1b[0m"; fn main() { // Get input file from command-line, and possibly print help/usage info. let args: Vec<String> = args().collect(); if args.len() < 2 { println!("Usage:\n\t{} <filename>", args[0]); println!("or"); println!("\t<path>/cifer <filename>"); println!("or"); println!("\tcargo run -- <filename>"); println!("\nAt any rate, we've gotta have a data file. It needs to be a"); println!("plain-text file containing the cryptoquote that needs to be"); println!("deciphered. Enter \"+\" to quit program."); exit(1); } let filename = &args[1]; // Read data from file into a String. let errmsg = format!( "\n\n{SET_FG_RED}ERROR reading \"{SET_FG_YELLOW}{}{SET_FG_RED}\".{SET_FG_RESET}\n\n", filename ); let cryptoquote: String = std::fs::read_to_string(filename).expect(&errmsg); // Strip newlines from cryptoquote. let cryptoquote = cryptoquote.replace("\n", " "); // Convert it to a vector of chars. let cryptoquote: Vec<char> = cryptoquote.chars().collect(); // Create a twin vector to hold the decrypted version (initially dashes). let mut decrypted_quote: Vec<char> = vec![]; for ndx in 0..cryptoquote.len() { if cryptoquote[ndx] == ' ' || cryptoquote[ndx] == '.' { decrypted_quote.push(' '); } else { decrypted_quote.push('-'); } } // And a vector for the match attempts. let mut alpha_matches: Vec<char> = vec![]; for _alpha in 0..26 { alpha_matches.push('-'); } let crypt_line = 3; let decrypt_line = crypt_line + 1; let change_line = crypt_line + 4; let alpha_line = crypt_line + 7; let match_line = crypt_line + 8; // Clear screen; print intro. clear_screen(); goto(1, 1); println!("Decrypt this cryptoquote. (\"+\" to quit.)"); // Print cryptoquote. goto(crypt_line, 1); for ndx in 0..cryptoquote.len() { print!("{}", cryptoquote[ndx]); } // Print alphabet, and matches. goto(alpha_line, 1); println!("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); loop { // Print the alpha-matches. goto(match_line, 1); for alpha in 0..26 { print!("{}", alpha_matches[alpha]); } // Print the decrypted line (as it progresses). goto(decrypt_line, 1); for ndx in 0..decrypted_quote.len() { print!("{}", decrypted_quote[ndx]); } // Get letter to change. goto(change_line, 1); println!("Enter letter to change: "); goto(change_line, 25); let crypted_key = getchar().unwrap().to_ascii_uppercase(); if crypted_key == '+' { break; } // Highlight that letter in the alpha-match line. let offset = crypted_key as usize - 'A' as usize; set_fg_color("yellow"); goto(alpha_line, offset + 1); // Account for 1-indexed coords. println!("{}", crypted_key); // Get the new letter. goto(change_line, 1); println!(" Change it to: "); goto(change_line, 25); print!("{}", crypted_key); goto(change_line, 25); let decrypted_key = getchar().unwrap().to_ascii_uppercase(); // Add this to the match line, turning off the highlight from earlier. set_fg_color("reset"); goto(alpha_line, offset + 1); // Adjust for grid starting at 1,1 instead of 0,0. println!("{}", crypted_key); if decrypted_key == '+' { break; } alpha_matches[offset] = decrypted_key; for ndx in 0..cryptoquote.len() { if cryptoquote[ndx] == crypted_key { decrypted_quote[ndx] = decrypted_key; } } } println!("\n\nBye!\n\n"); } // end of main() fn clear_screen() { println!("\x1b[2J"); } fn goto(row: usize, col: usize) { print!("\x1b[{row};{col}H"); stdout().flush().unwrap(); } fn set_fg_color(color: &str) { match color.to_uppercase().as_str() { "RED" => println!("{SET_FG_RED}"), "YELLOW" => println!("{SET_FG_YELLOW}"), "RESET" | _ => println!("{SET_FG_RESET}"), }; }