l5kyu/
fundamentals.rs

1//!
2//! Modules categorized by Codewars labels - 5kyu *** Fundamentals ***
3//!
4
5use shared::kata::*;
6
7/// A squared string has n lines, each substring being n characters long.
8/// For example: s = "abcd\nefgh\nijkl\nmnop" is a squared string of size 4.
9/// We will use squared strings to code and decode texts. To make things
10/// easier we suppose that our original text doesn't include the character '\n'.
11/// # Example
12/// ``` code("Alan Turing") ``` <br>
13/// returns "\x0bi A\n\x0bnTl\n\x0bgua\n\x0b\x0brn"
14pub fn code(s: &str) -> String {
15    let kata = Kata {
16        level: Level::L8kyu,
17        tags: vec![
18            Tag::Fundamentals,
19            Tag::Strings,
20            Tag::Ciphers,
21            Tag::Cryptography,
22        ],
23        description: String::from("Coding with Squared Strings - code"),
24    };
25
26    println!(
27        "Level: {:?}, Tags: {:?}, Description: {}",
28        kata.level, kata.tags, kata.description
29    );
30
31    let n = (s.len() as f32).sqrt().ceil() as usize;
32    println!("l is {} and n is {n}", s.len());
33
34    // Step 2: Pad the text with ASCII char 11 (vertical tab, \x0b)
35    // until the length is n * n
36    let mut padded_s = s.to_string();
37    while padded_s.len() < n * n {
38        padded_s.push(char::from(11)); // ASCII code 11
39    }
40
41    // Step 3: Convert the padded string into a square of size n
42    let mut square = Vec::with_capacity(n);
43    for i in 0..n {
44        square.push(padded_s[i * n..(i + 1) * n].to_string());
45    }
46
47    // Step 4: Rotate the square 90 degrees clockwise
48    let mut rotated_square = vec![String::new(); n];
49    for i in 0..n {
50        for j in 0..n {
51            rotated_square[j].push(square[n - 1 - i].chars().nth(j).unwrap());
52        }
53    }
54
55    // Print rotated square
56    // println!("Rotated square:");
57    // for row in &rotated_square {
58    //     let row_with_escape = row.replace("\x0b", "\\x0b"); // Show vertical tab as text
59    //     println!("{}", row_with_escape);
60    // }
61
62    // Step 5: Return the rotated square as a single string
63    rotated_square.join("\n")
64}
65
66/// A squared string has n lines, each substring being n characters long.
67/// For example: s = "abcd\nefgh\nijkl\nmnop" is a squared string of size 4.
68/// We will use squared strings to code and decode texts. To make things
69/// easier we suppose that our original text doesn't include the character '\n'.
70/// # Example
71/// ``` code("\x0bi A\n\x0bnTl\n\x0bgua\n\x0b\x0brn") ``` <br>
72/// returns "Alan Turing"
73pub fn decode(s: &str) -> String {
74    let kata = Kata {
75        level: Level::L8kyu,
76        tags: vec![
77            Tag::Fundamentals,
78            Tag::Strings,
79            Tag::Ciphers,
80            Tag::Cryptography,
81        ],
82        description: String::from("Coding with Squared Strings - decode"),
83    };
84
85    println!(
86        "Level: {:?}, Tags: {:?}, Description: {}",
87        kata.level, kata.tags, kata.description
88    );
89
90    // Step 1: Calculate the size of the square (n)
91    let len = s.len();
92    let n = (len as f64).sqrt() as usize; // Derive n from the length of the string
93
94    // Step 2: Convert the squared string `s` into rows (split by newlines)
95    let rows: Vec<String> = s.lines().map(|line| line.to_string()).collect();
96
97    // Ensure the correct number of rows and columns
98    if rows.len() != n {
99        panic!("The number of rows does not match the expected size");
100    }
101
102    // Step 3: Apply the counter-clockwise rotation
103    let mut decoded_square = vec![String::new(); n];
104    for i in 0..n {
105        for j in 0..n {
106            // The counter-clockwise rotation (this is the reverse of a clockwise rotation)
107            decoded_square[j].push(rows[i].chars().nth(n - 1 - j).unwrap());
108        }
109    }
110
111    // Step 4: Join the decoded square into a single string and clean up the padding
112    let decoded_string: String = decoded_square.concat(); // Concatenate the rows into a single string
113
114    // Step 5: Remove any padding (ASCII char 11 - vertical tab)
115    decoded_string.trim_matches(char::from(11)).to_string()
116}