Search code examples
javawhile-loopjava.util.scannercaesar-cipher

Java: Scanner Issue?


I have a pretty simple little program here that reads in an integer, encrypts it, and then decrypts it, but for whatever reason sometimes it gives me the right answers while other times it doesn't. Code:

public class Cipher {

    public static void main(String[] args) {

        System.out.println("Welcome to Caesar Cipher Demo:");
        Scanner scanner = new Scanner(System.in);
        CaesarCipher cipher = new CaesarCipher();
        int a, n, x, y;
        int i = 1;
        while(true) {
            System.out.println("====== General Test ======");
            System.out.println("Please specify the following numbers:");
            System.out.printf("n - ");
            n = scanner.nextInt();
            scanner.nextLine();
            System.out.print("a - ");
            a = scanner.nextInt();
            scanner.nextLine();
            cipher.setN(n);
            cipher.setA(a);
            //scanner.nextLine();
            System.out.printf("plaintext value from [0 - %d] - ", (n-1));
            x = scanner.nextInt();
            y = cipher.encrypt(x);
            System.out.printf("ciphertext value - %d%n", y);

            x = cipher.decrypt(y);
            System.out.printf("back to plaintext value - %d%n", x);
            scanner.nextLine();

            System.out.printf("Continue? (1 for yes, 0 for no) - ");
            i = scanner.nextInt();
            scanner.nextLine();
            if(i == 0) break;
        }
        while(true){
            System.out.println("====== Text Message Test ======");
            cipher.setN(26);
            System.out.printf("key [0-25] - ");
            a = scanner.nextInt();
            scanner.nextLine();
            while(a < 0 || a > 25){
                System.out.printf("key must be from [0-25] - ");
                a = scanner.nextInt();
                scanner.nextLine();
            }
            cipher.setA(a);
            System.out.printf("plaintext (use English alphabet)- ");

            String plaintext = scanner.nextLine();
            plaintext = plaintext.toLowerCase();
            String ciphertext = cipher.encrypt(plaintext);
            System.out.printf("ciphertext - %s%n", ciphertext);

            plaintext = cipher.decrypt(ciphertext);
            System.out.printf("plaintext - %s%n", plaintext);

            System.out.printf("Continue? (1 for yes, 0 for no) - ");
            i = scanner.nextInt();
            scanner.nextLine();
            if(i == 0) break;
        }
    }
}

class CaesarCipher {
    private int a;
    private int n;
    private char[] letters;

    public CaesarCipher() {
        this.letters = new char[]{'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
    }

    public int getA() {
        return a;
    }

    public int getN() {
        return n;
    }

    public void setA(int a) {
        this.a = a;
    }

    public void setN(int n) {
        this.n = n;
    }

    public int encrypt(int x){
        if (x >= n){
            System.out.println("X must be less than "+n+"-1");
        }

        return (a+x) % n;

    }

    public int inverseOf(int e){
        return (n - e %n);
    }

    public int decrypt(int y){
        if (y >= n) {
            System.out.println("N must be "+ n +"-1");
        }

        return (inverseOf(a) + y % n);
    }

    public String encrypt(String plaintext){
        char[] ciphertext= new char[plaintext.length()];
        for (int j = 0; j<plaintext.length();j++) {
            char c = plaintext.charAt(j);
            int index = c- 'a';
            if (index < 0 || index > 25) {
                System.out.println("Illegal character!");
                System.exit(1);
            }
            index = encrypt(index);
            ciphertext[j] = letters[index];
        }
        return new String(ciphertext);

    }

    public String decrypt(String ciphertext){
        char[] plaintext = new char[ciphertext.length()];
        for (int j = 0; j < ciphertext.length();j++) {
            char c = ciphertext.charAt(j);
            int index = c- 'a';
            index = decrypt(index);
            plaintext[j] = letters[index];
        }
        return new String(plaintext);
    }
}

Output I'm getting:

    Welcome to Caesar Cipher Demo:
====== General Test ======
Please specify the following numbers:
n - 54
a - 44
plaintext value from [0 - 53] - 15
ciphertext value - 5
back to plaintext value - 15
Continue? (1 for yes, 0 for no) - 1
====== General Test ======
Please specify the following numbers:
n - 78
a - 55
plaintext value from [0 - 77] - 7
ciphertext value - 62
back to plaintext value - 85
Continue? (1 for yes, 0 for no) - 1
====== General Test ======
Please specify the following numbers:
n - 55
a - 54
plaintext value from [0 - 54] - 6
ciphertext value - 5
back to plaintext value - 6
Continue? (1 for yes, 0 for no) - 1
====== General Test ======
Please specify the following numbers:
n - 632
a - 43
plaintext value from [0 - 631] - 66
ciphertext value - 109
back to plaintext value - 698
Continue? (1 for yes, 0 for no) - 1
====== General Test ======
Please specify the following numbers:
n - 25
a - 3
plaintext value from [0 - 24] - 5
ciphertext value - 8
back to plaintext value - 30
Continue? (1 for yes, 0 for no) - 

As you can see, sometimes it returns the right back to plaintext value and sometimes it adds n and the plaintext value from [0 - n-1]. I believe this is due to a scanner issue, but can't figure out where exactly the problem is coming from. I was hoping another set of eyes could see something I can't. Thanks for your time, I really do appreciate it!


Solution

  • I'm not sure what you are trying to do in your decrypt function, especially the method inverseOf. But it's not correct. What you want in the decrypt function is just to subtract the key from the encrypted value (and then keep it in the correct range using the modulo operator, and and extra check that's it not negative because the modulo operator in itself is not enough to keep the value inside the bottom end of the range)

    public int decrypt(int y) {
        if (y >= n) {
            System.out.println("N must be " + n + "-1");
        }
    
        if (y < a)
            return (y - a + n) % n;
        else
            return (y - a) % n;
    }