RosettaCodeData/Task/Playfair-cipher/Rust/playfair-cipher.rs

226 lines
5.4 KiB
Rust

use std::io::{self, Write};
struct Playfair {
txt: String,
m: [[char; 5]; 5],
}
impl Playfair {
fn new() -> Self {
Playfair {
txt: String::new(),
m: [[' '; 5]; 5],
}
}
fn do_it(&mut self, k: &str, t: &str, ij: bool, e: bool) {
self.create_grid(k, ij);
self.get_text_ready(t, ij, e);
if e {
self.process(1);
} else {
self.process(-1);
}
self.display();
}
fn process(&mut self, dir: i32) {
let mut ntxt = String::new();
let mut chars = self.txt.chars().collect::<Vec<char>>();
let mut i = 0;
while i < chars.len() {
if i + 1 >= chars.len() {
break;
}
let mut a = 0;
let mut b = 0;
let mut c = 0;
let mut d = 0;
if self.get_char_pos(chars[i], &mut a, &mut b) &&
self.get_char_pos(chars[i+1], &mut c, &mut d) {
if a == c {
ntxt.push(self.get_char(a, b + dir));
ntxt.push(self.get_char(c, d + dir));
} else if b == d {
ntxt.push(self.get_char(a + dir, b));
ntxt.push(self.get_char(c + dir, d));
} else {
ntxt.push(self.get_char(c, b));
ntxt.push(self.get_char(a, d));
}
}
i += 2;
}
self.txt = ntxt;
}
fn display(&self) {
println!("\n\n OUTPUT:\n=========");
let chars = self.txt.chars().collect::<Vec<char>>();
let mut cnt = 0;
let mut i = 0;
while i < chars.len() {
if i + 1 < chars.len() {
print!("{}{} ", chars[i], chars[i+1]);
i += 2;
cnt += 1;
if cnt >= 26 {
println!();
cnt = 0;
}
} else {
print!("{}", chars[i]);
i += 1;
}
}
println!("\n");
}
fn get_char(&self, a: i32, b: i32) -> char {
let row = ((b + 5) % 5) as usize;
let col = ((a + 5) % 5) as usize;
self.m[row][col]
}
fn get_char_pos(&self, l: char, a: &mut i32, b: &mut i32) -> bool {
for y in 0..5 {
for x in 0..5 {
if self.m[y][x] == l {
*a = x as i32;
*b = y as i32;
return true;
}
}
}
false
}
fn get_text_ready(&mut self, t: &str, ij: bool, e: bool) {
self.txt.clear();
for c in t.chars() {
let c_upper = c.to_ascii_uppercase();
if c_upper < 'A' || c_upper > 'Z' {
continue;
}
if c_upper == 'J' && ij {
self.txt.push('I');
} else if c_upper == 'Q' && !ij {
continue;
} else {
self.txt.push(c_upper);
}
}
if e {
let mut ntxt = String::new();
let chars = self.txt.chars().collect::<Vec<char>>();
let len = chars.len();
let mut x = 0;
while x < len {
ntxt.push(chars[x]);
if x + 1 < len {
if chars[x] == chars[x + 1] {
ntxt.push('X');
}
ntxt.push(chars[x + 1]);
}
x += 2;
}
self.txt = ntxt;
}
if self.txt.len() % 2 == 1 {
self.txt.push('X');
}
}
fn create_grid(&mut self, k: &str, ij: bool) {
let mut key = k.to_string();
if key.is_empty() {
key = "KEYWORD".to_string();
}
key.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
let mut nk = String::new();
for c in key.chars() {
let c_upper = c.to_ascii_uppercase();
if c_upper < 'A' || c_upper > 'Z' {
continue;
}
if (c_upper == 'J' && ij) || (c_upper == 'Q' && !ij) {
continue;
}
if !nk.contains(c_upper) {
nk.push(c_upper);
}
}
let mut idx = 0;
for y in 0..5 {
for x in 0..5 {
if idx < nk.len() {
self.m[y][x] = nk.chars().nth(idx).unwrap();
idx += 1;
}
}
}
}
}
fn main() -> io::Result<()> {
let mut input = String::new();
print!("(E)ncode or (D)ecode? ");
io::stdout().flush()?;
io::stdin().read_line(&mut input)?;
let e = input.trim().to_lowercase().starts_with('e');
input.clear();
print!("Enter a en/decryption key: ");
io::stdout().flush()?;
io::stdin().read_line(&mut input)?;
let key = input.trim().to_string();
input.clear();
print!("I <-> J (Y/N): ");
io::stdout().flush()?;
io::stdin().read_line(&mut input)?;
let ij = input.trim().to_lowercase().starts_with('y');
input.clear();
print!("Enter the text: ");
io::stdout().flush()?;
io::stdin().read_line(&mut input)?;
let txt = input.trim().to_string();
let mut pf = Playfair::new();
pf.do_it(&key, &txt, ij, e);
println!("Press Enter to continue...");
input.clear();
io::stdin().read_line(&mut input)?;
Ok(())
}