为什么`循环`写不止一次

时间:2017-03-14 15:35:20

标签: javascript loops for-loop foreach

我尝试使用guessed创建javascript,这是代码:

<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>

但不幸的是,结果重复了不止一次: 结果:

  

abb baa aac cba cbb aba bbb aac acb cba ccc bab caa bab ccc aac ccb   aba abc bac cbb

这会减慢程序,如何解决这个问题 有解决方案吗? 谢谢

4 个答案:

答案 0 :(得分:3)

由于您不想两次检查相同的密码,因此生成随机猜测显然不是正确的方法。正如klumme所提到的,存储一系列先前的猜测只会增加时间和空间的复杂性,因此也是如此。您需要做的是使用强力方法,即尝试每个字符组合,直到您得到正确的答案。以下是如何实现它:

注意:请注意,强力算法通常效率很低,如果您使用原始代码中的完整字母数字字符串来强制使用超过3-4个字符的密码,这将花费大量的时间(特别是在浏览器中)。从本质上讲,JavaScript并不是一种非常强大的数字运算语言 - 所以这个答案更多的是它的概念,而不是在大多数现实环境中使用。

&#13;
&#13;
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);
&#13;
&#13;
&#13;

答案 1 :(得分:2)

如果我理解正确,问题在于随机密码功能(&#34; makeid&#34;)可能会多次返回相同的密码。这并不奇怪,这个功能没有理由知道已经尝试过哪些密码。您可以跟踪已经尝试过的密码,如果之前已经尝试过,请不要尝试密码(如在用户的答案中),但在这种情况下,它可能不会加快程序的速度。

更好的方法可能是系统地而不是随机地迭代可能的密码。例如,试试&#34; aaa&#34;首先,然后&#34; aab&#34;,&#34; aac&#34; &#34; ABA&#34;等等。

这是我想出来的东西 - 它可能不是很快。我在&#34;可能&#34;中使用了一系列索引。字符串,直到实际尝试密码,因为我不想在路上乱搞indexOf()。

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);
}

答案 2 :(得分:1)

首先,将结果存储在数组中。其次,添加以下条件:if (arr.indexOf(guess) == -1) - 如果猜测的数字已经在数组中 - 跳过它。

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);

答案 3 :(得分:0)

我对这个问题很感兴趣,并决定用这个机会来了解有关发电机的更多信息。注意:使用ES6语法,因此不一定与所有平台兼容。

我不一定会推荐这个已经实施的其他方法,但它可能是一个很好的未来参考。

/**
 * 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.");
}