Repository: TheAlgorithms/Java
Pull request #4988 (2024-01-02 16:52:49)

Added Playfair Cipher
- [x] I have read [CONTRIBUTING.md](https://github.com/TheAlgorithms/Java/blob/master/CONTRIBUTING.md).
- [x] This pull request is all my own work -- I have not plagiarized it.
- [x] All filenames are in PascalCase.
- [x] All functions and variable names follow Java naming conventions.

Govind516: okay. I will add JUnit Tests.
Govind516: could you please check now as changes meets the requirements.
Govind516: Removed the _main_ function and also solved Clang format. Please check now.

Patch:
diff --git a/DIRECTORY.md b/DIRECTORY.md
index fd50b291..b621216d 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -27,6 +27,7 @@
             * [NonRepeatingNumberFinder](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/NonRepeatingNumberFinder.java)
             * [NumbersDifferentSigns](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/NumbersDifferentSigns.java)
             * [ReverseBits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/ReverseBits.java)
+            * [SetKthBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/SetKthBit.java)
             * [SingleBitOperations](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/SingleBitOperations.java)
           * ciphers
             * a5
@@ -44,6 +45,7 @@
             * [ColumnarTranspositionCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/ColumnarTranspositionCipher.java)
             * [DES](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/DES.java)
             * [HillCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/HillCipher.java)
+            * [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)
             * [RSA](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/RSA.java)
@@ -585,6 +587,7 @@
             * [NonRepeatingNumberFinderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/NonRepeatingNumberFinderTest.java)
             * [NumbersDifferentSignsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/NumbersDifferentSignsTest.java)
             * [ReverseBitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/ReverseBitsTest.java)
+            * [SetKthBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/SetKthBitTest.java)
             * [SingleBitOperationsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/SingleBitOperationsTest.java)
           * ciphers
             * a5
@@ -592,6 +595,7 @@
             * [BlowfishTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/BlowfishTest.java)
             * [CaesarTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/CaesarTest.java)
             * [DESTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/DESTest.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)
             * [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)
diff --git a/src/main/java/com/thealgorithms/ciphers/PlayfairCipher.java b/src/main/java/com/thealgorithms/ciphers/PlayfairCipher.java
new file mode 100644
index 00000000..76ceb6db
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/PlayfairCipher.java
@@ -0,0 +1,128 @@
+package com.thealgorithms.ciphers;
+
+public class PlayfairCipher {
+
+    private char[][] matrix;
+    private String key;
+
+    public PlayfairCipher(String key) {
+        this.key = key;
+        generateMatrix();
+    }
+
+    public String encrypt(String plaintext) {
+        plaintext = prepareText(plaintext.replace("J", "I"));
+        StringBuilder ciphertext = new StringBuilder();
+        for (int i = 0; i < plaintext.length(); i += 2) {
+            char char1 = plaintext.charAt(i);
+            char char2 = plaintext.charAt(i + 1);
+            int[] pos1 = findPosition(char1);
+            int[] pos2 = findPosition(char2);
+            int row1 = pos1[0];
+            int col1 = pos1[1];
+            int row2 = pos2[0];
+            int col2 = pos2[1];
+            if (row1 == row2) {
+                ciphertext.append(matrix[row1][(col1 + 1) % 5]);
+                ciphertext.append(matrix[row2][(col2 + 1) % 5]);
+            } else if (col1 == col2) {
+                ciphertext.append(matrix[(row1 + 1) % 5][col1]);
+                ciphertext.append(matrix[(row2 + 1) % 5][col2]);
+            } else {
+                ciphertext.append(matrix[row1][col2]);
+                ciphertext.append(matrix[row2][col1]);
+            }
+        }
+        return ciphertext.toString();
+    }
+
+    public String decrypt(String ciphertext) {
+        StringBuilder plaintext = new StringBuilder();
+        for (int i = 0; i < ciphertext.length(); i += 2) {
+            char char1 = ciphertext.charAt(i);
+            char char2 = ciphertext.charAt(i + 1);
+            int[] pos1 = findPosition(char1);
+            int[] pos2 = findPosition(char2);
+            int row1 = pos1[0];
+            int col1 = pos1[1];
+            int row2 = pos2[0];
+            int col2 = pos2[1];
+            if (row1 == row2) {
+                plaintext.append(matrix[row1][(col1 + 4) % 5]);
+                plaintext.append(matrix[row2][(col2 + 4) % 5]);
+            } else if (col1 == col2) {
+                plaintext.append(matrix[(row1 + 4) % 5][col1]);
+                plaintext.append(matrix[(row2 + 4) % 5][col2]);
+            } else {
+                plaintext.append(matrix[row1][col2]);
+                plaintext.append(matrix[row2][col1]);
+            }
+        }
+        return plaintext.toString();
+    }
+
+    private void generateMatrix() {
+        String keyWithoutDuplicates = removeDuplicateChars(key + "ABCDEFGHIKLMNOPQRSTUVWXYZ");
+        matrix = new char[5][5];
+        int index = 0;
+        for (int i = 0; i < 5; i++) {
+            for (int j = 0; j < 5; j++) {
+                matrix[i][j] = keyWithoutDuplicates.charAt(index);
+                index++;
+            }
+        }
+    }
+
+    private String removeDuplicateChars(String str) {
+        StringBuilder result = new StringBuilder();
+        for (int i = 0; i < str.length(); i++) {
+            if (result.indexOf(String.valueOf(str.charAt(i))) == -1) {
+                result.append(str.charAt(i));
+            }
+        }
+        return result.toString();
+    }
+
+    private String prepareText(String text) {
+        text = text.toUpperCase().replaceAll("[^A-Z]", "");
+        StringBuilder preparedText = new StringBuilder();
+        char prevChar = '\0';
+        for (char c : text.toCharArray()) {
+            if (c != prevChar) {
+                preparedText.append(c);
+                prevChar = c;
+            } else {
+                preparedText.append('X').append(c);
+                prevChar = '\0';
+            }
+        }
+        if (preparedText.length() % 2 != 0) {
+            preparedText.append('X');
+        }
+        return preparedText.toString();
+    }
+
+    private int[] findPosition(char c) {
+        int[] pos = new int[2];
+        for (int i = 0; i < 5; i++) {
+            for (int j = 0; j < 5; j++) {
+                if (matrix[i][j] == c) {
+                    pos[0] = i;
+                    pos[1] = j;
+                    return pos;
+                }
+            }
+        }
+        return pos;
+    }
+
+    public void printMatrix() {
+        System.out.println("\nPlayfair Cipher Matrix:");
+        for (int i = 0; i < 5; i++) {
+            for (int j = 0; j < 5; j++) {
+                System.out.print(matrix[i][j] + " ");
+            }
+            System.out.println();
+        }
+    }
+}


Test patch:
diff --git a/src/test/java/com/thealgorithms/ciphers/PlayfairTest.java b/src/test/java/com/thealgorithms/ciphers/PlayfairTest.java
new file mode 100644
index 00000000..5562241b
--- /dev/null
+++ b/src/test/java/com/thealgorithms/ciphers/PlayfairTest.java
@@ -0,0 +1,37 @@
+package com.thealgorithms.ciphers;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+public class PlayfairTest {
+
+    @Test
+    public void testEncryption() {
+        PlayfairCipher playfairCipher = new PlayfairCipher("KEYWORD");
+
+        String plaintext = "HELLO";
+        String encryptedText = playfairCipher.encrypt(plaintext);
+        assertEquals("GYIZSC", encryptedText);
+    }
+
+    @Test
+    public void testDecryption() {
+        PlayfairCipher playfairCipher = new PlayfairCipher("KEYWORD");
+
+        String encryptedText = "UDRIYP";
+        String decryptedText = playfairCipher.decrypt(encryptedText);
+        assertEquals("NEBFVH", decryptedText);
+    }
+
+    @Test
+    public void testEncryptionAndDecryption() {
+        PlayfairCipher playfairCipher = new PlayfairCipher("KEYWORD");
+
+        String plaintext = "PLAYFAIR";
+        String encryptedText = playfairCipher.encrypt(plaintext);
+        String decryptedText = playfairCipher.decrypt(encryptedText);
+
+        assertEquals(plaintext, decryptedText);
+    }
+}