Is there a way to exclude already used characters from an array? - javascript

New to programming here, and I am just about to finish my first project-a password generator. I am trying to keep it as simple as possible, nothing fancy, yet I have come to a standstill. I want to implement an option that allows the user to only get one character to appear only once in the generated password. As of now, it is just a random jumble of characters, repeating and whatnot, so I was wondering if there is any way to implement such a feature-and if so, how? If statements? loops? I am up for all suggestions!
Here is the code.
var keys = {
upperCase : ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"],
lowerCase: ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","z"],
number: ["0","1","2","3","5","6","7","8","9"],
symbol: ["!","#","#","$","%","^","&","*","(",")","_","+","~","|","}","{","[","]",":",";","?",">","<",",",".","/","-","="]
}
var getKey = [
function upperCase() {
return keys.upperCase[Math.floor(Math.random() * keys.upperCase.length)];
},
function lowerCase() {
return keys.lowerCase[Math.floor(Math.random() * keys.lowerCase.length)];
},
function number() {
return keys.number[Math.floor(Math.random() * keys.number.length)];
},
function symbol() {
return keys.symbol[Math.floor(Math.random() * keys.symbol.length)];
}
];
function createPassword() {
var upper = document.getElementById("upperCase").checked;
var lower = document.getElementById("lowerCase").checked;
var number = document.getElementById("number").checked;
var symbol = document.getElementById("symbol").checked;
if (upper + lower + number + symbol === 0) {
alert("Please check a box!");
return;
}
var passwordBox = document.getElementById("passwordBox");
var length = document.getElementById("length");
var password = "";
while (length.value > password.length) {
var keyToAdd = getKey[Math.floor(Math.random() * getKey.length)];
var isChecked = document.getElementById(keyToAdd.name).checked;
if (isChecked) {
password += keyToAdd();
}
}
passwordBox.innerHTML = password;
}
Link to codepen (with all HTML, JavaScript and CSS) is available here.

#Embla I think this is what you are trying to achieve, let me know if smthg is missing in this solution. You didnt provide HTML, I just assumed what it might look like
let passwordBox = document.getElementById("passwordBox");
let length = document.getElementById("length");
const keys = {
upperCase : ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"],
lowerCase: ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","z"],
number: ["0","1","2","3","5","6","7","8","9"],
symbol: ["!","#","#","$","%","^","&","*","(",")","_","+","~","|","}","{","[","]",":",";","?",">","<",",",".","/","-","="]
}
function random( max, min=0){
return ~~(Math.random() * (max - min) + min)
}
function getKey(objArr){
const values = Object.values(objArr);
const randValue = values[random(values.length)];
return randValue[random(randValue.length)];
}
function createPassWord(passwordLength){
const pwdStorage = new Set();
while( pwdStorage.size < passwordLength ){
pwdStorage.add(getKey(keys))
}
return [...pwdStorage].join('');
}
length.addEventListener('change', (event)=>{
passwordBox.textContent = createPassWord(+length.value)
})
input[type="number"]{
width: 150px;
height: 30px;
border: 2px solid grey;
border-radius: 5px;
padding-left:10px;
font-size: 18px;
}
<div class="password-Container">
<h2 id="passwordBox">Password</h2>
</div>
<input type="number" name="" id="length" min="1" max="100" step="1" placeholder="Enter number">

I writed a function for your request, i hope that works for you.
Array.prototype.getAndRemove = function (index) {
const item = this[index];
if (this.indexOf(item) > -1) {
this = this.splice(this.indexOf(item), 1);
if (this.indexOf(item) > -1) {
this = this.splice(this.indexOf(item), 1);
}
}
return item;
}

Related

I am trying to evaluate if the input is an empty string or not a number in JavaScript

I am trying to evaluate when the user inputs nothing (an empty string) or anything besides a number (Not a number). After I console log the an input of empty string a NaN is returned. I am not sure why the else-if statement is never recognized if I test for both an empty string or NaN value. This also ultimately affects my average total score.
const equationTag = document.querySelector('div#equation');
const inputBtn = document.querySelector('input.submit-btn');
const incorrectTag = document.querySelector('p#incorrect');
const correctTag = document.querySelector('p#correct');
const counterTag = document.querySelector('div#counter');
const exitButton = document.querySelector('button.exit-btn');
const displayButton = document.querySelector('button.display-btn');
const resultModal = document.querySelector('section.stats-section');
const averageP = document.querySelector('p.avg');
const guessP = document.querySelector('p.total-guesses');
let points = 0;
let correctGuesses = 0;
let incorrectGuess = 0;
let totalGuesses = 0;
/*
Takes a min and max value as parameters, and
returns a randomized integer
*/
function getRandomValue(min, max) {
let r = Math.floor(Math.random() * (max - min + 1)) + min;
return r;
}
// Displays multiplcation equation on the user interface
function displayEquation() {
equationTag.textContent = `${integerOne} x ${integerTwo}=`;
}
// Returns the product of the two integers
function getProduct() {
return integerOne * integerTwo;
}
/*
Event listener grabs user input on click
and clears user input afterwards
*/
inputBtn.addEventListener('click', () => {
const inputTag = document.querySelector('#num');
const answer = parseFloat(inputTag.value);
evaluateAnswer(answer);
inputTag.value = "";
inputTag.focus();
})
/*
Event listener grabs user input on enter key
and clears user input afterwards
*/
document.addEventListener("keydown", (event) => {
if (event.key === "Enter") {
const inputTag = document.querySelector('#num');
const answer = parseFloat(inputTag.value);
evaluateAnswer(answer);
inputTag.value = "";
inputTag.focus();
}
})
exitButton.addEventListener('click', () => {
setDisplayNone(resultModal);
})
displayButton.addEventListener('click', () => {
setDisplayBlock(resultModal);
})
/*
Takes a integer user input as an argument
and compares whether the answer is correct or not.
*/
function evaluateAnswer(input) {
console.log('Input value on eval ', input); // double checking value
if (input !== getProduct()) {
subtractPoint();
incorrectGuess++;
} else if (input === ' ' || isNaN()) { // I am not sure why it's never evaluated
console.log('Input value is empty or not a number ', input);
} else {
addPoint();
correctGuesses++;
}
totalGuesses++;
restartGame();
guessP.textContent = "Incorrect Guesses= " + incorrectGuess;
let average = (correctGuesses / totalGuesses);
let precisionAvg = roundToPrecision(average, 2);
averageP.textContent = `${(precisionAvg * 100).toFixed(2)}%`;
// console.log('Total guesses: ', totalGuesses);
// console.log('Incorrect ', incorrectGuess);
// console.log("Average: ", average)
}
/*
Evaluates if the points are less
than zero then restart points to 0
else minus a point.
*/
function subtractPoint() {
if (points <= 0) {
points = 0;
} else {
points -= 1;
}
setDisplayBlock(incorrectTag);
setDisplayNone(correctTag);
incorrectTag.textContent = ('Incorrect: ' + integerOne + ' x ' + integerTwo + ' = ' + getProduct());
setPoint();
}
// Sets new updated point
function setPoint() {
counterTag.textContent = points;
}
// Adds a point and updates earned points
function addPoint() {
points += 1;
correctTag.textContent = ('Correct!');
setDisplayBlock(correctTag);
setDisplayNone(incorrectTag);
setPoint();
}
/*
Resets game and gets two new random integers
and calls the displayEquation function.
*/
function restartGame() {
integerOne = getRandomValue(0, 12);
integerTwo = getRandomValue(0, 12);
displayEquation();
}
// sets css display block and opacity 1 on element
function setDisplayBlock(displayResult) {
displayResult.style.display = 'block';
displayResult.style.opacity = 1;
}
// sets css display none and opacity 0 on element
function setDisplayNone(displayResult) {
displayResult.style.display = 'none';
displayResult.style.opacity = 0;
}
/*
Takes a value as a parameter, and integer as a parameter
returns a rounded value with two decimal places at most
https://stackoverflow.com/questions/11832914/how-to-round-to-at-most-2-decimal-places-if-necessary/11832950#11832950
*/
function roundToPrecision(value, decimals = 2) {
const pow = Math.pow(10, decimals);
return Math.round((value + Number.EPSILON) * pow) / pow;
}
// run game on load
let integerOne = getRandomValue(0, 12);
let integerTwo = getRandomValue(0, 12);
displayEquation();
<body>
<header>
<h1 id="title">Multiply Me</h1>
</header>
<main>
<div id="equation"></div>
<div id="counter">0</div>
<input type="number" id="num" value="" title="input">
<input type="submit" class="submit-btn">
<button type="submit" class="display-btn" value="Show Results">+</button>
<div id="response">
<p id="correct"></p>
<p id="incorrect"></p>
</div>
<section class="stats-section">
<h3 class="h3-title">Overall Results:</h3>
<button class="exit-btn">x</button>
<article class="article-stats">
<p class="total-guesses"></p>
<p class="avg"></p>
</article>
</section>
</main>
</body>
Several issues apart from not using isNaN correctly
You cannot see if a value is a single space after parseFloating it.
I would suggest
const answer = inputTag.value;
evaluateAnswer(answer);
where you have this. Note the order and that I test the positive outcome before the negative
function evaluateAnswer(input) {
input = input.trim();
if (input === "" || isNaN(input)) {
console.log('Input value is empty or not a number ', input);
return; /* Any need to continue? */
} else if (input === getProduct()) {
addPoint();
correctGuesses++;
} else {
subtractPoint();
incorrectGuess++;
}
You must first check that the input value is not empty, so you must modify the order of the condition. And it is better to add a return to exit the function when no value is entered so that a new question is not generated.
function evaluateAnswer(input) {
console.log('Input value on eval ', input); // double checking value
if (input === '' || isNaN(input)) { // I am not sure why it's never evaluated
console.log('Input value is empty or not a number ', input);
return;
} else if (input !== getProduct()) {
subtractPoint();
incorrectGuess++;
} else{
addPoint();
correctGuesses++;
}
totalGuesses++;
restartGame();
guessP.textContent = "Incorrect Guesses= " + incorrectGuess;
let average = (correctGuesses / totalGuesses);
let precisionAvg = roundToPrecision(average, 2);
averageP.textContent = `${(precisionAvg * 100).toFixed(2)}%`;
}

jQuery number format for HTML input number with dynamic decimals

I've seen a lot of similar threads or library but I haven't found one I need.
I have preexisting code with many input[type=number] in the forms. I need to format the number value to local format when form is viewed at first load or when cursor/pointer is out of focus (onblur), and unformat the number to raw input when onfocus or when the form is submitted. The format are dot as separator and comma as decimal. The decimal numbers are dynamic, some don't have decimals, some have 2 or 4, or in other words, the decimal format is only shown when the number has decimal. And when a field doesn't have any value, still displays an empty string ("") not zero (0). A field that has 0 value still displays a 0.
Example:
//Number is 1400.45
//Document ready: 1.400,45
//Onfocus: 1400.45
//Onblur: 1.400,45
//Onsubmit value send by PHP page load: 1400.45
Is there any way to do this or jQuery/javascript library for this?
I don't think there is a library for such a specialized solution you are looking for but you can do it on your own.
That's the idea:
String.prototype.replaceLast = function(find, replace) {
var index = this.lastIndexOf(find);
if (index >= 0) {
return this.substring(0, index) + replace + this.substring(index + find.length);
}
return this.toString();
};
let transformValue = function(value) {
value = parseFloat(value);
value = parseInt(value).toLocaleString() + '.' + parseInt(value.toString().split('.')[1] || '0');
value = value.replace(',', '.');
value = value.replaceLast('.', ',');
return value;
};
let form = document.querySelector('#myForm');
window.addEventListener('load', function() {
let inputs = form.querySelectorAll('input[type="text"]');
for (let i = 0; i < inputs.length; i++) {
let input = inputs[i];
input.value = transformValue(input.value);
input.onfocus = function() {
this.value = this.value.replaceAll('.', '').replace(',', '.');
};
input.onblur = function() {
this.value = transformValue(this.value);
};
}
});
form.onsubmit = function() {
let inputs = form.querySelectorAll('input[type="text"]');
for (let i = 0; i < inputs.length; i++) {
inputs[i].value = inputs[i].value.replaceAll('.', '').replace(',', '.'); }
for (let i = 0; i < inputs.length; i++) {
alert('submitted value ' + inputs[i].value);
}
};
#myForm {
display: flex;
flex-direction: column;
}
#myForm input {
outline: none;
border: 1px solid #000;
border-radius: 3px;
margin: 5px 0;
padding: 3px 7px;
}
<form id="myForm">
<input type="text" value="1400.45">
<input type="text" value="1401.45">
<input type="text" value="1402.45">
<input type="submit">
</form>
The below solution is totally dynamic, as wherever you want to put decimal position.
var num;
$(document).ready(function(){
num=$(".nums").val();
var nstring=num.replace(/\D/g,'');
var total_strings=nstring.length;
totalz=pad("1", (total_strings));
var nums=eval(nstring/totalz);
nums=""+nums+"";
var new_array=nums.split(".");
var val_1=addCommas(new_array[1]);
var narray=new_array[0]+"."+val_1;
$(".nums").val(narray);
});
$(".nums").focus(function(){
var numz=num;
$(".nums").val(numz);
});
$(".nums").blur(function(){
num=$(".nums").val();
var nstring=num.replace(/\D/g,'');
var total_strings=nstring.length;
totalz=pad("1", (total_strings));
var nums=eval(nstring/totalz);
nums=""+nums+"";
var new_array=nums.split(".");
var val_1=addCommas(new_array[1]);
var narray=new_array[0]+"."+val_1;
$(".nums").val(narray);
});
$(".nums").focus(function(){
var numz=num;
$(".nums").val(numz);
});
$(".form1").submit(function(){
var numz2=num;
$(".nums").val(numz2);
$(".form1").submit();
});
function pad (str, max) {
str = str.toString();
return str.length < max ? pad(str+"0", max) : str;
}
function addCommas(nStr) {
nStr += '';
var x = nStr.split('.');
var x1 = x[0];
var x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form class="form1" action="submit.php" method="post">
<input type="text" name="num" class="nums" value="1.40045">
<input type="submit">
</form>

Improving Secure Password Generator

Simple Password Generator Example:
function randomPassword() {
var chars = "abcdefghijklmnopqrstuvwxyz" +
"ABCDEFGHIJKLMNOP" +
"1234567890" +
"#\#\-!$%^&*()_+|~=`{}\[\]:\";'<>?,.\/",
pass = "",
PL = 10;
for (var x = 0; x < PL; x++) {
var i = Math.floor(Math.random() * chars.length);
pass += chars.charAt(i);
}
return pass;
}
function generate() {
myform.row_password.value = randomPassword();
}
<form name="myform" method="post" action="">
<table width="100%" border="0">
<tr>
<td>Password:</td>
<td>
<input name="row_password" type="text" size="40">
<input type="button" class="button" value="Generate" onClick="generate();" tabindex="2">
</td>
</tr>
</table>
</form>
Improving Functionality Questions
1). Obtaining All Values Within Variable
Taking the base script above, how can I call chars.length and chars.charAt(i) where chars equals all the values within Chars?
var Chars = {};
Chars.abc = "abcdefghijklmnopqrstuvwxyz";
Chars.ABE = "ABCDEFGHIJKLMNOP";
Chars.Num = "1234567890";
Chars.Sym = "#\#\-!$%^&*()_+|~=`{}\[\]:\";'<>?,.\/";
2). Implementing a checkbox system for less advanced password
To generate a less advanced password, such as not including symbox via unchecking a checkbox, how can I make it so only Chars.abc, Chars.ABE, and Chars.Num values are used?
3). Equally Divide Password Length By Chars
Round down (Password length / Chars used ), ie; the example used in this question generates a 10 character password and uses all charecters, therefore there would be a minimum of 2 of each Chars.
The 3rd functionality is missing and will probably be way more sophisticated. But this is a simple solution to the 1st and 2nd ones.
var output = document.getElementsByTagName('output')[0];
var Chars = {};
Chars.length = 16;
Chars.abc = "abcdefghijklmnopqrstuvwxyz";
Chars.ABE = "ABCDEFGHIJKLMNOP";
Chars.Num = "1234567890";
Chars.NumRequired = true;
Chars.Sym = "#\#\-!$%^&*()_+|~=`{}\[\]:\";'<>?,.\/";
var generator = new randomPasswordGenerator(Chars);
var simpleGenerator = new randomPasswordGenerator({
length: 6,
abc: 'abc',
Num: '0'
});
var button = document.getElementsByTagName('button')[0];
button.addEventListener('click', clickFunction);
var checkbox = document.getElementsByTagName('input')[0];
function clickFunction () {
if (checkbox.checked) output.textContent = simpleGenerator.randomPassword();
else output.textContent = generator.randomPassword();
}
function randomPasswordGenerator(opts) {
for(var p in opts) this[p] = opts[p];
this.randomPassword = randomPassword;
}
function randomPassword() {
var chars = (this.abc || "") +
(this.ABE || "") +
(this.Num || "") +
(this.Sym || ""),
pass = [],
PL = this.length;
if (this.NumRequired) {
var r = Math.floor(Math.random() * this.Num.length);
var i = Math.floor(Math.random() * PL);
pass[i] = this.Num[r];
}
for (var x = 0; x < PL; x++) {
if(!pass[x]) {
var i = Math.floor(Math.random() * chars.length);
pass[x] = chars.charAt(i);
}
}
return pass.join('');
}
output {
margin: 12px;
display: block;
border-bottom: 1px solid
}
<button>Generate</button>
<input type="checkbox">Simple
<output></output>

how can i display all items randomly in an array

I want to split a word into letters put it into in array and display the letters randomly. i am having trouble. with words that have double of the same letter. and also the correct amount of letter is being shown but not all the letters are being displayed.
Here is my code I'm a noob:
window.onload = init;
function init() {
//var name=prompt("what is your name ? ","");
//character(name) ;
words();
}
function character(name) {
var name = name;
document.getElementById("words").innerHTML = "hey " + name + " my name is koala could you help me put these words back in order?";
}
function words() {
var lastlet = "";
var words = ["joe", "suzy", "terry", "fox", "lopez"];
var rand = Math.floor(Math.random() * words.length) + 0;
//for one word and seperation with letters
var ranwor = words[rand].split("");
for (var i = 0; i < ranwor.length; i++) {
var inn = ranwor[Math.floor(Math.random() * ranwor.length)].split().shift();
if (true) {
var di = document.getElementById("wor").innerHTML += inn;
}
lastlet = inn;
}
}
#char {
height: 65px;
width: 65px;
}
#words {
height: 100px;
width: 200px;
}
<img id="char" src="C:\Users\Public\Pictures\Sample Pictures\Koala.jpg" />
<p id="words"></p>
<br>
<p id="wor"></p>
<p id="wo"></p>
<br>
<textarea id="inp"></textarea>
<br>
<button>
I think this is right :)
</button>
Just sort the array using a random number and use join() so you do not need to loop.
var words = ["joe", "suzy", "terry", "fox", "lopez"];
var rand = words[Math.floor(Math.random() * words.length)];
function scramble (word, rescrambled) {
var scrambled = word.split("").sort(function(){ return Math.random() > .5 ? 1 : -1; }).join("");
if (word===scrambled && !rescrambled) { //if it matches the original, retry once
return scramble (word, true);
}
return scrambled;
}
console.log("Random word: ", scramble(rand));
console.group("loop them");
while(words.length){
var x = words.pop();
console.log(x,":", scramble(x));
}
console.groupEnd("loop them");

Unable to call function within jQuery

I am trying to call a function in this javascript code. My code needs to check for whether the user selects var num, var letters and var symbols to be true or false. In the code, I preset the values but I still search the object choices for the variables that are true and push it into the array choices_made. However, since I need to randomly choose the order in which the num, letters and symbols appear, I randomly choose the class based on the Math.random(). However, it doesn't show me the alert(jumbled_result) afterwards.
http://jsfiddle.net/bdaxtv2g/1/
HTML
<input id="num" type="text" placeholder="Enter desired length">
<br/><br/>
<input id="press" type="button" value="jumble it up">
JS
$(document).ready(function(){
var fns={};
$('#press').click(function(){
var length = parseInt($('#num').val());
var num = true;
var letters = true;
var symbols = false;
gen(length, num, letters, symbols);
});
function gen(len, num, letters, sym){
var choices = {
1:num,
2:letters,
3:sym
};
var choice_made = ['0'];
var choice = 0;
var jumbled_result = '';
for(x in choices){
if(choices[x]==true){
choice_made.push(x);
}
}
for(i=0;i<len;i++){
var funName = 'choice';
choice = Math.round(Math.random() * (choice_made.length-1));
funName += choice_made[choice];
jumbled_result = fns[funName](jumbled_result);
}
alert(jumbled_result);
}
fns.choice0 = function choice0(jumbled_result){
var numbers = '0123456789';
return jumbled_result += numbers.charAt(Math.round(Math.random() * numbers.length));
}
fns.choice1 = function choice1(jumbled_result) {
var alpha = 'abcdefghijklmnopqrstuvwxyz';
return jumbled_result += alpha.charAt(Math.round(Math.random() * alpha.length));
}
});
You never declare functions within document.ready of jQuery. The functions should be declared during the first run(unless in special cases).
Here is a working code made out of your code. What I have done is just removed your functions out of document.ready event.
$(document).ready(function() {
$('#press').click(function() {
var length = parseInt($('#num').val());
var num = true;
var letters = true;
var symbols = false;
gen(length, num, letters, symbols);
});
});
var fns = {};
function gen(len, num, letters, sym) {
var choices = {
1: num,
2: letters,
3: sym
};
var choice_made = ['0'];
var choice = 0;
var jumbled_result = '';
for (x in choices) {
if (choices[x] == true) {
choice_made.push(x);
}
}
for (i = 0; i < len; i++) {
var funName = 'choice';
choice = Math.round(Math.random() * (choice_made.length - 1));
funName += choice_made[choice];
jumbled_result = fns[funName](jumbled_result);
}
alert(jumbled_result);
}
fns.choice0 = function choice0(jumbled_result) {
var numbers = '0123456789';
return jumbled_result += numbers.charAt(Math.round(Math.random() * numbers.length));
}
fns.choice1 = function choice1(jumbled_result) {
var alpha = 'abcdefghijklmnopqrstuvwxyz';
return jumbled_result += alpha.charAt(Math.round(Math.random() * alpha.length));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="num" type="text" placeholder="Enter desired length">
<br/>
<br/>
<input id="press" type="button" value="jumble it up">
Its because of the way the object choices have been intitialized.. Try this..
var choices = {
0:num,
1:letters,
2:sym
};
And also
var choice_made = [];
JS fiddle link : http://jsfiddle.net/8dw7nvr7/2/

Categories

Resources