1#![feature(inclusive_range_syntax)]
2
3pub enum Method {
4 Encipher,
5 Decipher,
6}
7
8const ALPHABET: &'static str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
9
10fn char_to_pos(input: char) -> usize {
11 ALPHABET.chars().position(|c| input == c).unwrap()
12}
13
14pub fn cipher(input: &str, key: &str, method: Method) -> String {
15 let w = input.to_string().to_uppercase();
16 let k = key.to_string().to_uppercase();
17
18 let key_alphabet_pos = k.chars().map(|c| char_to_pos(c)).collect::<Vec<usize>>();
19
20 let chunk_amount = w.len() as f32 / k.len() as f32;
22
23 (0..chunk_amount.ceil() as usize)
26 .map(|chunk| {
27 let lowerbound = chunk * key.len();
28 let maximum = (chunk_amount.ceil() as usize) - 1;
29
30 let upperbound = if chunk == maximum {
31 w.len() - 1
33 } else {
34 lowerbound + key.len() - 1
36 };
37
38 (lowerbound..=upperbound)
40 .map(|i| char_to_pos(w.chars().nth(i).unwrap()))
41 .collect::<Vec<usize>>()
42 })
43 .collect::<Vec<Vec<usize>>>()
44 .into_iter()
45 .map(|char_chunk| {
46 char_chunk
47 .into_iter()
48 .enumerate()
49 .map(|(i, single)| {
50 let encrypted_char_pos = match method {
51 Method::Encipher => (single + key_alphabet_pos[i]) % ALPHABET.len(),
52 Method::Decipher => {
53 let pos = single as i8 - key_alphabet_pos[i] as i8;
54 if pos < 0 {
56 (ALPHABET.len() as i8 + pos) as usize
57 } else {
58 pos as usize
59 }
60 }
61 };
62 ALPHABET.chars().nth(encrypted_char_pos).unwrap()
63 })
64 .collect::<String>()
65 })
66 .collect::<Vec<String>>()
67 .concat()
68}