-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRailFenceCipher.java
More file actions
143 lines (123 loc) · 4.82 KB
/
Copy pathRailFenceCipher.java
File metadata and controls
143 lines (123 loc) · 4.82 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
package kyu3;
import java.util.Map;
import java.util.TreeMap;
public class RailFenceCipher {
//3 https://www.codewars.com/kata/58c5577d61aefcf3ff000081/train/java
static String encode(String s, int n) {
// Distributes characters across rails using a periodic index that walks
// up and down between boundary rails, then concatenates each rail content.
Map<Integer, StringBuilder> map = new TreeMap<>();
StringBuilder result = new StringBuilder();
for (int i = 0; i < n; i++) {
map.put(i, new StringBuilder());
}
char[] chars = s.toCharArray();
Counter counter = new Counter(n - 1);
for (int i = 0; i < s.length(); i++) {
int tik = counter.tik();
StringBuilder stringBuilder = map.get(tik);
stringBuilder.append(chars[i]);
map.put(tik, stringBuilder);
}
for (Map.Entry<Integer, StringBuilder> e : map.entrySet()
) {
result.append(e.getValue());
}
return result.toString();
}
static String decode(String s, int n) {
// First computes the exact size of each rail, splits ciphertext into
// contiguous rail segments, then reconstructs plaintext by replaying the
// same rail traversal cycle.
if (n < 2) {
throw new IllegalArgumentException("Number of rails must be at least 2");
}
if (s.isEmpty() || n >= s.length()) {
return s;
}
int[] size = new int[n];
Counter counter = new Counter(n - 1);
for (int i = 0; i < s.length(); i++) {
int tik = counter.tik();
size[tik]++;
}
int[] position = new int[n];
int start = 0;
for (int i = 0; i < n; i++) {
position[i] = start;
start += size[i];
}
StringBuilder result = new StringBuilder(s.length());
Counter counterRes = new Counter(n - 1);
for (int i = 0; i < s.length(); i++) {
int tik = counterRes.tik();
result.append(s.charAt(position[tik]++));
}
return result.toString();
}
/**
* Create two functions to encode and then decode a string using the Rail Fence Cipher. This cipher is used to encode
* a string by placing each character successively in a diagonal along a set of "rails". First start off moving diagonally
* and down. When you reach the bottom, reverse direction and move diagonally and up until you reach the top rail.
* Continue until you reach the end of the string. Each "rail" is then read left to right to derive the encoded string.
* <p>
* For example, the string "WEAREDISCOVEREDFLEEATONCE" could be represented in a three rail system as follows:
* <p>
* W E C R L T E
* E R D S O E E F E A O C
* A I V D E N
* The encoded string would be:
* <p>
* WECRLTEERDSOEEFEAOCAIVDEN
* Write a function/method that takes 2 arguments, a string and the number of rails, and returns the ENCODED string.
* <p>
* Write a second function/method that takes 2 arguments, an encoded string and the number of rails, and returns the
* DECODED string.
* <p>
* For both encoding and decoding, assume number of rails >= 2 and that passing an empty string will return an empty string.
* <p>
* Note that the example above excludes the punctuation and spaces just for simplicity. There are, however, tests
* that include punctuation. Don't filter out punctuation as they are a part of the string.
*/
private static class Counter {
// Generates rail indices in the sequence 0..max..1..max-1..0...
// (triangular wave), allowing both encoding and decoding to reuse
// the same movement logic.
private final int max;
private boolean vector = true;
private boolean start = true;
private int count = 0;
private Counter(int max) {
this.max = max;
}
private int tik() {
if (start) {
start = false;
return 0;
}
if (vector) {
if (count < max) {
count++;
return count;
}
if (count == max) {
vector = false;
count--;
return count;
}
}
if (!vector) {
if (count > 0) {
count--;
return count;
}
if (count == 0) {
vector = true;
count++;
return count;
}
}
return count;
}
}
}