randomly splice values into array - javascript

I have an array "A" of scrambled, randomly generated ASCII characters... and a message "M". I want to insert the characters of message M into array A such that the order of M's characters are intact... but randomly distributed throughout array A.
Original array: zH$#%#$##$#^^##(%*$#^&#!$^%&
Sample output: zH$#%#^t$##$#^^h##(%*$#^&#i!$^%&s, etc...
var randomChars = [];
for(var i=33;i<127;++i) {
var letter = document.createElement('span');
letter.innerHTML = String.fromCharCode(i);
randomChars.push(letter);
}
var message = "this is a message";
var rand = 0;
for (var i = 0; i < message.split("").length; i++) {
rand = Math.floor((Math.random() * randomChars.length) + rand);
var letters = document.createElement('span');
letters.innerHTML = message.split("")[i];
letters.setAttribute("hidden","");
randomChars.splice(rand, 0, letters);
}
Fiddle: https://jsfiddle.net/0ftm2srz/1/

Use the previous random index as the minimum (non inclusive) of your next randomly generated index. Start at zero.
You could end up with some barely scrambled stuff, though. (!##!$!#$#!##this) But it's random.
EDIT A better way would be to generate a message.length amount of unique random indices, sort them in ascending, and then insert characters from message at those spots in the scrambled array.
http://jsbin.com/kuzepujabo/1/edit?js,console

var o = {
array: "zH$#%#$##$#^^##(%*$#^&#!$^%&".split(''),
msg: "this is a message",
randomMsgIndex: function () { return Math.floor(Math.random() * this.msg.length); },
randomMsgChar: function () { return this.msg[this.randomMsgIndex()]; },
//resultingArray: [],
randomArrayIndex: function () { return Math.floor(Math.random() * this.array.length); }
}
for(var i = 0; i < o.msg.length; i++) {
o.array.splice(o.randomArrayIndex(), 0, o.randomMsgChar());
}
console.log(o.array);
I have come up with this - but I assume it is still not what you want - you probably want something that keeps track of which message chars were already added - so not to add them twice - and make sure the entire message (all its characters) were added to the array.
Version 2 with the feature described above:
var o = {
array: "zH$#%#$##$#^^##(%*$#^&#!$^%&".split(''),
msg: "this is a message",
msgArray: function () { this.msg.split(''); },
randomMsgIndex: function () { return Math.floor(Math.random() * this.msg.length); },
randomMsgChar: function (i) { return this.msg[i]; },
//resultingArray: [],
randomArrayIndex: function () { return Math.floor(Math.random() * this.array.length); },
stripStr: function (indexToSkip, originalStr) {
var result = "";
for (var i = 0; i < originalStr.length; i++)
if (indexToSkip != i)
result += originalStr[i];
return result;
}
}
for(var i = 0; i < o.msg.length; i++) {
var msgRandomIndex = o.randomMsgIndex();
o.array.splice(o.randomArrayIndex(), 0, o.randomMsgChar(msgRandomIndex));
o.msg = o.stripStr(msgRandomIndex, o.msg);
}
console.log(o.array);
I think it it is still not a 100%, but moving towards the "optimized" solution :-)

Related

In which way I can validate a random password?

I wrote a code to generate a random password, but in which way i can check that in the password there is a number, uppercase, lowercase and special characters?
function randomPassword(length) {
var chars = "abcdefghijklmnopqrstuvwxyz!##$%^&*1234567890ABCDEFGHIJKLMNOPQRSTUVWYZ";
var pass = "";
for (var x = 0; x < length; x++) {
var i = Math.floor(Math.random() * chars.length);
pass += chars.charAt(i);
}
return pass;
}
Why not loop over the different sets of characters. Then you don't have to check it at all:
function randomPassword(length) {
var chars = [
"abcdefghijklmnopqrstuvwxyz",
"!##$%^&*",
"1234567890",
"ABCDEFGHIJKLMNOPQRSTUVWYZ"
];
var pass = "";
while (pass.length < length) {
chars.forEach(set => {
if(pass.length < length) {
var i = Math.floor(Math.random() * set.length);
pass += set.charAt(i);
};
});
};
return pass;
};
Every iteration of the while loop will add one character from each of the sets. We check the pass.length the second time to make sure we aren't going over the limit when in the middle of a while loop. You should probably also make sure you return early if the length parameter is less than 4.
Maybe you can leave the password like it is, but to make sure you have the four required characters (number, uppercase, lowercase and special characters), you can later add one of each. These can also be chosen at random.
What you need is RegEx. Here are a few examples:
https://www.thepolyglotdeveloper.com/2015/05/use-regex-to-test-password-strength-in-javascript/
https://gist.github.com/leandromoh/470b0b54208f02a9ba223cdbdd1534bd
https://www.w3schools.com/howto/howto_js_password_validation.asp
You could generate passwords untill you get one that satisfies RegEx which would be the most random way:
function randomPassword(length) {
var chars = "abcdefghijklmnopqrstuvwxyz!##$%^&*1234567890ABCDEFGHIJKLMNOPQRSTUVWYZ";
var pass = "";
for (var x = 0; x < length; x++) {
var i = Math.floor(Math.random() * chars.length);
pass += chars.charAt(i);
}
return pass;
}
function randomStrongPassword(length) {
const strongRegex = new RegExp(`^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!##\$%\^&\*])(?=.{${length},})`)
let pass, valid
do {
pass = randomPassword(length)
valid = strongRegex.test(pass)
} while (valid !== true)
return pass
}
console.log(randomStrongPassword(8))
Or generate it like this and than randomize (I've added a test at end):
function randomPassword(length) {
const lower = 'abcdefghijklmnopqrstuvwxyz'
const upper = lower.toUpperCase()
const special ='!##$%^&*'
const numbers = '1234567890'
const characters = [lower, upper, special, numbers]
let pass = ""
for (var x = 0; x < length; x++) {
characters.forEach(e => {
const i = Math.floor(Math.random() * e.length)
pass += e.charAt(i)
})
}
const splice = Math.max(Math.floor(Math.random() * length) - length, 0)
return [...pass].splice(splice, length).sort(e => Math.random() - 0.5).join('')
}
console.log(randomPassword(10))
// Test password
const minLength = 8
const strongRegex = new RegExp(`^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!##\$%\^&\*])(?=.{${minLength},})`)
console.log(strongRegex.test(randomPassword(6)))
console.log(strongRegex.test(randomPassword(8)))

function that randomly sorts through letters and changes them not working

I am making a javascript function that will input a string, and output a "spongebob mocking text"
basically, you input "Hello, this is a message to the world" and you would get "HeLlO, ThIS iS a MeSsAGe tO tHE wORlD"
basically, randomly decide wheather to capitalize a letter or not. I made a function which i thought would do that, but it didn't work. here is the code that I tested in the js console:
function memify(input) { // function called memify()
var il = input.length; // gets the length of the input
var newinput = input; // creates a new variable that will be changed from input.
for (var i=0;i>il;i++) {
var rng = Math.floor((Math.random()*2)); // random number between 0 and 1. 0 = upper 1 = lower
if (rng === 0) {
newinput.charAt(i).toUpperCase();
}
else {
newinput.charAt(i).toLowerCase();
}
}
return newinput;
}
var text = prompt();
var textmeme = memify(text);
alert(textmeme);
Why is this not working? Do I have an error in my code? Any help will be greatly appreciated.
When you do
newinput.charAt(i).toUpperCase();
you're creating a new uppercase character, but you aren't doing anything with it; it's just an unused expression, so there's no visible change. Primitives (including strings) are immutable - you should explicitly reassign a string to something else (eg newString += newinput.charAt(i).toUpperCase();) to see an effect.
You also need to use
for (var i = 0; i < il; i++) {
// ^
instead of
for (var i = 0; i > il; i++) {
// ^
else, no iterations will run at all.
function memify(input) { // function called memify()
var il = input.length; // gets the length of the input
let changedStr = '';
for (var i = 0; i < il; i++) {
var rng = Math.floor((Math.random() * 2)); // random number between 0 and 1. 0 = upper 1 = lower
if (rng === 0) {
changedStr += input.charAt(i).toUpperCase();
} else {
changedStr += input.charAt(i).toLowerCase();
}
}
return changedStr;
}
var text = prompt();
var textmeme = memify(text);
console.log(textmeme);
Another option, using .map, which looks much cleaner IMO:
const memify = input => [...input]
.map(char => Math.random() < 0.5 ? char.toUpperCase() : char.toLowerCase())
.join('');
console.log(memify(prompt()));
Or more concise, safer and generally better solution :). It does not require for loop, checking length of string and other error prone stuff.
function memify(input) {
var rng = () => Math.random() > 0.5;
var res = input.split('').map( letter =>
rng() ? letter.toUpperCase() : letter.toLowerCase()
).join('');
return res;
}
var textmeme = memify("Hello World");
console.log(textmeme);
Please up-vote if it was helpful :)

Why `Loop` write more than once

I try to create a guessed with javascript and this is the code:
<script>
function makeid(len)
{
var text = "";
//var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var possible = "abc";
for( var i=0; i < len; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
////////////////////////////////////////////
var password = 'abc';
var correctGuess = false
var guess;
do {
document.write(makeid(3) + "<br>");
guess = makeid(3);
if (guess === password) {
correctGuess = true;
}
} while ( ! correctGuess )
document.write("You know the secret password. Welcome.");
</script>
But unfortunately the result is repeated more than once :
The result:
abb baa aac cba cbb aba bbb aac acb cba ccc bab caa bab ccc aac ccb
aba abc bac cbb
This slows down the program,, how disband this problem
Is there a solution?
thank you
Since you want to not check the same password twice, generating random guesses is obviously not the right way to go. As klumme mentioned, storing an array of previous guesses would only increase time and space complexity, so that is also out. What you will have to do is use a brute force method, that is, trying every combination of characters until you get the correct answer. Here's how you can implement it:
NOTE: Keep in mind that brute force algorithms are typically pretty inefficient, and if you use the full alphanumeric string that you have in your original code to brute force passwords of more than 3-4 characters, it will take a significant amount of time (especially in a browser). JavaScript, by nature, is not an extremely powerful number crunching language - so this answer is more for the idea of it, than for use in most real-world environments.
function guesser(len) {
var arr = Array.apply(null, Array(len));
var propIndex = -1;
var indexes = arr.reduce(function(total, curr) {
propIndex++;
total[propIndex] = 0;
return total;
}, {});
var lastGuess = arr.map(function() {
return possible[possible.length - 1];
}).join("");
var guess = "";
var found = false;
while (guess !== lastGuess) {
guess = "";
for (var i = 0; i < propIndex; i++) {
// if on last char, reset to 0 and increment previous index start position
if (indexes[propIndex - i] >= possible.length) {
indexes[propIndex - i - 1]++;
indexes[propIndex - i] = 0;
}
}
for (var i in indexes) {
guess += possible[indexes[i]];
}
document.write(guess + "<br/>");
if (guess === password) {
found = true;
break;
}
// increment last char
indexes[propIndex]++;
}
if (found) {
document.write("You know the secret password. Welcome.");
} else {
document.write("Sorry, you do not know the secret password.");
}
}
var password = 'dcd';
var possible = "abcd";
guesser(password.length);
If I understand you correctly, the problem is that the random password function ("makeid") may return the same password several times. This is no surprise, there's no reason for the function to know which passwords have been tried already. You could keep track of already tried passwords and not try one if it has been tried before (as in Kind user's answer), but in this case it probably wouldn't speed up the program.
A better approach would probably be to iterate through the possible passwords systematically instead of randomly. For example, try "aaa" first, then "aab", "aac" "aba" and so on.
Here is something I came up with -- it's probably not very fast. I use an array of indices into the "possible" string until actually trying the password, because I don't wan't to mess around with indexOf() on the way.
const correctPassword = 'abc';
const possible = 'abc';
const maxIndex = possible.length - 1;
function next(previous) {
var i = previous.length - 1;
while (previous[i] === maxIndex) {
previous[i] = 0;
i--;
// All passwords have been tried.
if (i < 0) {
return [];
}
}
previous[i]++;
return previous;
}
var current = Array(3).fill(0);
var currentPassword;
while (current.length != 0) {
currentPassword = current.map(function (i) {
return possible[i];
}).join('');
document.write(currentPassword + '<br>');
if (currentPassword === correctPassword) {
document.write('You know the secret password. Welcome.');
break;
}
current = next(current);
}
First of all, store the results inside an array. Secondly, add a following condition: if (arr.indexOf(guess) == -1) - if the guessed number is already in the array - skip it.
function makeid(len) {
var text = "";
//var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var possible = "abc";
for (var i = 0; i < len; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
var password = 'abc';
var correctGuess = false;
var guess;
var arr = [];
while (!correctGuess) {
guess = makeid(3);
if (arr.indexOf(guess) == -1) {
arr.push(guess)
if (guess === password) {
correctGuess = true;
}
}
}
console.log(arr);
I got interested in this question and decided to use it as an opportunity to learn more about generators. Note: Uses ES6 syntax, so not necessarily compatible with all platforms.
I wouldn't necessarily recommend this over the other approaches already put in place, but it might be a good future reference.
/**
* Invoke `callback` with every possible combination of `elements` up to length of `length`, until `callback` returns `true`
* #param elements an array of elements to be passed to `callback`
* #param length the maximum number of elements to pass to `callback`
* #param callback a function taking an array of elements, that returns a boolean
* #returns the first combination of elements for which `callback(combination)` returns `true`. Returns undefined if no combination up to the specified `length` returns `true`.
*/
const combineAndCall = (elements = [], length = 0, callback) => {
const it = permuteIterator(elements, length);
for (const el of it) {
if (callback(el)) {
return el;
}
}
};
/**
* Returns a generator that returns permutations, with repeated elements, of an array. The maximum length of each permutation is `len`
* #param arr the array to iterate. The first iteration will always be the empty array.
*
* Example:
* const it = permuteIterator([1,2,3], 2);
* it.next().value; // []
* it.next().value; // [1]
* it.next().value; // [2]
* it.next().value; // [3]
* it.next().value; // [1,1]
* it.next().value; // [1,2]
* it.next().value; // [1,3]
* it.next().value; // [2,1]
* it.next().value; // [2,2]
* ...
* it.next().value; // [3,3]
*
* #len the maximum length of each permutation
* #returns a generator that iterates the array
*/
function *permuteIterator(arr, len) {
let current = [];
function *helper(current, arr, len) {
if (current.length >= len) {
yield current;
} else {
for (const el of arr) {
yield* helper([...current, el], arr, len);
}
}
}
for (let i = 0; i <= len; i++) {
yield* helper([], arr, i);
}
}
/**
* Validates a password
* #param elements an array of strings (usually single characters) to combine into a a single string, and compare against the password
* #returns true if the string resulting from `elements.join("")` exactly equals the real password, false otherwise
*/
const passwordValidator = (elements) => {
const guess = elements.join("");
//console.log("validating:", guess);
return guess === "abc";
};
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
//const alphabet = "abc";
const elements = alphabet.split("");
const guessedPassword = combineAndCall(elements, 3, passwordValidator);
if (guessedPassword) {
console.log(`You know the secret password '${guessedPassword.join("")}'. Welcome.`);
} else {
console.log("You don't know the secret password. Rejected.");
}

How To Randomize Sentence Length From Array

There is probably a simple solution to this, but for some reason I can't seem to find it on the site, or elsewhere on the net. Just trying to produce a sentence of RANDOM LENGTH from an array. Here is an example:
var words = ["yes", "ok", "java", "pull my hair out", "sleep"];
Here is the code that I'm currently using to randomize the contents of the array, but it always produces a sentence where every string is used once. I want varying sentence lengths.
function fisherYates(words) {
var i = words.length, j, tempi, tempj;
if ( i == 0 ) return false;
while ( --i ) {
j = Math.floor( Math.random() * ( i + 1 ) );
tempi = words[i];
tempj = words[j];
words[i] = tempj;
words[j] = tempi;
}
return words;
}
Suggestions?
I would suggest you select a random number m from 1 to n inclusive (where n is the maximum length of the sentence you want). Then you randomly select m items from the array and put them into a new array:
var words = ["yes", "ok", "java", "pull my hair out", "sleep"];
alert(randomize(words, 10).join(" ") + ".");
function randomize(array, maximum) { // array, n
var length = Math.ceil(maximum * Math.random()); // m
var result = new Array(length);
var count = array.length;
var index = 0;
while (index < length) {
result[index++] = array[Math.floor(count * Math.random())];
}
return result;
}
Hope that helps.
Perhaps not.
If you don't want repeated strings, copy the array and splice random members from it to form the new collection. Just splice off a random number of strings from random positions.
function randWords(arr) {
// Copy original array
arr = arr.slice();
// Random number of words to get
var len = (Math.random() * arr.length + 1)|0;
var result = [];
// Randomly fill result from arr, don't repeat members
while (len--) {
result.push(arr.splice(Math.random()*arr.length|0, 1));
}
return result;
}
console.log( randWords(["yes", "ok", "java", "pull my hair out", "sleep"]).join(' ') );

How do I remove "undefined" from the beginning of JavaScript array items?

I'm trying to generate an array of random digits, but I'm getting "undefined" at the beginning of each row. I've been searching online for a couple of hours, but haven't been able to figure it out.
The expected output should be 5 rows of 2 random digits like this:
87
57
81
80
02
but the actual output looks like this:
undefined87
undefined57
undefined81
undefined80
undefined02
This is a modified excerpt that produces the result shown above:
function NumberSet() {
// generate all the digits
this.generate = function() {
random_digits = [];
// create 5 rows of 2 random digits
for(i=0; i<5; i++) {
for(z=0; z<2; z++) {
// use .toString() in order to concatenate digits to
// the array without adding them together
random_digit = Math.floor(Math.random()*10).toString();
random_digits[i] +=random_digit;
}
}
return random_digits;
}
}
randomnumbers1 = new NumberSet();
mynums = randomnumbers1.generate();
jQuery.each(mynums, function(i, l) {
// display output in a div#nums
$('#nums').append(l + '<br>');
});
The final version won't be using this method to display the digits. I'm just trying to troubleshoot where the "undefined" is coming from.
Initialize your variables
random_digits[i] = "";
for(z=0; z<2; z++) {
random_digit = Math.floor(Math.random()*10).toString();
random_digits[i] +=random_digit;
}
Declare the variables properly with var.
var random_digit, random_digits = [];
Declare random_digit in the first for loop and assign an empty string.
Go through the inner for loop appending your random numbers, and then push() to the array back in the outer for loop.
function NumberSet() {
// generate all the digits -a meme should be attached here-
this.generate = function() {
random_digits = [];
// create 5 rows of 2 random digits
for(i=0; i<5; i++) {
var random_digit = ""; //Declare it out here
for(z=0; z<2; z++) {
// use .toString() in order to concatenate digits to
// the array without adding them together
random_digit += Math.floor(Math.random()*10).toString(); //Append it here
}
random_digits.push(random_digit); //Push it back here
}
return random_digits;
}
}
Fiddle-dee-dee
OR Forget the inner loop and use recursion
function NumberSet() {
// generate all the digits
this.generate = function () {
random_digits = [];
// create 5 rows of 2 random digits
// Use i for how many numbers you want returned!
var random_digit = function (i) {
var getRand = function() {
return (Math.floor(Math.random() * 10).toString());
}
return (i > 0) ? getRand()+random_digit(i-1) : "";
};
for (i = 0; i < 5; i++) {
random_digits.push(random_digit(2)); //In this case, you want 2 numbers
}
return random_digits;
}
}
Fiddle-do-do
And the final version because I'm bored
function NumberSet(elNum, numLen) {
this.random_digits = []; //Random digits array
this.elNum = elNum; //Number of elements to add to the array
this.numLen = numLen; //Length of each element in the array
// generate all the digits
this.generate = function () {
// create 5 rows of 2 random digits
var random_digit = function (i) {
var getRand = function () {
return (Math.floor(Math.random() * 10).toString());
}
return (i > 0) ? getRand() + random_digit(i - 1) : "";
};
for (i = 0; i < this.elNum; i++) {
this.random_digits.push(random_digit(this.numLen));
}
return this.random_digits;
}
}
randomnumbers1 = new NumberSet(5, 2).generate();
jQuery.each(randomnumbers1, function (i, l) {
// display output in a div#nums
$('#nums').append(l + '<br>');
});
Fiddle on the roof
Replace
random_digits[i] +=random_digit;
With
random_digits[i] = (random_digits[i] == undefined ? '' : random_digits[i]) + random_digit;
Demo: Fiddle
Your function can be simplified to:
function NumberSet() {
this.generate = function() {
var random_digits = new Array();
for (i = 0; i < 5; i++) {
randnum = Math.floor(Math.random() * 99);
random_digits[i] = (randnum < 10 ? '0' : 0) + randnum;
}
return random_digits;
}
}
Live Demo

Categories