Seeking an explanation of Caesar Cipher code [closed] - javascript

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
After trying (and failing) to code a Caesar Cipher assignment for the Odin Project exercise, I finally caved in and looked up the answer. However, I do not quite understand it.
I am seeking an explanation of each line does and why it works. The code I copied has some brief descriptions of what each line does, but I still don't understand how it all works.
const caesar = function (str, amount) {
// Wrap the amount
if (amount < 0) {
return caesar(str, amount + 26);
}
// Make an output variable
var output = "";
// Go through each character
for (var i = 0; i < str.length; i++) {
// Get the character we'll be appending
var c = str[i];
// If it's a letter...
if (c.match(/[a-z]/i)) {
// Get its code
var code = str.charCodeAt(i);
// Uppercase letters
if (code >= 65 && code <= 90) {
c = String.fromCharCode(((code - 65 + amount) % 26) + 65);
}
// Lowercase letters
else if (code >= 97 && code <= 122) {
c = String.fromCharCode(((code - 97 + amount) % 26) + 97);
}
}
// Append
output += c;
}
// All done!
return output;
};

The first if-statement:
if (amount < 0) {
return caesar(str, amount + 26)
}
Makes sure that the shifting amount is 0 and above by calling itself until it is. Then the following line loops through all the characters in the entire string.
for (var i = 0; i < str.length; i++) {
For every character it checks if its a letter using something called a regex (Google for more information)
if (c.match(/[a-z]/i)) {
The line
var code = str.charCodeAt(i);
Gets the number representing the character at position "i" in the string. The number is the way the computer represents letters and other characters. Upper- and lowercase characters have two completely different numbers associated with them. That is what the two following if-statements is for. I will explain the one for lowercase letters, you should be able to see how the uppercase one works as well.
c = String.fromCharCode(((code - 65 + amount) % 26) + 65);
It starts by subtracting 65 from the number. This is because the first lowercase letter "a" has a value of 65. After that it shifts the result by "amount". The %-sign might seem weird. But all it does is divide the two sides and returning the "rest", the residual number. For example if we write:
5 % 2
It is equal to 1. This is done to "loop" the number and keep it between 0 and 26. After that it adds back the 65 and turns the number back to a character. The last line:
output += c;
Adds the character to the resulting string. Hope this helped you out!

Related

Find time to write a number in one figure [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 days ago.
Improve this question
write a function to calculate the number of milliseconds needed to type a number with one finger in javaScript
am try to solve this question but i don't have any idea how am solve this problem.
If I understand the comments well here's the answer
function calcTime (digits, num ){
const digits_arr = Array.from(digits);
let last_index = 0, new_index, time =0;
for (const n of num) {
new_index =digits_arr.findIndex(x => x===n);
time += Math.abs(new_index - last_index);
last_index = new_index;
}
return time;
}
example: Input: digits = "0123456789", num = "201" Output: 4
Here is the solution of Time Complexity: O(n) and Space Complexity: O(1):
def typing_time(digits, num):
typing_time = 0
start = 0
for digit in num:
index = digits.index(digit)
typing_time += abs(start - index)
start = index
return typing_time
# Test code
print(typing_time('0123456789', '210')) # 4
print(typing_time('8459761203', '5439')) # 17
Thanks to AbdelazizAlsabagh's answer I've finally understand the trick with the indexes!. I'm posting the full problem to solve (untested).
Number Generator
A digit-only keyboard contains all 10 digits from 0 to 9. They all exist in one line.
Give a string of 10 digits illustrating how the keys are positioned. To type a digit, you start from index zero to the index of the target digit. It takes |a - b| milliseconds to move from index a to index b.
Write a function to calculate the number of milliseconds needed to type a number with one finger.
Input: digits = '0123456789', num = '210
Output: 4
Input: digits = '8459761203', num = '5439'
Output: 17
Constraints:
digits.length == 10
digits contains each digit [0-9] exactly one in some order
1 <= num.length <= 10e4
num[i] is digit
def number_gen_idx(digits: str, nums: str) -> str:
"""
>>> number_gen_idx('0123456789', '210')
4
>>> number_gen_idx('8459761203', '5439')
17
"""
digits_idx = defaultdict(int)
for idx, digit in enumerate(digits):
digits_idx[digit] = idx
curr_ptr = 0
result = 0
for digit in nums:
result += abs((digits_idx[digit] - curr_ptr))
curr_ptr = digits_idx[digit]
return result

String Compression

A list of strings should be compressed into their shortest forms by expressing repetitions with numbers. If a letter only shows up only once, the "1" before it should be omitted.
For example
"aabbaccc" can be compressed into "2a2ba3c" if subdivided into units of 1.
"ababcdcdababcdcd" can be compressed into "2ab2cd2ab2cd" if subdivided into units of 2.
"abcabcdede" can be compressed into "2abcdede" if subdivided into units of 3 and so on.
I need to compress the following strings to the following shortest lengths
"aabbaccc", 7
"ababcdcdababcdcd", 9
"abcabcdede", 8
"abcabcabcabcdededededede", 14
"xababcdcdababcdcd", 17
My code only works for case 1 and 5 because I only know how to subdivide strings into units of 1. I am not sure how to subdivide for units greater than 1 and need someone to edit my code.
// traverse string, keep count of repeated chars
// if cur and next char is the same, inc count
// otherwise, concat cur char and count to output string, reset counter to 1
// return compressed string, only if the length is less than the original string, otherwise, return original string
let stringCompression = (s) => {
let out = '';
let count = 1;
for (let i = 0; i < s.length; i++) {
let cur = s[i];
let next = s[i + 1];
if (cur === next) {
count++;
} else {
out += String(count) + cur;
final = out.replace('1','')
count = 1;
}
}
return final.length < s.length ? final : s;
}
console.log(stringCompression('aabbaccc').length); // is 7
For anyone who can read Korean, the original source is question 1 from here
Let's call compression parts a chunk. For example, in "ababcdcdababcdcd" (which can be compressed either to "2ab2cd2ab2cd" or to "2ababcdcd") "ab", "cd" and "abcd" are chunks.
You can write a cycle:
for(let i = N; i > ; i--)
where N is the maximum possible length of a chunk (obviously it is the length of a string divided by 2) and i is current chunk size we assume. So we will start looking for the biggest possible chunks. In case of "xababcdcdababcdcd" it is:
"xababcdc"
"ababcdcd"
...
And each time you find a repeating chunk, you replace it
However, there is another path. I think it may be possible to solve this task by using Recursive Regular Expressions.

Math behind obtaining a charaters Ascii code

So, basically I am doing some JS exercises and I understand this code, just cant figure out whats the math behind obtaining characters Ascii code in String.fromCharCode function?
why do we decrement by 18?
Have the function LetterChanges(str) take the str parameter being passed and modify it using the following algorithm. Replace every letter in the string with the letter following it in the alphabet (ie. c becomes d, z becomes a). Then capitalize every vowel in this new string (a, e, i, o, u) and finally return this modified string.
function LetterChanges(str) {
str = str.trim().toLowerCase();
var len = str.length;
var newStr = '';
for (var i = 0; i < len; i++) {
if (/[a-ce-gi-mo-su-y]/.test(str[i])) {
newStr += String.fromCharCode(((str[i].charCodeAt(0) - 18) % 26) +
97)
}
else if (/[zdhnt]/.test(str[i])) {
newStr += String.fromCharCode(((str[i].charCodeAt(0) - 18) % 26) +
65);
}
else {
newStr += str[i];
}
}
return newStr;
}
LetterChanges(readline());
Fact: charCode for 'a' is 97, and (97 - 18) % 26 == 1
Take 'b' for example, (98 - 18) % 26 == 2, so after change, its charCode equals 97 + 2 == 99, becomes 'c'. This rule applies to all 'a-z'.
Now you should see the pattern.
Quiz: what if you want to change uppercase letters, what would you pick as the "magic number" for this case?
About ASCII
Well, as you know, computers don't store characters as 'a', 'b', 'z' or '.', they only accept binary bits (0 or 1). These binary bits can be used to form integers and numbers, but not strings and characters.
So how does the computer store characters? That's where ASCII (American Standard Code for Information Interchange) comes in.
So the idea is that each character needs to be stored as a number, and ASCII code is then the standardization for what number corresponds to what character and vice versa.
So to answer your first question: String.fromCharCode(x) is just returning you the character in the standardized ASCII table corresponding to the number x. For eg, String.fromCharCode(65) will return you 'A' because the ASCII code for 'A' is standardized by the standard as 65.
Why -18
It's a clever (but confusing) hack to force all the lowercase letters to the character following it.
Because str has been made to be lowercase by the line str = str.trim().toLowerCase();, str[i] will now only contain values from 97 ('a') to 97+25 = 122 ('z').
Now 18 = 122 (mod 26) or 122%26.
This is necessary to accommodate for the fact that 'z' needs to go to 'a', and since we only have 26 characters from 'a' to 'z' that we need to "wrap around" (modulus/%)
Note that:
(97('a')-18)%26 = 1
(98('b')-18)%26 = 2
...
(122('z')-18)%26 = 0
So when you add 97 ('a') to each of the numbers you get a function mapping of 'a'->'b', 'b'->'c', ... , 'z'->'a'

Can't figure out parseInt, even after research in JS and JQ [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 8 years ago.
Improve this question
I have an object with a property containing a large string. This property has a value with random numbers generated earlier in the script in the format x , x , x , x ... (isn't and can't be an array because of other needs for the variable within the program) and so on. I am trying to get the sum of these numbers and my first thought was to use parseInt() to do this by splitting them all up then adding them together, but when I do this it only returns the first number. Is this what I should do but I'm just doing it wrong? Or is there another function that would make this easier?
The program is a blackjack game I'm making to see how well i understand everything I am learning.
Here is the function i am trying to make to see if the user busts when taking a hit (not much so far because i can't figure out the parseInt thing)
'
function checkBust() {
var total = parseInt(user.hand, 10);
}
'
the user object
'
var user = {
hand: dealUser()
};
'
and the functions to set the object property
function randomCard() {
// random number between 0 and 10
var j = Math.random() * 10;
// round that number into a var called card
var card = Math.round(j);
// if card is 0, assign a J Q or K by making a random number again
if (card === 0) {
//another random number
var k = Math.random() * 10;
// checks random number and assign J Q or K
if (k <= 4) {
card = 'J';
} else if (k <= 7) {
card = 'Q';
}
else {
card = 'K';
}
}
// value of the function is a single card
return card;
}
function dealUser() {
// empty array to store cards
var x = [];
// var to start for loop
var i = 0;
// start for loop
for (i; i < 2; i++) {
// add a random card to the i^th index of x
x[i] = randomCard();
}
// value for function is array of two cards x[0] , x[1]
var cards = x[0] + " , " + x[1];
return cards;
}
parseInt will stop parsing when it reaches a non numeric character.
parseInt('1234,5678', 10); // => 1234
// since a comma (,) is not a numeric character, everything after is ignored.
You have to split the string into an array of strings using the comma as the delimiter:
'1234,5678'.split(','); // => ['1234', '5678'];
Then parse each element of the array to convert them to numbers and then you can sum them.
Here's how I'd do it:
var nums = "1,2,3,4,5";
var sum = nums.split(',').reduce(function(memo, num) {
return memo + parseInt(num, 10);
}, 0);
console.log(sum); // => 15
That should work. See jsbin example.
Note the split parameter needs to match the delimiters you use in your string. for this example ',' is appropriate. For your example you might need /\s*,\s*/.
Unrelated
Since you provided an example of code I can see that you're spending a lot of effort attempting to duck punch and transform the values to the types you need instead of exposing the types in an object. Might I suggest:
function Stack(cards) {
this.cards = cards || [];
}
Stack.prototype.toString = function() {
return this.cards.join(' , ');
};
Stack.prototype.sum = function() {
return this.cards.reduce(function(memo, card) {
return memo + parseInt(card, 10);
}, 0);
};
function randomCard() {
return Math.floor(Math.random() * 13) + 1;
}
Stack.dealHand = function() {
var card1 = randomCard(), card2;
do { card2 = randomCard(); } while (card1 === card2);
return new Stack([card1, card2]);
};
// Example
var hand = Stack.dealHand();
console.log(hand + ' = ' + hand.sum()); // => '3 , 11 = 14'

Advice on how to code Luhn Credit Card validation with Javascript?

I'm pretty awful at Javascript as I've just started learning.
I'm doing a Luhn check for a 16-digit credit card.
It's driving me nuts and I'd just appreciate if someone looked over it and could give me some help.
<script>
var creditNum;
var valid = new Boolean(true);
creditNum = prompt("Enter your credit card number: ");
if((creditNum==null)||(creditNum=="")){
valid = false;
alert("Invalid Number!\nThere was no input.");
}else if(creditNum.length!=16){
valid = false;
alert("Invalid Number!\nThe number is the wrong length.");
}
//Luhn check
var c;
var digitOne;
var digitTwo;
var numSum;
for(i=0;i<16;i+2){
c = creditNum.slice(i,i+1);
if(c.length==2){
digitOne = c.slice(0,1);
digitTwo = c.slice(1,2);
numSum = numSum + (digitOne + digitTwo);
}else{
numSum = numSum + c;
}
}
if((numSum%10)!=0){
alert("Invalid Number!");
}else{
alert("Credit Card Accepted!");
}
</script>
The immediate problem in your code is your for loop. i+2 is not a proper third term. From the context, you're looking for i = i + 2, which you can write in shorthand as i += 2.
It seems your algorithm is "take the 16 digits, turn them into 8 pairs, add them together, and see if the sum is divisible by 10". If that's the case, you can massively simplify your loop - you never need to look at the tens' place, just the units' place.
Your loop could look like this and do the same thing:
for (i = 1; i < 16; i +=2) {
numSum += +creditNum[i];
}
Also, note that as long as you're dealing with a string, you don't need to slice anything at all - just use array notation to get each character.
I added a + in front of creditNum. One of the issues with javascript is that it will treat a string as a string, so if you have string "1" and string "3" and add them, you'll concatenate and get "13" instead of 4. The plus sign forces the string to be a number, so you'll get the right result.
The third term of the loop is the only blatant bug I see. I don't actually know the Luhn algorithm, so inferred the rest from the context of your code.
EDIT
Well, it would have helped if you had posted what the Luhn algorithm is. Chances are, if you can at least articulate it, you can help us help you code it.
Here's what you want.
// Luhn check
function luhnCheck(sixteenDigitString) {
var numSum = 0;
var value;
for (var i = 0; i < 16; ++i) {
if (i % 2 == 0) {
value = 2 * sixteenDigitString[i];
if (value >= 10) {
value = (Math.floor(value / 10) + value % 10);
}
} else {
value = +sixteenDigitString[i];
}
numSum += value;
}
return (numSum % 10 == 0);
}
alert(luhnCheck("4111111111111111"));
What this does is go through all the numbers, keeping the even indices as they are, but doubling the odd ones. If the doubling is more than nine, the values of the two digits are added together, as per the algorithm stated in wikipedia.
FIDDLE
Note: the number I tested with isn't my credit card number, but it's a well known number you can use that's known to pass a properly coded Luhn verification.
My below solution will work on AmEx also. I submitted it for a code test a while ago. Hope it helps :)
function validateCard(num){
var oddSum = 0;
var evenSum = 0;
var numToString = num.toString().split("");
for(var i = 0; i < numToString.length; i++){
if(i % 2 === 0){
if(numToString[i] * 2 >= 10){
evenSum += ((numToString[i] * 2) - 9 );
} else {
evenSum += numToString[i] * 2;
}
} else {
oddSum += parseInt(numToString[i]);
}
}
return (oddSum + evenSum) % 10 === 0;
}
console.log(validateCard(41111111111111111));
Enjoy - Mitch from https://spangle.com.au
#Spangle, when you're using even and odd here, you're already considering that index 0 is even? So you're doubling the digits at index 0, 2 and so on and not the second position, fourth and so on.. Is that intentional? It's returning inconsistent validations for some cards here compared with another algorithm I'm using. Try for example AmEx's 378282246310005.

Categories

Resources