Repository: TheAlgorithms/Java
Pull request #5761 (2024-10-13 07:32:38)

Add main, test for Rail Fence Cipher and update README.md
- [☑️] I have read [CONTRIBUTING.md](https://github.com/TheAlgorithms/Java/blob/master/CONTRIBUTING.md).
- [☑️] This pull request is all my own work -- I have not plagiarized it.
- [☑️] All filenames are in PascalCase.
- [☑️] All functions and variable names follow Java naming conventions.
- [☑️] All new algorithms have a URL in their comments that points to Wikipedia or other similar explanations.
- [☑️] All new code is formatted with `clang-format -i --style=file path/to/your/file.java`

codecov-commenter: ## [Codecov](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5761?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 64.07%. Comparing base [(`6682c7c`)](https://app.codecov.io/gh/TheAlgorithms/Java/commit/6682c7c76e2bf016e2e7b51a6027ac30d354b13e?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) to head [(`8e0cff0`)](https://app.codecov.io/gh/TheAlgorithms/Java/commit/8e0cff0f95410edc041b77c0dfd1d34e2477955d?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms).

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff              @@
##             master    #5761      +/-   ##
============================================
+ Coverage     63.96%   64.07%   +0.11%     
- Complexity     4172     4198      +26     
============================================
  Files           583      584       +1     
  Lines         16320    16370      +50     
  Branches       3150     3169      +19     
============================================
+ Hits          10439    10489      +50     
  Misses         5456     5456              
  Partials        425      425              
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5761?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms).


Patch:
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 652ecbfd..3d215855 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -73,6 +73,7 @@
             * [PlayfairCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/PlayfairCipher.java)
             * [Polybius](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Polybius.java)
             * [ProductCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/ProductCipher.java)
+            * [RailFenceCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java)
             * [RSA](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/RSA.java)
             * [SimpleSubCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/SimpleSubCipher.java)
             * [Vigenere](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Vigenere.java)
@@ -729,6 +730,7 @@
             * [HillCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/HillCipherTest.java)
             * [PlayfairTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/PlayfairTest.java)
             * [PolybiusTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/PolybiusTest.java)
+            * [RailFenceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/RailFenceTest.java)
             * [RSATest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/RSATest.java)
             * [SimpleSubCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/SimpleSubCipherTest.java)
             * [VigenereTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/VigenereTest.java)
diff --git a/src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java b/src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java
new file mode 100644
index 00000000..f8125298
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java
@@ -0,0 +1,147 @@
+package com.thealgorithms.ciphers;
+
+import java.util.Arrays;
+
+/**
+ * The rail fence cipher (also called a zigzag cipher) is a classical type of transposition cipher.
+ * It derives its name from the manner in which encryption is performed, in analogy to a fence built with horizontal rails.
+ * https://en.wikipedia.org/wiki/Rail_fence_cipher
+ * @author https://github.com/Krounosity
+ */
+
+public class RailFenceCipher {
+
+    // Encrypts the input string using the rail fence cipher method with the given number of rails.
+    public String encrypt(String str, int rails) {
+
+        // Base case of single rail or rails are more than the number of characters in the string
+        if (rails == 1 || rails >= str.length()) {
+            return str;
+        }
+
+        // Boolean flag to determine if the movement is downward or upward in the rail matrix.
+        boolean down = true;
+        // Create a 2D array to represent the rails (rows) and the length of the string (columns).
+        char[][] strRail = new char[rails][str.length()];
+
+        // Initialize all positions in the rail matrix with a placeholder character ('\n').
+        for (int i = 0; i < rails; i++) {
+            Arrays.fill(strRail[i], '\n');
+        }
+
+        int row = 0; // Start at the first row
+        int col = 0; // Start at the first column
+
+        int i = 0;
+
+        // Fill the rail matrix with characters from the string based on the rail pattern.
+        while (col < str.length()) {
+            // Change direction to down when at the first row.
+            if (row == 0) {
+                down = true;
+            }
+            // Change direction to up when at the last row.
+            else if (row == rails - 1) {
+                down = false;
+            }
+
+            // Place the character in the current position of the rail matrix.
+            strRail[row][col] = str.charAt(i);
+            col++; // Move to the next column.
+            // Move to the next row based on the direction.
+            if (down) {
+                row++;
+            } else {
+                row--;
+            }
+
+            i++;
+        }
+
+        // Construct the encrypted string by reading characters row by row.
+        StringBuilder encryptedString = new StringBuilder();
+        for (char[] chRow : strRail) {
+            for (char ch : chRow) {
+                if (ch != '\n') {
+                    encryptedString.append(ch);
+                }
+            }
+        }
+        return encryptedString.toString();
+    }
+    // Decrypts the input string using the rail fence cipher method with the given number of rails.
+    public String decrypt(String str, int rails) {
+
+        // Base case of single rail or rails are more than the number of characters in the string
+        if (rails == 1 || rails >= str.length()) {
+            return str;
+        }
+        // Boolean flag to determine if the movement is downward or upward in the rail matrix.
+        boolean down = true;
+
+        // Create a 2D array to represent the rails (rows) and the length of the string (columns).
+        char[][] strRail = new char[rails][str.length()];
+
+        int row = 0; // Start at the first row
+        int col = 0; // Start at the first column
+
+        // Mark the pattern on the rail matrix using '*'.
+        while (col < str.length()) {
+            // Change direction to down when at the first row.
+            if (row == 0) {
+                down = true;
+            }
+            // Change direction to up when at the last row.
+            else if (row == rails - 1) {
+                down = false;
+            }
+
+            // Mark the current position in the rail matrix.
+            strRail[row][col] = '*';
+            col++; // Move to the next column.
+            // Move to the next row based on the direction.
+            if (down) {
+                row++;
+            } else {
+                row--;
+            }
+        }
+
+        int index = 0; // Index to track characters from the input string.
+        // Fill the rail matrix with characters from the input string based on the marked pattern.
+        for (int i = 0; i < rails; i++) {
+            for (int j = 0; j < str.length(); j++) {
+                if (strRail[i][j] == '*') {
+                    strRail[i][j] = str.charAt(index++);
+                }
+            }
+        }
+
+        // Construct the decrypted string by following the zigzag pattern.
+        StringBuilder decryptedString = new StringBuilder();
+        row = 0; // Reset to the first row
+        col = 0; // Reset to the first column
+
+        while (col < str.length()) {
+            // Change direction to down when at the first row.
+            if (row == 0) {
+                down = true;
+            }
+            // Change direction to up when at the last row.
+            else if (row == rails - 1) {
+                down = false;
+            }
+            // Append the character from the rail matrix to the decrypted string.
+            decryptedString.append(strRail[row][col]);
+            col++; // Move to the next column.
+            // Move to the next row based on the direction.
+            if (down) {
+                row++;
+            } else {
+                row--;
+            }
+        }
+
+        return decryptedString.toString();
+    }
+}


Test patch:
diff --git a/src/test/java/com/thealgorithms/ciphers/RailFenceTest.java b/src/test/java/com/thealgorithms/ciphers/RailFenceTest.java
new file mode 100644
index 00000000..2bfa704e
--- /dev/null
+++ b/src/test/java/com/thealgorithms/ciphers/RailFenceTest.java
@@ -0,0 +1,62 @@
+package com.thealgorithms.ciphers;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class RailFenceTest {
+
+    @Test
+    void testEncryption() {
+        RailFenceCipher cipher = new RailFenceCipher();
+
+        String input = "We are discovered! Flee at once";
+        int rails = 3;
+        String encrypted = cipher.encrypt(input, rails);
+        assertEquals("Wrivdlaneaedsoee!Fe toc  cr e e", encrypted);
+
+        String singleChar = "A";
+        int singleRail = 2;
+        String encryptedSingleChar = cipher.encrypt(singleChar, singleRail);
+        assertEquals("A", encryptedSingleChar);
+
+        String shortString = "Hello";
+        int moreRails = 10;
+        String encryptedShortString = cipher.encrypt(shortString, moreRails);
+        assertEquals("Hello", encryptedShortString);
+
+        String inputSingleRail = "Single line";
+        int singleRailOnly = 1;
+        String encryptedSingleRail = cipher.encrypt(inputSingleRail, singleRailOnly);
+        assertEquals("Single line", encryptedSingleRail);
+    }
+
+    @Test
+    void testDecryption() {
+        RailFenceCipher cipher = new RailFenceCipher();
+
+        // Scenario 1: Basic decryption with multiple rails
+        String encryptedInput = "Wrivdlaneaedsoee!Fe toc  cr e e";
+        int rails = 3;
+        String decrypted = cipher.decrypt(encryptedInput, rails);
+        assertEquals("We are discovered! Flee at once", decrypted);
+
+        // Scenario 2: Single character string decryption
+        String encryptedSingleChar = "A";
+        int singleRail = 2; // More than 1 rail
+        String decryptedSingleChar = cipher.decrypt(encryptedSingleChar, singleRail);
+        assertEquals("A", decryptedSingleChar);
+
+        // Scenario 3: String length less than the number of rails
+        String encryptedShortString = "Hello";
+        int moreRails = 10; // More rails than characters
+        String decryptedShortString = cipher.decrypt(encryptedShortString, moreRails);
+        assertEquals("Hello", decryptedShortString);
+
+        // Scenario 4: Single rail decryption (output should be the same as input)
+        String encryptedSingleRail = "Single line";
+        int singleRailOnly = 1;
+        String decryptedSingleRail = cipher.decrypt(encryptedSingleRail, singleRailOnly);
+        assertEquals("Single line", decryptedSingleRail);
+    }
+}