Reversing a modulus operator for decrypting - java

For school, i've got an assignment to encrypt a four-digit Integer by the following requirements.
A company wants to transmit data over the telephone, but they are
concerned that their phones may be tapped. All of their data is
transmitted as four-digit integers. They have asked you to write a
method that will encrypt their data so that it may be transmitted more
securely. Your method should read a four-digit integer and encrypt it
as follows: Replace each digit by (the sum of that digit plus 7)
modulus 10. Then, swap the second digit with the fourth. Then print
the encrypted integer. Write a separate method that inputs an
en-crypted four-digit integer, and decrypts it to form the original
number.
The encrypting of the four-digit wasn't such of a problem, I've converted it to a string, then to a char array and then seperately encrypted the numbers by its needs.
The method I made looks like this:
public int encrypt4DigitNumber(int number) throws Exception {
String numberAsString = String.valueOf(number);
if (numberAsString.length() != 4) {
throw new Exception("The digit has to be 4 digits long");
}
int[] numbers = new int[4];
char[] numbersAsChars = numberAsString.toCharArray();
for (int index = 0; index < numbersAsChars.length; index++) {
int currentNumber = Character.getNumericValue(numbersAsChars[index]);
int numberToReplace = (currentNumber + 7) % 10;
numbers[index] = numberToReplace;
}
int second = numbers[1];
int fourth = numbers[3];
numbers[1] = fourth;
numbers[3] = second;
StringBuilder encryptedNumberStringBuilder = new StringBuilder();
for (int encryptedNumber : numbers) {
encryptedNumberStringBuilder.append(encryptedNumber);
}
String encryptedNumberString = encryptedNumberStringBuilder.toString();
return Integer.parseInt(encryptedNumberString);
}
The problem came when I had to de-crypt the encrypted four-digit code.
I know I had to swap the 2 array elements, and add 7 to each number in the array.
The thing I didn't know how to do was reverse the modulus operator, the only thing I can come up with is multiply the current number by 10, but that won't work.
After doing some research, I have to search the left-overs from the modulus somewhere, but I have absolutely no idea how to do that. Do I need to return those in the encrypt function aswell and pass them into the decrypt function?
Can someone explain the process of reversing the modulus operator?

If you encrypt a number from 0 to 9 (= mod 10) with an offset 7, you can of course subtract the offset from every digit during decryption and wrap around if the number is negative, but that is not very nice:
int numberToReplace = currentNumber - 7;
if (numberToReplace < 0) {
numberToReplace += 10;
}
If the encryption offset is 7, then the decryption offset would be 3 (10 - 7). You could just add 3 to each digit and apply mod 10 in order to decrypt them.
int numberToReplace = (currentNumber + 3) % 10;

Let's see what actually (i + 7) % 10 do:
0 = 7
1 = 8
2 = 9
3 = 0
4 = 1
5 = 2
6 = 3
7 = 4
8 = 5
9 = 6
As you can see there's definitely quite obvious pattern. So in order to decode our original digit back we have to do
(i + 3) % 10

Related

Adding Values to a List and Converting to BigInteger - Java [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I'm writing a code that determines the smallest integer that is a sequence of sevens followed by some number of zeros (possibly none) that is divisible by int n. Since this number can be massive, the return value should be a BigInteger.
My code so far has an if-else ladder that covers the case that if any int n is not divisible by two or five is guaranteed to only contain sevens (no zeros). In the case where int n is not divisible by two or five, my thought process was to continue adding sevens to a LinkedList in a while loop, until that list (converted to a BigInteger) is divisible by int n. The same logic goes for the case where int n is divisible by two or five, except a two for-loops would add seven and zero to the list.
My code is getting a runtime error when converting the list to a string and then to a BigInteger, specifically on the line BigInteger numBig = new BigInteger(str);. The error is: "java.lang.NumberFormatException: Zero length BigInteger (in java.math.BigInteger)" Also, I'm not quite sure the logic is sound for the case where int n is divisible by two or five.
You don't need BigInteger for this task. The idea is the following:
First you determine the number of required zeros. Since number composed of only sevens cannot be divided by 2 or 5, the number of zeros is equal to the maximum power of 2 or 5 in number n.
Now we have a number n which is not divisible by 2 or 5. Suppose that a remainder of the division of a number composed of m sevens by n is equal to r:
777...m-times..777 mod n = r
Then number composed of (m+1) sevens will have a remainder 10*r + 7, because
777..(m+1)-times...777 = 777...m-times...7 * 10 + 7
So you can just recalculate the remainder until it becomes zero.
public static BigInteger method(int n) {
int two;
for (two = 0; n % 2 == 0; two++) n /= 2;
int five;
for (five = 0; n % 5 == 0; five++) n /= 5;
int zeros = Math.max(two, five);
int sevens = 1;
int r = 7 % n;
while (r != 0) {
r = (r * 10 + 7) % n;
sevens++;
}
// Now just make a number of 'sevens' sevens and 'zeros' zeros:
StringBuilder result = new StringBuilder();
for (int i = 0; i < sevens; i++) {
result.append("7");
}
for (int i = 0; i < zeros; i++) {
result.append("0");
}
return new BigInteger(result.toString());
}
"Zero length BigInteger" means you're trying to create a BigInteger from something that has length of 0. The stack trace would tell you on which line exactly.
I would guess the bug is in your convert method. If you pass in an empty list, it tries to convert an empty string into BigInteger with new BigInteger("")
I don't know what your algorithm is supposed to do in this case. If for example you want to convert an empty list into the number zero, you can do:
if (res.isEmpty()) return BigInteger.ZERO;

Compare randomly generated number between user input

I am a cs student and i have an assignment that I'm not sure how to complete here is the prompt,
"Develop a Java console application for a simple game of guessing at a secret five-digit code (a random number from 10000 to 99999). When the user enters a guess at the code, the program outputs two values: the number of digits in the guess that are in the correct position and the sum of those digits. For example, if the secret code is 53840 and the user guesses 83241, the digits 3 and 4 are in the correct positions. Thus, the program should respond with 2 (number of correct digits) and 7 (sum of the correct digits). Allow the user to guess until s/he gets it correct."
basically the part I am stuck on is how to find which numbers are correct numbers in common and add them together. Here is my code so far.
Random rand = new Random();
int secretNumber = rand.nextInt(99999 - 10000 + 1) + 10000;
System.out.println(secretNumber);
Scanner consoleScanner = new Scanner(System.in);
int guess;
do {
System.out.print("Please enter a 5-digit code (your guess): ");
guess = consoleScanner.nextInt();
if (guess == secretNumber)
System.out.println("****HOORAY! You solved it. You are so smart****");
else if (guess > 99999 || guess < 10000)
System.out.println("Guess must be a 5-digit code between 10000 and 99999.\n");
} while (guess != secretNumber);
any help would be greatly appreciated.
You have a number. I'm going to call it blarg. Let's say blarg is a double.
You also have a number called input.
String blargString = Double.toString(blarg);
String inputString = Double.toString(input);
ArrayList<Integer[]> indexNumberList = new ArrayList<Integer[]>();
int n = 0;
for (char c : blargString.toCharArray()) {
n++;
if (c == inputString.toCharArray()[n]) {
Integer[] entry = new Integer[2];
entry[0] = n;
entry[1] = Character.getNumericValue(c);
indexNumberList.add(entry);
}
}
Now you have a list of Integer pairs. Do what you will with it. For each pair, entry[0] is the location in the number, the index, and entry[1] is the value.
Integer.toString(int) returns the string representation of an integer. You can compare the strings returned from Integer.toString(secretNumber) and Integer.toString(guess) character-by-character to determine which digits differ.
Here's how I'd go about solving that problem. My solution is quick but probably naive. Convert the number the user enters and your generated number to strings and then to two arrays of 5 bytes each. Scan through the arrays and compare two corresponding bytes at a time. Let the user know that the position of a digit was guessed correctly if two corresponding bytes are equal. Below, I show you how you can get the array of bytes you need.
byte[] a = Integer.toString(guess).getBytes();
byte[] b = Integer.toString(secretNumber).getBytes();
So you have 2 5-digit numbers that you need to compare.
I would recommend you to do this with a loop:
//Make copies so we can modify the value without changing
// the original ones.
int tempGuess = guess;
int tempSecret = secretNumber;
//Create variables for the output
int numCorrect = 0;
int sumCorrect = 0;
for(int i = 0; i < 5; i++) //for each of the digits
{
//Get the last digit of each number and remove it from the number:
int lastGuess = tempGuess%10;
tempGuess/=10;
int lastSecret = tempSecret%10;
tempSecret/=10;
//Compare both digits:
if(lastGuess == lastSecret)
{
//Found a match: Increas number of found by one
numCorrect++;
//Add value of digit to sum
sumCorrect += lastGuess;
}
}
//numCorrect now contains the number of matching digits
//sumCorrect now contains the sum of matchig digits
The solution can be address like:
define an counter for the coincidences and an accumulator for the adition of those
make a loop through the guess and compare char by char if the input at any given char match the random number, if so:
increase counter by one and add to the accumulator the integer value of the char.
Example:
final String s1 = Integer.toString(secretNumber);
final String s2 = Integer.toString(guess);
for (int i = 0; i < s1.length(); i++) {
if (s1.charAt(i) == s2.charAt(i)) {
counter++;
acumm = Character.getNumericValue(s1.charAt(i));
}
}
System.out.println("There is/are " + counter + " coincidences");
System.out.println("The addition of those is: " + acumm);
you could use integers, use modulus and divide to get the digit you want.
53840 % 100000 / 10000 = 5
53840 % 10000 / 1000 = 3
loop and compare

Converting a decimal number to binary in java not showing leading zeroes

This is my function in Java:
public static String convertFromDecimal(int number, int base)
{
String result = "";
/*
* This while loop will keep running until 'number' is not 0
*/
while(number != 0)
{
result = (number%base) + result; // Appending the remainder
number = number / base; // Dividing the number by the base so we can get the next remainder
}
// If the number is already 0, then the while loop will ignore it, so we will return "0"
if(result == "")
{
return "0";
}
return result;
}
It works fine for numbers that convert to numbers not beginning with 0, if the number is supposed to have a zero at the start, it will not record it, could anyone tell me why?
For example, if I print out
convertFromDecimal(13,2) it returns
1101
Which is correct, but if I print out
convertFromDecimal(461,2), I get
111001101
Where the actual answer is
0000000111001101
So it's the same as my answer without the leading zeroes, if anyone knows why I would appreciate the help, thank you.
EDIT My question is different because I don't want 16 digits, I want the binary number of the given decimal, a calculator like this can explain what I want.
I assume you are looking to format all your answers as shorts (16 bits).
In this case, simply check the length of your current string, and add on zeroes as needed.
int zeroesRemaining = 16 - result.length();
for (int i = 0; i < zeroesRemaining; i++) {
result = "0" + result;
}
Alternatively, if you want to do it faster, use a StringBuilder.
int zeroesRemaining = 16 - result.length();
StringBuilder tempBuilder = new StringBuilder(result);
for (int i = 0; i < zeroesRemaining; i++) {
tempBuilder.insert(0, 0); //inserts the integer 0 at position 0 of the stringbuilder
}
return tempBuilder.toString(); //converts to string format
There is also probably a formatter that could do this, but I don't know of such.
If you want to change the number of zeroes to be the closest integer primitive, just set zeroesRemaining to be the (least power of 2 that is greater than the number of bits) minus (the number of bits).
Since you want fixed lengths for your result, in groups of 8 bits, the easiest way is to append 0 to the front of your result until its length is a multiple of 8.
That is as simple as
wile (result.length() % 8 > 0)
{
result = "0" + result;
}
return result;

Longest Snake Sequence

Question : A set of numbers separated by space is passed as input. The program must print the largest snake sequence present in the numbers. A snake sequence is made up of adjacent numbers such that for each number, the number on the right or left is +1 or -1 of it's value. If multiple snake sequences of maximum length is possible print the snake sequence appearing in the natural input order.
Example Input/Output 1:
Input:
5 6 7 9 8 8
Output:
5 6 7 8 9 8
8 9 8 7 6 5
Example Input/Output 2:
Input:
9 8 7 5 3 0 1 -2 -3 1 2
Output:
3 2 1 0 1
void doPermute(int[] in, StringBuffer out, boolean[] used, int length, int level, StringBuffer max) {
if (level == length) {
int count = 0;
for (int i = 1; i < out.length(); i++) {
if (Math.abs(Character.getNumericValue(out.charAt(i)) - Character.getNumericValue(out.charAt(i - 1))) != 1) {
//System.out.println(Character.getNumericValue(i) - Character.getNumericValue(i - 1) + " " + i + " yes");
count++;
break;
}
}
if (count == 0) {
max.append(out + " ");
}
return;
}
for (int i = 0; i < length; ++i) {
if (used[i]) {
continue;
}
out.append(in[i]);
used[i] = true;
doPermute(in, out, used, length, level + 1, max);
used[i] = false;
out.setLength(out.length() - 1);
}
}
As i am using StringBuffer my code passed the test cases that contains positive value (first test case) but failed in test cases containing negative values(second test case).
Update:-
I replaced stringbuffer with Integer[] and made few changes.it works fine for smaller inputs of length 8 or 9. How to make it fast for larger inputs of length 13 to 15?
Have you tried doing the process using an array of integers?
Scanner sc = new Scanner(System.in);
String s = sc.nextLine(); //The numbers entered in string format separated by spaces
String ss = s.split(" "); //Numbers separated by space will be put as individual numbers in a String array but each number is still in string format
int l = ss.length, i = 0;
int[] n = new int[l]; //The integer array which will store the values
for(i = 0; i < l; i++)
{
n[i] = Integer.parseInt(ss[i]); //Has integers now instead of string numbers
}
There might be creation of a few extra arrays but then calling the Character.getNumericValue() function repeatedly can also reduce efficiency. Also might solve your StringBuffer problem.
But SkillRack is very annoying anyway.
Your comparison isn't finding adjacent numbers for negative values.
For example: Abs(-2) - (-3) = 5 but -2 and -3 should be adjacent.
Ok. I see you're parsing - and digit separately.
Given the requirement of what a snake sequence is, the longest snake sequence for "5 6 7 9 8 8" is "5 6 7". The output listed above does not correspond to the definition: " adjacent numbers such that for each number, the number on the right or left is +1 or -1 of it's value". How does "5 6 7 8 9 8" meet the definition of snake sequence for "5 6 7 9 8 8"? Sorry I couldn't help.
You might want to parse the code into Integers, store the longest sequences in a map).
#Test
public void testSnake(){
String t2 = "9 8 7 5 3 0 1 -2 -3 1 2";
List<String> numsStr = Arrays.asList(t2.split(" "));
List<Integer> nums = new ArrayList();
HashMap<Integer,List<Integer> > numMap = new HashMap();
numsStr.forEach((s) -> {
Integer val = Integer.decode(s);
nums.add(val);
});
nums.forEach((num) -> {
System.out.println("num: " + num);
// track longest sequence, store in numMap
});
// Print numMap
}

Java Integer digit reader

I am creating a method that needs to read a 5 digit integer digit by digit. (ie 26505 would be read as 2 6 5 0 5, and each digit could be read individually in another method) I cannot convert the integer to a string and read each character because I need the digits to be read by another method. It has also been suggested to use %10 but that wouldnt give me individual digits. Also, the integer needs to be read digit by digit from the left to right. I hope this is clear enough, but I am really confused on how to complete this and everything I have tried does not work. Any help offered would be appreciated, thank you.
while(d>=10){
j=code%d;
d=d/10;
printDigit(j)
This will return an array with the integer digits in order.
public static int[] integerToDigits(int n)
{
int[] digits= new int[5];
int temp = n;
for(int i = 0; i < 5; i++)
{
digits[4-i] = temp % 10;
temp /= 10;
}
return digits;
}
integerToDigits(12345) = {1,2,3,4,5}
For getting single digits from left-to-right: -
26505 / 10000 = 2
26505 % 10000 = 6505
6505 / 1000 = 6
6505 % 1000 = 505
505 / 100 = 5
505 % 100 = 5
5 / 10 = 5
I think you can now implement it.
But, if you are OK with traversing from right-to-left, it would be easier, since then your denominator will be fixed to 10: -
26505 % 10 = 5
26505 / 10 = 2650
2650 % 10 = 0
2650 / 10 = 265
265 % 10 = 5
265 / 10 = 26
26 % 10 = 6
26 / 10 = 2
2 % 10 = 2
Something totally lazy would look like
final int [] digits = {score % 1000 / 100, score % 100 / 10, score % 10};
which would work if you know your ints will never be larger than 999, for example.
From this example, it is trivial to improve it to support arbitrary integers by calculating the next power of ten from your integer and then adding digits to the array in a loop.
You can do this:
you can create a integer array and parse the each character of the user input string into and store into an array
then you can use this array for your other method.
e.g.
Scanner scan = new Scanner(System.in);
String str = scan.nextLine();
int[] digitArray = new int[str.length()];
for(int i=0; i<str.length(); i++)
{
String temp = Character.toString(str.charAt(i));
System.out.println("temp is "+temp);
digitArray[i] = Integer.parseInt(temp);
}
for (int i =0; i<digitArray.length; i++) {
System.out.println(digitArray[i]);
}

Categories