Kent West - kent.west@{that mail that swore to do no evil}
Cargo.toml
$ cargo add getchar
src/12Dec2023.txt
OYPAXSUZX AX UBXS SPTRG
OYPAXSUZX JYVF JV
OVRVNPZSV AS NG CADAFC
SYV RACYS BQ RBDV SB
SYBXV JYB FVVL AS UBXS.
--
PTSY OZPSVP XSZERVSBF
src/main.rs
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}"),
};
}