I have this Vigenère cipher code that works, but it spits out a number one on the first encryption when I put "Attack at Dawn" (POTTER). It comes out as 1inuhc Qi Xubf. What is causing this?
public class vigenere {
public static void main(String[] args) {
System.out.println();
char[] message = args[0].toCharArray();
int code;
int index = 0;
code = args[1].charAt(index%args[1].length()) - 96;
for(int i = 0; i < message.length; i++){
code = args[1].charAt(index%args[1].length()) - 96;
if(65 <= message[i] && message[i] <= 90){
index++;
message[i] = (char) (65 + ((message[i] - 65) + code) % 26);
}
else if(97 <= message[i] && message[i] <= 122){
index++;
message[i] = (char) (97 + ((message[i] - 97) + code) % 26);
}
System.out.print(message[i]);
}
}
}
I think that you input is
text to be encrypted "Attack at Dawn"
key = potter (should be in all low case letter right) because of this line
code = args[1].charAt(index%args[1].length()) - 96;
I enter the key as Potter and get your result posted.but I use potter, it works fine.
Related
I am trying to challenge the Caesar Cipher problem, but am stuck at one condition, the question not only move n element position but also keep loop internally in the ASCII range, so 'z' will go to 'c' not '|' if n=3.
Could someone enlighten me how to get loop inside of Character.isLetter and Character.isLowerCase base on what I am doing now? hope I am on the track, and here is my code. Thank you
public static String caesarCipher(String s, int k) {
if(k>26){
k = k % 26;
}else if (k<26){
k = (k % 26) + 26;
}
String result = new String();
int length = s.length();
for(int i=0; i<length; i++){
char ch = s.charAt(i);
if(Character.isLetter(ch)){ // only for alphabet
if(Character.isLowerCase(ch)){ // for lower case a-z
char cha = (char)(ch+k);
if(cha > 'z'){
result += (char)(ch - (26 - k));
} else {
result += cha;
}
} else if(Character.isUpperCase(ch)){ // for upper case a-z
char cha = (char)(ch+k);
if(cha > 'Z'){
result += (char)(ch - (26 - k));
}else {
result += cha;
}
}
} else {
result += ch;
}
}
return result;
}
I was doing practice algorithms problems HackerRank website and I submitted my code firstly in C language but I got some Test Cases incorrect. I thought my logic was right so I ported my code to Java and I passed all my Test Cases.
Link to the problem definition:
https://www.hackerrank.com/challenges/caesar-cipher-1
Here is my code in C:
int main(){
int n;
scanf("%d", &n);
char* s = (char *)malloc(n * sizeof(char));
scanf("%s", s);
int k;
scanf("%d", &k);
k = k % 26;
for(int i = 0; i < n; i++){
if(s[i] >= 65 && s[i] <= 90){
s[i] += k;
if(s[i] > 90){
s[i] = s[i] - 90 + 64;
}
}
if(s[i] >= 97 && s[i] <= 122){
s[i] += k;
if(s[i] > 122){
s[i] = s[i] - 122 + 96;
}
}
}
printf("%s", s);
return 0;
}
And here is my code in Java:
public class Solution {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
String str = br.readLine();
int K = Integer.parseInt(br.readLine());
K %= 26;
for(int i = 0; i < N; i++){
char c = str.charAt(i);
if(c >= 65 && c <= 90){
c += K;
if(c > 90){
c = (char)(c - 90 + 64);
}
}
if(c >= 97 && c <= 122){
c += K;
if(c > 122){
c = (char)(c - 122 + 96);
}
}
System.out.print(c);
}
}
}
Both my solutions are passing Sample Test Cases and logic is all the same. I can't understand why it is showing W/A in C in some Test Cases.
P.S. This is practice problem solution and not a live contest solution.
C strings are terminated with a special '\0' character appended to their end. So an actual string is always 1 character longer than the visible text.
You are not allocating memory for the input string null terminator:
Replace
char* s = (char *)malloc(n * sizeof(char));
with
char* s = malloc(n * sizeof(char) + 1);
or even
char* s = malloc(n + 1);
as sizeof(char) is guaranteed to be 1.
In addition there would be a problem with these lines:
if(s[i] >= 97 && s[i] <= 122){
s[i] += k;
s[i] might be 122 and k might be very well greater than 5. As s[i] is most likely signed char type, and it might overflow past the value of 127, which is the maximum for signed char. And signed integer overflow has an undefined behavior.
This one is working fine.
int main(){
int n;
scanf("%d",&n);
char* s = (char *)malloc(10240 * sizeof(char));
scanf("%s",s);
int k;
scanf("%d",&k);
for(int i = 0; i < n; i++){
if(s[i] >= 65 && s[i] <= 90){
s[i] = (s[i]-'A'+k)%26 +'A';
}
if(s[i] >= 97 && s[i] <= 122){
s[i] = (s[i]-'a'+k)%26 +'a';
}
}
printf("%s", s);
return 0;
}
Just updated contents of if blocks and malloc size.
I am doing this as a project. The point of it is to created a password with the types of characters you picked at the length you pick. But when i use option D, it doesn't return anything and on options B and C, no matter the length I put in, i always get a random number of characters. If you could run it, and point me in the right direction of fixing this, it would be greatly appreciated.
import java.util.Scanner;
public class Password
{
public static void main(String [] args){
String password = "";
String temp = "";
int randLetter = 0;
int randNumber = 0;
int randPunct = 0;
int charSelection = 0;
int counter = 0;
String lowerCase = "abcdefghijklmnopqrstuvwxyz";
String upperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
String number = "0123456789";
String punctuation = "!?";
Scanner in = new Scanner(System.in);
System.out.println("Please choose what characters you would like to use.");
System.out.println("[A] Lowercase Letters");
System.out.println("[B] Lowercase & Uppercase Letters");
System.out.println("[C] Lowercase, Uppercase, Numbers");
System.out.println("[D] Lowercase, Uppercase, Numbers, Punctuation");
System.out.print("Selection: ");
String selection = in.next();
System.out.println();
System.out.print("Select a length (1 - 14): ");
int length = in.nextInt();
if(selection.equalsIgnoreCase("A")){
for (int i = 0; i < length; i++){
randLetter = 1 + (int)(Math.random() * 26);
temp = lowerCase.substring(randLetter - 1 , randLetter);
password += temp;
}
}
else if(selection.equalsIgnoreCase("B")){
while (counter < length){
for (int i = 0; i < length; i++){
charSelection = 1 + (int)(Math.random() * 10);
if (charSelection < 5){
randLetter = 1 + (int)(Math.random() * 26);
temp = lowerCase.substring(randLetter - 1 , randLetter);
counter++;
password += temp;
}
else if (charSelection > 5 && charSelection < 10){
randLetter = 1 + (int)(Math.random() * 26);
temp = upperCase.substring(randLetter - 1 , randLetter);
counter++;
password += temp;
}
}
}
}
else if(selection.equalsIgnoreCase("C")){
while (counter < length){
for (int i = 0; i < length; i++){
charSelection = 1 + (int)(Math.random() * 17);
randNumber = 1 + (int)(Math.random() * 9);
if (charSelection < 5){
randLetter = 1 + (int)(Math.random() * 26);
temp = lowerCase.substring(randLetter - 1 , randLetter);
counter++;
password += temp;
}
else if (charSelection > 5 && charSelection < 10){
randLetter = 1 + (int)(Math.random() * 26);
temp = upperCase.substring(randLetter - 1 , randLetter);
counter++;
password += temp;
}
else if (charSelection > 15 && charSelection < 17){
randLetter = 1 + (int)(Math.random() * 26);
temp = number.substring(randNumber - 1 , randNumber);
counter++;
password += temp;
}
}
}
}
else if(selection.equalsIgnoreCase("D")){
while (counter < length){
for (int i = 1; i < 0; i++){
charSelection = 1 + (int)(Math.random() * 20);
randNumber = 1 + (int)(Math.random() * 9);
randPunct = 1 + (int)(Math.random() * 2);
if (charSelection < 5){
randLetter = 1 + (int)(Math.random() * 26);
temp = lowerCase.substring(randLetter - 1 , randLetter);
counter++;
password += temp;
}
else if (charSelection > 5 && charSelection < 10){
randLetter = 1 + (int)(Math.random() * 26);
temp = upperCase.substring(randLetter - 1 , randLetter);
counter++;
password += temp;
}
else if (charSelection > 15 && charSelection < 17){
randLetter = 1 + (int)(Math.random() * 26);
temp = number.substring(randNumber - 1 , randNumber);
counter++;
password += temp;
}
else if (charSelection > 17){
randLetter = 1 + (int)(Math.random() * 26);
temp = punctuation.substring(randPunct - 1 , randPunct);
counter++;
password += temp;
}
}
}
}
System.out.println(password);
}
}
for (int i = 1; i < 0; i++){
This condition is never true, so the loop body never executes.
It's unclear what you really intend here, so it is hard to suggest the correct condition - do you mean length instead of 0, like you do in other loops?
Mode "B" and "C":
this loop: while (counter < length){ will run the password generation a second time, if atleast one of the value generate in this line:
charSelection = 1 + (int)(Math.random() * 10);
is equal to 5 (Mode "B"), or either equal to 5 or between (inclusive) 10 and 15 (Mode "C"). So basically you try length times to generate a new values, and repeat this process, until you've generated more characters (counter) than length, which will quite likely produce more than length characters. I'd recommend you eliminate the unused values and remove the while-loop in order to provide consistent behaviour.
Mode "D":
for (int i = 1; i < 0; i++){
This loop will terminate the generation, without ever generating a single character, since i < 0 doesn't hold at the loop-start (i is initialized as 1).
And a recommendation:
I'd recommend you split the code up into several parts, since there's plenty of reusable code:
Random r = new Random();
public char nextChar(String valid_chars){
return valid_chars.charAt(r.nextInt(valid_chars.length()));
}
public String generate(String chars , int len){
String tmp = "";
for(int i = 0 ; i < len ; i++)
tmp += nextChar(chars);
return tmp;
}
public static void main(String[] args){
...
switch(selection.toLowerCase()){
case "a":
{
String password = generate("abcdefghijklmnop..." , length);
System.out.println(password);
}
break;
...
}
...
}
This is helps keeping the code readable, maintainable and allows simple extension to other modes.
I am trying to implement a loop that encrypts a string to the given shift amount of int shift. The code below works great, however I'd like to change the code so that it encrypts in a descending order instead of ascending. Any clues as to what to change in the algorithm?
int shift = 3;
string line = "abc";
for (int i = 0; i < line.length(); i++) {
if (line[i] >= 'a' && line[i] <= 'z') {
int rotate = line[i] + shift;
if (rotate > 'z') line[i] = ((line[i] - 26) + shift);
else line[i] = rotate;
}
}
cout << line << endl;
With a shift of 3, the above code converts string line "abc" to "def", but I am trying to get the output of "dcb".
NOTE: The code is in C++ but I will accept JavaScript, Java, or Php suggestions just as C++, as long as it's raw code with no library resources. Thanks guys and gals.
you can just upgrade the variable shift and then instead of checking overflow of increasing check the decreasing
int shift = -3;
string line = "abc";
for (int i = 0; i < line.length(); i++) {
if (line[i] >= 'a' && line[i] <= 'z') {
int rotate = line[i] + shift;
if (rotate < 'a') line[i] = ((line[i] + 26) + shift);
else line[i] = rotate;
}
}
cout << line << endl;
you can also do the below if in your loop if you want to handle uppercases
if (line[i] >= 'A' && line[i] <= 'Z') {
int rotate = line[i] + shift;
if (rotate < 'A') line[i] = ((line[i] + 26) + shift);
else line[i] = rotate;
}
I have a program that supposedly
prompts user to input a word, phrase, or sentence.
I should then "encrypt" what you entered 13 times, printing every single time. The last thing printed should match user input.
I can only encrypt alphabetical characters. Anything else remains the same.
"encrypt" by finding the ASCII value of each character then increasing it by 2. If the letter changes case, make it so that it starts over at the a for lowercase or A for uppercase instead.
My code right now just gives me 1 encryption and stops at 2. It also only works for the first letter. My class hasn't learned arrays yet but we can try it if we want.
import java.util.Scanner;
public class Encrypt{
Scanner keyboard = new Scanner(System.in);
String message = new String();
String g = new String();
char y;
public void input(){
System.out.printf("Welcome to Encrypt.java. Please enter a word,phrase, or sentence. \n");
System.out.println();
System.out.print("-> ");
message = keyboard.nextLine();
}
public void code(){
int x = message.length()-1;
boolean enter = true;
for(int i = 0; i <= x; i++){
int j = message.charAt(i);
if((j >= 32 && j <=64) ||
(j >= 91 && j <=96) ||
(j >= 123 && j <= 127)){
}
else if((j >= 65 && j <= 90)){
j = j + 2;
if(j>90){
j = (j-90)+64;
}
}
else if(j>=97 && j <= 122){
j = j + 2;
if(j>122){
j = (j-122) + 96;
}
}
if(enter == true){
System.out.println();
System.out.print(" ");
enter = false;
}
y = (char)(j);
g = g + y;
message = g;
x = message.length()-1;
}
System.out.print(g);
System.out.println();
}
public void print(){
for(int i = 1; i <= 13; i ++){
System.out.println("Encryption " + i + ":");
this.code();
}
}
public static void main(String [] args){
Encrypt e = new Encrypt();
e.input();
e.print();
}
}
Two Things :
Resetting the variable g after every iteration.
Proper placement of message.
public void code() {
int x = message.length() - 1;
boolean enter = true;
g = "";
for (int i = 0; i <= x; i++) {
int j = message.charAt(i);
if ((j >= 32 && j <= 64) || (j >= 91 && j <= 96)
|| (j >= 123 && j <= 127)) {
}
else if ((j >= 65 && j <= 90)) {
j = j + 2;
if (j > 90) {
j = (j - 90) + 64;
}
} else if (j >= 97 && j <= 122) {
j = j + 2;
if (j > 122) {
j = (j - 122) + 96;
}
}
if(enter == true){
System.out.println();
System.out.print(" ");
enter = false;
}
y = (char) (j);
g = g + y;
}
message = g;
}
Output:
Welcome to Encrypt.java. Please enter a word,phrase, or sentence.
-> abba
Encrypt.code() message >> abba
Encrypt.code() message >> cddc
Encrypt.code() message >> effe
Encrypt.code() message >> ghhg
Encrypt.code() message >> ijji
Encrypt.code() message >> kllk
Encrypt.code() message >> mnnm
Encrypt.code() message >> oppo
Encrypt.code() message >> qrrq
Encrypt.code() message >> stts
Encrypt.code() message >> uvvu
Encrypt.code() message >> wxxw
Encrypt.code() message >> yzzy
Here's your problem
y = (char) (j);
g = g + y;
message = g;
In the first run, g is only one char, and you're making message = g;. This makes message just that one character g. I ran it deleting the message = g and it works fine. I don't know if it's your desired output, but at least it's getting past Encryption 1
Note: You should really learn how to use a debugger. That's how I spotted the problem.