0

I am currently working on random password generator. I want my generator to produce a changeable number of character from a certain type. I want the character types to be: capital letters, regular letters, numbers and special characters (!@#$%^&*)

For example: the output of (number:3, letters:2, capital letters:1, (!@#$%^&*):2) will be:" *a49s@1R " but my current code is not working.

function myFunction() {
  var n = document.getElementById("myText").value;
  var l = document.getElementById("myletter").value;
  var cl = document.getElementById("mycapitalletter").value;
  var overall = cl + l + n
  var ran;
  password = ""
  var i = 1

  /*here is the javascript method *not working* */
  while (i <= overall) {
    ran = Math.floor(Math.random() * 3);
    if (ran == 2 && cl != 0 && overall > 0) {
      var letter = "";
      var choice = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
      firstletter += choice.charAt(Math.floor(Math.random() * choice.length));
      password = password + "" + firstletter;
      overall--;
      cl--;
    } else {
      if (ran == 1 && l != 0 && overall > 0) {

        var choice = "abcdefghijklmnopqrstuvwxyz";
        firstletter += choice.charAt(Math.floor(Math.random() * choice.length));
        password = password + "" + firstletter;
        overall--;
        l--;
      }
      if (ran == 0 && n != 0 && overall > 0) {
        firstletter = Math.floor(Math.random() * 10);
        password = password + "" + firstletter;
        overall--;
        n--;
      }
    }
  }

  var myWindow = window.open("", "MsgWindow", "width=200,height=100  />");
  myWindow.document.write("<p > This pasword is:  " + password + " </p>  <botton> save <botton>");
  if (myWindow.closed) {
    document.getElementById("msg").innerHTML = "i see your not stosfaied with your password, you can change it by pushing the botton again!";
  }
}
Barmar
  • 741,623
  • 53
  • 500
  • 612
Aviv Aviv
  • 129
  • 1
  • 10
  • Please give a [mcve]. – jonrsharpe Jan 12 '19 at 18:08
  • 1
    You never increment `i`, so you have an infinite `while` loop. – Barmar Jan 12 '19 at 18:36
  • 1
    A simpler way is to use separate loops to append each type of character to the string. Then randomly shuffle the final string. – Barmar Jan 12 '19 at 18:39
  • See https://stackoverflow.com/questions/3943772/how-do-i-shuffle-the-characters-in-a-string-in-javascript for how to do the last part. – Barmar Jan 12 '19 at 18:40
  • @Barmar as for your first comment, i changed the code to i++ instead of overall--, has not solved the problames. as for the second, such change in the code will lead to all the character types to be grouped, like: AKgsdf54*&, witch is not my target – Aviv Aviv Jan 12 '19 at 18:52
  • @AvivAviv They won't be grouped if you shuffle the string after concatenating them. – Barmar Jan 12 '19 at 19:02

2 Answers2

0

number:3, letters:2, capital letters:1, (!@#$%^&*):2

Apart from the special characters... numbers, letters and capital letters are easy to generate as their Character Code are consecutive.

const rules = [[3,[48,57]],[2,[97,122]],[1,[65,90]]]

Create an array of rules, where for example [3,[48,57]] requests to generate 3 numbers in between the character codes of 48 and 57.

Then all there was to do was to use Array#reduce on the rules with destructuring and to convert the chosen char code into a character.

const res = rules.reduce((a,[b,[c,d]])=>{
    for(let i = 0; i < b; i++){
      a.push(String.fromCharCode(r(d,c)));
    }
    return a;
  }, []);

The special characters needed to be calculated manually as there was no pattern between the character codes.

  const specials = "!@#$%^&*";
  for(let i = 0; i < 2; i++){
    res.push(specials[r(0,specials.length-1)])
  }
  return shuffle(res);

Full Solution:

const specialChars = document.getElementById("s");
const numbers = document.getElementById("n");
const capitals = document.getElementById("c");
const letters = document.getElementById("l");
const button = document.getElementById("b");
const result = document.getElementById("res");

button.addEventListener("click", function(e) {
  const numberCount = numbers.value;
  const letterCount = letters.value;
  const capitalCount = capitals.value;
  const specialCount = specialChars.value;

  const rules = [
    [numberCount, [48, 57]],
    [letterCount, [97, 122]],
    [capitalCount, [65, 90]]
  ]

  result.value = genPass(rules, specialCount);

})


function r(min, max) {
  return Math.floor(Math.random() * (max + 1 - min) + min);
}

/**
 * Shuffles array in place. ES6 version
 * @param {Array} a items An array containing the items.
 */
function shuffle(a) {
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

function genPass(rules, specialCount) {

  const res = rules.reduce((a, [b, [c, d]]) => {
    for (let i = 0; i < b; i++) {
      a.push(String.fromCharCode(r(d, c)));
    }
    return a;
  }, []);
  const specials = "!@#$%^&*";
  for (let i = 0; i < specialCount; i++) {
    res.push(specials[r(0, specials.length - 1)])
  }
  return shuffle(res).join("");
}
div {
  display: flex;
  flex-direction: column;
}
<div>
  <label for="n">Numbers</label>
  <input id="n" value="3" type="number" placeHolder="Numbers">
</div>
<div>
  <label for="l">Letters</label>
  <input id="l" value="3" type="number" placeHolder="Letters">
</div>
<div>
  <label for="c">Capital</label>
  <input id="c" value="3" type="number" placeHolder="Capital Letters">
</div>
<div>
  <label for="s">Specials</label>
  <input id="s" value="3" type="number" placeHolder="Specials">
</div>

<button id="b">Generate</button>
<input id="res" type="text" disabled>

Shuffle method take from here: https://stackoverflow.com/a/6274381/3589092

kemicofa ghost
  • 16,349
  • 8
  • 82
  • 131
0

You need to parse the inputs as integers. Otherwise, + is concatenation, so if you enter 3, 2, 1 it will try to create a password with 321 characters, but only 3 digits, 2 letters, and 1 lowercase letter. The loop will never finish.

You're using firstletter += when it should just be firstletter =, since there's no previous value of firstletter to append to.

You should also declare password and firstletter as local variables.

You don't need the i variable. You can simply test while (overall > 0).

function myFunction() {
  var n = parseInt(document.getElementById("myText").value, 10);
  var l = parseInt(document.getElementById("myletter").value, 10);
  var cl = parseInt(document.getElementById("mycapitalletter").value, 10);
  var overall = cl + l + n
  var ran, firstletter;
  var password = ""

  /*here is the javascript method *not working* */
  while (overall > 0) {
    ran = Math.floor(Math.random() * 3);
    if (ran == 2 && cl != 0) {
      var choice = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
      firstletter = choice.charAt(Math.floor(Math.random() * choice.length));
      password = password + "" + firstletter;
      overall--;
      cl--;
    } else if (ran == 1 && l != 0) {

      var choice = "abcdefghijklmnopqrstuvwxyz";
      firstletter = choice.charAt(Math.floor(Math.random() * choice.length));
      password = password + "" + firstletter;
      overall--;
      l--;
    } else if (ran == 0 && n != 0) {
      firstletter = Math.floor(Math.random() * 10);
      password = password + "" + firstletter;
      overall--;
      n--;
    }
  }

  console.log(password);
}
Digits: <input type="number" id="myText">
<br> Letters: <input type="number" id="myletter">
<br> Capitals: <input type="number" id="mycapitalletter">
<br>
<button onclick="myFunction()">Submit</button>
Barmar
  • 741,623
  • 53
  • 500
  • 612