1
\$\begingroup\$

I wrote a Java program that given a text message will print the encoded message. The problem is described in this link.

Summary:

We have to write a program that will encrypt a message that do not contain space character. Assuming that \$L\$ is the length of the message we have to put characters of this string in matrix where \$\textit{columns} \cdot \textit{rows} \ge L\$ and \$\lfloor \sqrt L \rfloor \le \textit{rows} \le \textit{columns} < \lceil \sqrt L \rceil\$. To get the encrypted message we have to iterate over column and print each one as a word.

For example:

Input: haveaniceday

Output: hae and via ecy

import java.util.Scanner;

public class Encryption {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String input = scan.next();
        int stringLengh = input.length();
        int lowerBound = getFloorSqrt(stringLengh);
        int upperBound = getCeilSqrt(stringLengh);
        IntRange range = new IntRange(lowerBound, upperBound);
        range = getRangeWithMinArea(range, stringLengh);
        char[][] grid = getGridEncryption(range, input);
        System.out.println(getEncryptedMessage(grid));
    }

    /**
     * return the ceil of the square root of a number.
     * 
     * @param number
     * @return
     */
    public static int getCeilSqrt(int number) {
        return (int) Math.ceil(Math.sqrt(number));
    }

    /**
     * return the floor of the square root of a number.
     * 
     * @param number
     * @return
     */
    public static int getFloorSqrt(int number) {
        return (int) Math.floor(Math.sqrt(number));
    }

    /**
     * Iterate over ranges enclosed by the initial range to get the one which
     * having area greater than or equal the minimal area.
     * 
     * @param initialRange
     * 
     * @param minimalArea
     * @return
     */
    public static IntRange getRangeWithMinArea(IntRange initialRange, int minimalArea) {
        if (initialRange.getLowerBound() * initialRange.getUpperBound() < minimalArea
                && initialRange.getLowerBound() <= initialRange.getUpperBound()) {
            return getRangeWithMinArea(initialRange.incremntLowerBound(), minimalArea);
        }
        return initialRange;
    }

    /**
     * Assuming a matrix of characters this function will return a phrase where
     * each word is represented by one column. eg. input:|a|b|c| |d|e|f|
     * 
     * output: ad be cf.
     * 
     * @param grid
     * @return
     */
    private static String getEncryptedMessage(char[][] grid) {
        StringBuffer str = new StringBuffer();
        for (int i = 0; i < grid[0].length; i++) {
            for (int j = 0; j < grid.length; j++) {
                if (grid[j][i] != '\u0000')
                    str.append(grid[j][i]);
            }
            str.append(" ");
        }
        return str.toString();
    }

    /**
     * 
     * @param range
     * @param str
     * @return
     */
    public static char[][] getGridEncryption(IntRange range, String str) {
        char[] text = str.toCharArray();
        char[][] ret = new char[range.getLowerBound()][range.getUpperBound()];
        int k = 0;
        for (int i = 0; i < range.getLowerBound(); i++) {
            for (int j = 0; j < range.getUpperBound() && k < str.length(); j++) {
                ret[i][j] = text[k];
                k++;
            }
        }
        return ret;
    }

    /**
     * IntRange represents a set of integer bounded by two numbers upperBound
     * and lowerBound. such as upperBound is greater or equal lowerBound.
     */
    static class IntRange {

        private final int lowerBound;
        private final int upperBound;

        IntRange(int lowerBound, int upperBound) {
            this.lowerBound = lowerBound;
            this.upperBound = upperBound;
        }

        public int getLowerBound() {
            return lowerBound;
        }

        public int getUpperBound() {
            return upperBound;
        }

        public IntRange incrementUpperBound() {
            return new IntRange(this.lowerBound, this.upperBound + 1);
        }

        public IntRange incremntLowerBound() {
            return new IntRange(this.lowerBound + 1, this.upperBound);
        }
    }
}
\$\endgroup\$
2
\$\begingroup\$

You have a couple typo's in your names.

    int stringLengh = input.length();

This variable should probably be called stringLength.

    public IntRange incremntLowerBound() {

This method should probably be called incrementLowerBound.


This section looks pretty fancy at first, but actually it's just splitting up a string.

/**
 * 
 * @param range
 * @param str
 * @return
 */
public static char[][] getGridEncryption(IntRange range, String str) {
    char[] text = str.toCharArray();
    char[][] ret = new char[range.getLowerBound()][range.getUpperBound()];
    int k = 0;
    for (int i = 0; i < range.getLowerBound(); i++) {
        for (int j = 0; j < range.getUpperBound() && k < str.length(); j++) {
            ret[i][j] = text[k];
            k++;
        }
    }
    return ret;
}

There's better ways to do this than copying character for character. Consider System.arraycopy or String.substring.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.