JS convert to ASCII numbers and reverse - javascript

I stuck on this can you help in JavaScript Alien message
Allowed languages
JavaScript
Your task is to translate a message in some alien language (let's call it Alienski).
The message could be created by following simple rules and from two known languages, English and Spanish.
Each word in Alienski is constructed by subtracting the letters from English and Spanish (absolute value) and that is the resulting letter.
There are two special cases. If in each of the words the symbol is '-' (hyphen) or ' ' (space) it is mandatory for it to be kept this way.
There won't be a case with a '-' (hyphen) and a ' ' (space) at the same time.
If one of the words is with more letters than the other just add the letters from the longer word to the result.
Example:
Copy
talk
hablar
Copy
a b c d....
0 1 2 3....
t - h = | 19 - 7 | = 12 = m
a - a = | 0 - 0 | = 0 = a
l - b = | 11 - 1 | = 10 = k
k - l = | 10 - 11 | = 1 = b
empty - a = a
empty - r = r
Result:
makbar
I stuck from 3 hours on this. Here is my code so far
let englishWord = 'talk'
let spanishWord = 'hablar'
let engToDigit = [];
let spnToDigit = [];
let alien = [];
for (var i = 0; i < englishWord.length; i++) {
engToDigit.push(englishWord.charCodeAt(i))
}
for (var y = 0; y < spanishWord.length; y++) {
spnToDigit.push(spanishWord.charCodeAt(y))
}
let result = engToDigit.map((a, i) => a - spnToDigit[i]);
for (let index = 0; index < result.length; index++) {
result[index] += 97;
console.log(result);

What it sounds like you need is to take this in small steps. First I would make a function that iterates through a string and converts each letter to its ASCII code. Try the following order:
Check if code is uppercase then get the numeric value.
Make sure charCode is greather than 96 and charCode is less than 123
Then turn all the codes to their numeric value by running and
collecting in an array: charCode - 97
Else check if the code is lower case then get the numeric value.
Make sure that charCode is greater than 64 and charCode is less than 91.
Then turn all the codes to their numeric value by running and collecting in an array: charCode - 65
Else just add the value to the array.
Outside the above loop return an array that is joined.
When the array is joined it will be a string like "19,0,11,10,-,7,0,1,11,0,17".
Check if there is a space or a hyphen.
Then you can split the array on the result of step 9.
Then split each array on ",".
Loop through each array and subtract the values.
Convert the values back by adding 65 - because there is no way at this point to know if a character was upper case.
Then use String.fromCharCode(##) to convert the code back to the non-readable alien word.

Related

Deciding key-value pairs for Roman Numeral Converter

Every solution I've found uses the following object.
function converter(num) {
var romanKeys =
{M:1000,CM:900,D:500,CD:400,C:100,XC:90,L:50,XL:40,X:10,IX:9,V:5,IV:4,I:1}
When attempting the problem myself, I wasn't too sure which roman numerals were redundant when constructing the object. Procedurally, how do we arrive to this object? e.g How do I know that
"VI: 6" is unnecessary but "IV: 4" is?
When a symbol appears after a larger (or equal) symbol it is added
Example: VI = V + I = 5 + 1 = 6
Example: LXX = L + X + X = 50 + 10 + 10 = 70
But if the symbol appears before a larger symbol it is subtracted
Example: IV = V − I = 5 − 1 = 4
Example: IX = X − I = 10 − 1 = 9
I can be placed before V (5) and X (10) to make 4 and 9.
X can be placed before L (50) and C (100) to make 40 and 90.
C can be placed before D (500) and M (1000) to make 400 and 900.
When you are scanning a roman number you are looking from left to right at each symbol and if it appears before a larger symbol, you take them together, do the substraction and add it to the result, then move to the symbol after them. Otherwise you take a single symbol and add its value to the result and move to the next symbol.
For example for XIV:
1) result = 0
2) X < I => result += 10 (result = 10)
3) I < V => result += (5-1) (result = 14)
Note that if you are using that mapping, you only need the combinations where the second symbol is greater than the first one for which the substraction rule applies, as noted above (CM, CD, XC, XL, IX, IV).
Having something like XI in that mapping would give you a wrong result. For XIV you will have XI (11) + V (5) = 16, not X (10) + IV (4) = 14.

Can't convert string into number

I have a large text from which I read data according to the scheme. Key words are placed in the "smallArtName" array. The scheme looks like this:
(key word) xxx (cordX|cordY)
I can't convert the string I received to a number. It seems to me that the reason is white space, visible in the terminal in the picture. I tried to use the replace method which works for sample text, but not for my value.
I'm a beginner and I could probably do it simpler, but the code I wrote works, and this is the most important thing for now.
for (i = 0; i < smallArtName.length; i++) {
var n = art.artPrintScreen.indexOf(smallArtName[i]);
if (n > -1) {
var tempString = art.artPrintScreen.substring(n, n + 100);
betweenChar = tempString.indexOf('|');
for (k = betweenChar - 10; k <= betweenChar + 10; k++) {
if (tempString[k] == '(') {
xStart = k;
}
if (tempString[k] == ')') {
yEnd = k;
}
}
cordX = tempString.slice(xStart + 1, betweenChar);
cordY = tempString.slice(betweenChar + 1, yEnd);
strTest = " t est".replace(/\s/g, '')
var cordY2 = cordY.replace(/\s/g, '')
console.log(typeof (cordY))
console.log(cordY2)
console.log(cordY2[0])
console.log(cordY2[1])
console.log(cordY2[2])
console.log(cordY2[3])
console.log(cordY2[4])
console.log(cordY2[5])
console.log(strTest)
var cordYtest = parseInt(cordY2, 10);
console.log(cordYtest)
}
}
Terminal:
-181
-
1
8
1
test
NaN
string
-154
-
1
5
4
test
NaN
string
104
1
0
4
undefined
test
NaN
Fragment of input text:
Ukryta twierdza (Mapa podziemi I) 153 ‭(‭−‭72‬‬|‭−‭155‬‬)‬
Ukryta twierdza (Amfora Mgły VI) 135 ‭(‭73‬|‭104‬)‬
Ukryta twierdza (Mapa podziemi IV) 131 ‭(‭154‬|‭−‭72‬‬)‬
Analysing your sample input strings, I found some unicode characters \u202c and \u202d that should be stripped before converting to number. Also, the negative values are prefixed by the character −, which is different than minus -, se we need to replace it. That being said, all parsing could be done with a single regex:
var input = "Ukryta twierdza (Mapa podziemi I) 153 ‭(‭−‭72‬‬|‭−‭155‬‬)‬";
input = input.replace(/\u202d|\u202c/g, "");
input = input.replace(/−/g, "-");
var m = input.match(/.*\((.*)\)\s*(.+?)\s*\((.+)\|(.+)\)/);
console.log(m);
console.log(parseInt(m[3]));
console.log(parseInt(m[4]));
Explaining the regex:
.* - Something that will be ignored
\((.*)\) - Something enclosed in parenthesis
\s*(.+?)\s* - Something possibly surrounded by spaces
\((.+)\|(.+)\) - Two parts split by a | and enclosed by parenthesis

Combinations of a string double loop (JavaScript)

I'm trying to understand how to find all the combinations of a string using a double loop but the solution I've come across is too complicated for my understanding. The function does what I need but I have beginner understanding of setting up a single or double for loop.
I'm hoping for a general step by step explanation of what is going on but for specific questions: what functions are "i < Math.pow(2,n)-1", "((i & (1 << j)) == 1 << j)", and "var comb = ''; (temporary storage?)" serving?
subsets = function(str) {
var n = str.length;
for (var i=1; i< Math.pow(2,n)-1; i++) {
var comb = '';
for (var j=0; j<n; j++) {
var use = ((i & (1 << j)) == 1 << j);
if(use)comb+=str.charAt(j);
}
console.log(comb);
}
}
subsets("age");
Output: a ag ae g ge e
To get a random combination of the string, we could set up a boolean array, storing if one of the characters should be displayed or not, e.g:
"a","g","e"
[true,false,true]
=>"ae"
So the number of possible variations is
2 /*true/false*/ ** str.length
written in old style:
Math.pow(2,str.length)
So the main for loop iterates over all possible combinatons except the first one (as i starts with 1),as that would be an empty string and the last one (-1) that would be "age". While i is an integer which simply counts up, we could also imagine that its a boolean array (in a bitwise view):
integer
bits
boolean array
1
001
[false,false,true]
2
010
[false,true,false]
3
011
[false,true,true]
4
100
[true,false,false]
...
6 < 2 ** 3 -1
110
[true,true,false]
Now the inner loop:
for (var j=0; j<n; j++) {
var use = ((i & (1 << j)) == 1 << j);
if(use)comb+=str.charAt(j);
}
Just goes over our letters and checks if the boolean flag is true, so at i = 5 the boolean array would be:
[true,false,true]//101
and that is converted to
"ae"
How it looks bitwise:
A true one ("a"):
101 // i
&001 //1<<j where j is 0
=001
===
001 //1<<j
A false one ("g"):
101
&010 //1<<j where j is 1
=000
!==
010 //1<<j
A true one ("e"):
101 // i
&100 //1<<j where j is 2
=100
===
100 //1<<j
So it checks if the boolean array (i) is true at js index, if so it adds that letter. BTW shorter:
if(i & (1<<j))
var i=1; i< Math.pow(2,n)-1; i++
What the Math.pow(2, n) - 1 is saying is run this loop until (2^n)-1, where 'n' is the length of the string. So with the input 'age', the first for loop will run while i, starting at 1 and incrementing by 1 each loop, is less than (2^3)-1. Therefore, this first loop will run 6 times.
var comb = ''
Is exactly what you think it is - storage for what to log that populates as the for loops do their thing!
As for (i & (1 << j)) == 1 << j), that's where we get into Bitwise operators! Unfortunately, I don't understand these nearly well enough to explain them :(
Math.pow is a power function. The first argument is the base, and the second argument is the exponent, so Math.pow(2, n) is equivalent to 2^n. In the loop, i< Math.pow(2,n) means the boundary of the for loop is while i is less than 2^n, where n is the string length.
var comb = ''; is initializing an empty string. This string is concatenated later in the loop so this declaration serves to establish that variable for concatenation.
It's a code based on binary (0/1)
operators in javascript explain << it's a "Shift a into binary representation of b bits to the left, by inserting zeros by the right"
and & : Returns a 1 for each bit position for which the corresponding bits of the two operands are 1.
If u had some problem to undestand a code, Try it on paper step by step with simple example.
Try example str = "a", after try "on" ...
For "a" the beginning is
var n = str.length; // 1
for (var i=1; i< Math.pow(2,n)-1; i++) { // for i=1;i<2^1-1 =2-1=1;i++
var comb = '';
for (var j=0; j<n; j++) {//for j=0;j<1;j++
var use = ((i & (1 << j)) == 1 << j);// use = 1 & (1 << 0 insert 0 times 0)) == 1 << 0= (1 & 1)== 1=true (1==1)
if(use)comb+=str.charAt(j);//comb='' + a.charAt(0)= comb= '' + "a"='a'
... You continue the loops.
binary is a method to write number with 0/1 :
Example 00101(binary)
U have 5 digits then the 1rst 0 = 0*2^(number of place of digit from right-1) = 0*2^4=0
Then 00101(binary) = 0*2^4 + 0*2^3 + 1*2^2 + 0*2^1 + 1*2^0
= 0 + 0 + 1*4 + 0 + 1*1
= 5 in current using (decimal)
U find lot of explanation on binary with Google

create all possible variations of a string with inserted character

I'm trying to take the variable email and create all possible combinations with a "." in it like so:
Results
andrew
andre.w
andr.ew
andr.e.w
and.rew
and.re.w
and.r.ew
and.r.e.w
an.drew
an.dre.w
an.dr.ew
an.dr.e.w
an.d.rew
an.d.re.w
an.d.r.ew
an.d.r.e.w
a.ndrew
a.ndre.w
a.ndr.ew
a.ndr.e.w
a.nd.rew
a.nd.re.w
a.nd.r.ew
a.nd.r.e.w
a.n.drew
a.n.dre.w
a.n.dr.ew
a.n.dr.e.w
a.n.d.rew
a.n.d.re.w
a.n.d.r.ew
a.n.d.r.e.w
I'm not sure how to do about doing this exactly. I know how to use a loop to go over each character, but as far as the rest goes I'm stumped. I was looking at substr, slice and few other functions but couldn't get anything working.
Code
var email = "andrew";
for (var i = 0; i < email.length; i++) {
console.log( email[i] + "." );
}
That's easy:
var str = 'andrew';
var results = [],
bin;
for (var i = 0; i < Math.pow(2, str.length - 1); ++i) {
bin = i.toString(2).split('').reverse().join('');
results.push(str.replace(/./g, function(letter, index) {
if (bin.charAt(index) == 1) {
letter += '.';
}
return letter;
}));
}
console.log(results);
Demo: http://jsfiddle.net/9qLY6/
Short description:
For 'abc' string there are 2 positions for a dot character: between a and b; b and c. These 2 positions might be presented as a digits of a binary number. All the possible combinations in this case are:
00
01
10
11
If you treat 1 as - . there, and 0 as no . there - you can just iterate over 2^(n-1) numbers and put . if the corresponding bit is set.
If you're interested in a recursive solution like Dinesh mentioned, here's some code to get you started.
function withPeriods(str, prev) {
prev = prev || '';
if(!str || str.length == 0) {
return prev ? [prev] : [];
} else if(str.length == 1) {
return [prev + str];
} else {
var c = str.charAt(0);
var newStr = str.slice(1);
return withPeriods(newStr, prev+c).concat(withPeriods(newStr, prev+c+'.'));
}
}
The idea here is that you are working your way through the string, keeping the current result in the 'prev' variable. If the string is length 0 or 1, there's nothing left to do. Otherwise, you need consider two options: one where you take a character from 'str' and add it to 'prev', and one where you do that but also add a '.'
If you think about it, you need to either insert a dot, or not insert one, at every possible location in the string (between any two characters). A funky way to do this is to realize that if you have n characters, there are n-1 places. If you wrote the combinations of period = 1 and no period = 0, then you can write all possible solutions as a 2^n-1 binary sequence. Showing this for a four letter word "word":
000 word
001 wor.d
010 wo.rd
011 wo.r.d
100 w.ord
101 w.or.d
110 w.o.rd
111 w.o.r.d
In pseudo code (can't test JS syntax right now):
n = strlen( email );
combinations = 1 << n - 1; // left shift operation
for i = 0 to combinations - 1:
dot = 1
for j = 0 to n:
print email[j];
if dot & i:
print '.'
dot << 1;
Can you take it from here?
You might take a recursive approach to this problem. Maybe you can use the base case as a string with 2 characters.

Writing a function in javascript that is the inverse of another

I'm trying to write a function that is the inverse of the function below.
So that I can get the output from the function foo and generate it's input parameter.
I'm not entirely sure if it's possible.
function foo(str){
var hexMap = {
"0":0,
"1":1,
"2":2,
"3":3,
"4":4,
"5":5,
"6":6,
"7":7,
"8":8,
"9":9,
"A":10,
"B":11,
"C":12,
"D":13,
"E":14,
"F":15
};
var charList = [];
str = str.toUpperCase();
for (var i = 0; i < str.length; i += 2) {
charList.push(hexMap[str.charAt(i)] * 16 + hexMap[str.charAt(i + 1)]);
}
charList.splice(0, 8);
charList.splice(0, 123);
var sliceEnd = charList[0] + charList[1] * 256;
charList.splice(0, 4);
charList = charList.slice(0, sliceEnd);
return charList;
}
Your function takes in a string that is hopefully a hexadecimal string using only the characters [0-9a-fA-F]. Then it makes an array where every two hex characters are converted to a decimal integer between 0 and 255. Then the function immediately throws away the first 131 elements from this array. This means that the first 262 characters on your string have no impact on the output of the function (The first 262 characters can be any characters).
Then there is this line:
var sliceEnd = charList[0] + charList[1] * 256;
sliceEnd becomes a number between 0 and 65535 (the maximum size of the resulting array). Based on the characters at indices 262 - 265 in the input string. (Two two digit hex values converted to two integers. The value at position 264 is multiplied by 256 and added to the value at position 262).
Then the resulting array contains the integers converted using the same method from the characters from position 270 to 270 + sliceEnd*2.
MSN is correct that this function is not 1 to 1 and therefore not mathematically invertible, but you can write a function which given an array of less than 65536 integers between 0 and 255 can generate an input string for foo which will give back that array. Specifically the following function will do just that:
function bar(arr){
var sliceEnd = arr.length;
var temp = '00' + (sliceEnd & 255).toString(16);
var first = temp.substring(temp.length - 2);
temp = '00' + Math.floor(sliceEnd/256).toString(16);
var second = temp.substring(temp.length - 2);
var str = '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + first + second + '0000';
for(var i = 0; i < arr.length; i++){
temp = '00' + arr[i].toString(16);
str += temp.substring(temp.length - 2);
}
return str;
}
This gives you the property that foo(bar(x)) === x (if x is an array of less than 65536 integers between 0 and 255 as stated previously), but not the property bar(foo(x)) === x because as MSN pointed out that property is impossible to achieve for your function.
EG. bar([17,125,12,11]) gives the string:
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000117dcb" which if you give as input to your function foo you get back the original array: [17,125,12,11], but there are many other inputs (at least 268 of those 0's can be any other of the values in [0-9a-fA-F], and the 04 can be anything greater than 04 which means 22^268*(255 - 4) different strings multiplied by a bit more since that only takes into account either lower case or capitals but not both when multiplying by 255 - 4. regardless 22^268 is a ridiculous number of inputs for one output anyways, and that's ignoring the fact that their are an infinite amount of strings which begin with the string above and have any other hexadecimal string appended to them which will give the same output from foo because of the sliceEnd variable.
That function is not a 1 to 1 function, i.e., many inputs will generate the same output.

Categories