-
Notifications
You must be signed in to change notification settings - Fork 21.2k
Expand file tree
/
Copy pathRailFenceCipher.java
More file actions
149 lines (128 loc) · 5.64 KB
/
Copy pathRailFenceCipher.java
File metadata and controls
149 lines (128 loc) · 5.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package com.thealgorithms.ciphers;
/**
* 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) {
checkInput(str, 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 pattern.
boolean down = true;
// Collect the characters of every rail separately. Using one buffer per rail (instead of a
// rails x length matrix with a placeholder character) keeps every character of the input,
// including characters that would otherwise be indistinguishable from the placeholder.
StringBuilder[] railBuffers = new StringBuilder[rails];
for (int i = 0; i < rails; i++) {
railBuffers[i] = new StringBuilder();
}
int row = 0; // Start at the first rail
// Distribute the characters of the string over the rails following the zigzag pattern.
for (int i = 0; i < str.length(); i++) {
// 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 to the rail it belongs to.
railBuffers[row].append(str.charAt(i));
// Move to the next row based on the direction.
if (down) {
row++;
} else {
row--;
}
}
// Construct the encrypted string by reading the rails top to bottom.
StringBuilder encryptedString = new StringBuilder(str.length());
for (StringBuilder railBuffer : railBuffers) {
encryptedString.append(railBuffer);
}
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) {
checkInput(str, 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();
}
// Rejects inputs the zigzag pattern is not defined for.
private static void checkInput(String str, int rails) {
if (str == null) {
throw new IllegalArgumentException("Input string must not be null");
}
if (rails <= 0) {
throw new IllegalArgumentException("Number of rails must be positive, but was " + rails);
}
}
}