Skip to content

Instantly share code, notes, and snippets.

@enihsyou
Created November 27, 2019 17:15
Show Gist options
  • Save enihsyou/8d4379cf358a75a5ab3cd504620e51f4 to your computer and use it in GitHub Desktop.
Save enihsyou/8d4379cf358a75a5ab3cd504620e51f4 to your computer and use it in GitHub Desktop.
Hyperskill Encryption-Decryption
package encryptdecrypt;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Path;
public final class Main {
private Main() {}
interface Algorithm {
CharSequence encrypt(CharSequence message);
CharSequence decrypt(CharSequence cipher);
}
abstract static class SymmetricEncDecAlgorithm implements Algorithm {
protected final int key;
protected SymmetricEncDecAlgorithm(int key) {
this.key = key;
}
protected abstract boolean shouldOperateOn(int character);
protected abstract int encrypt(int grain);
protected abstract int decrypt(int grain);
@Override
public CharSequence encrypt(CharSequence message) {
return message.codePoints()
.map(c -> {
if (shouldOperateOn(c)) {
return encrypt(c);
}
return c;
})
.collect(StringBuilder::new,
StringBuilder::appendCodePoint, StringBuilder::append);
}
@Override
public CharSequence decrypt(CharSequence cipher) {
return cipher.codePoints()
.map(c -> {
if (shouldOperateOn(c)) {
return decrypt(c);
}
return c;
})
.collect(StringBuilder::new,
StringBuilder::appendCodePoint, StringBuilder::append);
}
}
static class ShiftAlgorithm extends SymmetricEncDecAlgorithm {
private ShiftAlgorithm(int key) {
super(key);
}
private static final int ALPHABETIC_COUNT = (int) 'z' - (int) 'a' + 1;
@Override
protected boolean shouldOperateOn(int character) {
return Character.isAlphabetic(character);
}
@Override
protected int encrypt(int grain) {
int loopBoundary = getLoopBoundary(grain);
return (grain - loopBoundary + key) % ALPHABETIC_COUNT + loopBoundary;
}
@Override
protected int decrypt(int grain) {
int loopBoundary = getLoopBoundary(grain);
int dividend = grain - loopBoundary - key;
return (dividend < 0 ? dividend + ALPHABETIC_COUNT : dividend)
% ALPHABETIC_COUNT + loopBoundary;
}
private static int getLoopBoundary(int grain) {
int loopBoundary = 0;
if (Character.isUpperCase(grain)) {
loopBoundary = 'A';
} else if (Character.isLowerCase(grain)) {
loopBoundary = 'a';
}
return loopBoundary;
}
}
static class UnicodeAlgorithm extends SymmetricEncDecAlgorithm {
private UnicodeAlgorithm(int key) {
super(key);
}
@Override
protected boolean shouldOperateOn(int character) {
return true;
}
@Override
protected int encrypt(int grain) {
return grain + key;
}
@Override
protected int decrypt(int grain) {
return grain - key;
}
}
private static Algorithm getAlgorithm(String type, int key) {
switch (type) {
case "shift":
return new ShiftAlgorithm(key);
case "unicode":
return new UnicodeAlgorithm(key);
default:
throw new IllegalStateException("Unexpected value: " + type);
}
}
public static void main(String[] args) throws IOException {
String op = "enc";
String data = null;
int key = 0;
PrintStream out = System.out;
String alg = "unicode";
int i = 0;
while (i < args.length) {
String arg = args[i];
switch (arg) {
case "-mode":
op = args[++i];
break;
case "-key":
key = Integer.parseInt(args[++i]);
break;
case "-data":
data = args[++i];
break;
case "-in":
if (data == null) {
String pathStr = args[++i];
data = Files.readString(Path.of(pathStr));
}
break;
case "-out":
String pathStr = args[++i];
out = new PrintStream(pathStr);
break;
case "-alg":
alg = args[++i];
break;
default:
throw new IllegalStateException("Unexpected value: " + arg);
}
i++;
}
Algorithm algorithm = getAlgorithm(alg, key);
switch (op) {
case "enc":
out.println(algorithm.encrypt(data == null ? "" : data));
break;
case "dec":
out.println(algorithm.decrypt(data == null ? "" : data));
break;
default:
throw new IllegalArgumentException(op);
}
out.close();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment