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}