var rockPaperScissors = function(numRounds) {
var outcomes = [];
var plays = ["rock", "paper", "scissors"];
// can add rounds later, get 3 working.
// for a three round game, it would be 3^3 = 27.
// for any number of rounds it would be 3^numrounds.
function findOutCome(roundsLeft, result){
// when you cover all the rounds
// push to the outcomes
if (roundsLeft === 0) {
outcomes.push(result);
return;
}
plays.forEach(function(play){
//result.push(play);
//concat returns the entire array
findOutCome(roundsLeft-1, result.concat(play))
})
}
findOutCome(numRounds, []); // give it a starting point
return outcomes;
}
console.log(rockPaperScissors(3)); // returns an array of length 27
Что происходит в вышеописанном, перед выполнением, мы сначала определим большую функцию с функцией вложенной в него.
Затем мы вызываем console.log(rockPaperScissors(3));
, что он делает, это вызывает нашу большую функцию и назначает numRounds=3
. Внутри корпуса мы находим:
var outcomes = [];
и var plays = ["rock", "paper", "scissors"];
. Они останутся определяемыми для нашей рекурсивной функции следующим образом: plays
и напишите outcomes
.
Затем определяется вложенная функция, которую мы будем использовать для рекурсии.
Тогда, наконец, наша вложенная функция вызывается с: findOutCome(numRounds, []);
Что это делает он называет нашу вложенную функцию в первый раз и присваивает roundsLeft=numRounds
и result=[].
Наш первый вызов рекурсии выглядит следующим образом:
if (roundsLeft === 0){...}
это утверждение неверно, так как roundsLeft установлен на 3, поэтому мы переходим ...
plays.forEach(function(play){...}
это петли 3 раза, так как пьесы установлены на ["rock", "paper", "scissors"]
.
Первый цикл function(play){...}
вызывается с play="rock"
и в теле функции обратного вызова, которую мы называем:
findOutCome(roundsLeft-1, result.concat(play));
Что это делает, он называет findOutCome(2,result.concat("rock"))
Использование CONCAT здесь не изменяет result, а работает на копии и concats []
с "rock"
, создавая таким образом ["rock"]
.
Если мы хотим на самом деле изменить массив результатов, мы будем использовать здесь result.push(...)
. Но каждый экземпляр рекурсии имеет свою локальную версию результата, так что это не сработает, поскольку изменения ничего не повлияют.
Наш первый экземпляр рекурсии по-прежнему открыт, и мы все еще находимся в нашем первом цикле forEach, когда мы начинаем наш рекурсивный вызов.
Вызывается наш второй экземпляр рекурсии findOutCome
. В нашем втором случае roundsLeft=2
и result=["rock"]
.
if (roundsLeft === 0) {...}
является ложным, поэтому мы переходим на наш цикл по каждому элементу ...
Мы входим в наш первый цикл ForEach и play="rock"
. Затем мы звоним findOutCome(1, ["rock","rock"])
Таким образом, мы вводим наш третий уровень рекурсии и устанавливаем roundsLeft=1
и result=["rock","rock"]
.
if (roundsLeft === 0) {...}
еще ложь, поэтому мы переходим ...
Таким образом, мы войти в нашем 3-е уровня нашего цикла Foreach который петля через наши прослушивания массива ... первый цикл использует play="rock"
таким образом, наш цикл заканчивается:
findOutCome(0,["rock","rock","rock"])
затем Вводим наш 4-ый уровень рекурсии и установить roundsLeft=0
и result=["rock","rock","rock"]
.
if (roundsLeft === 0) {outcomes.push(result);return;}
Это утверждение верно, поэтому мы обрабатываем его логику.
наш outcomes
массив, который в настоящее время устанавливается в []
добавляемый с ["rock","rock","rock"]
создавая таким образом:
outcomes=[["rock","rock","rock"]];
Тогда наше утверждение, если встречает return
, который заканчивается наш 4-й уровень рекурсии и возвращается в наш 3-го уровня рекурсии.
На нашем третьем уровне рекурсии мы все еще находимся в пределах нашего цикла forEach, поэтому перейдем к нашему 2-му элементу в цикле.
Помните, что на нашем третьем уровне рекурсии наша функция findOutCome
вызывалась с roundsLeft=1
и result=["rock","rock"]
и не изменялась. Переменные никогда не изменяются, но каждый экземпляр рекурсии использует свою локальную копию этих переменных. Таким образом, в нашем forEach-цикле, поскольку это второй элемент, зацикливаемый, play="paper"
.
Затем мы сталкиваемся findOutCome(roundsLeft-1, result.concat(play))
, который вычисляет:
findOutCome(0, ["rock","rock","paper"])
таким образом мы входим в 4-й уровень рекурсии и if (roundsLeft === 0) {outcomes.push(result);return;}
верно, предотвращая более 3-х уровней рекурсии глубины, поэтому мы обрабатываем его логику.
outcomes.push(result)
прилагает ["rock","rock","paper"]
к нашему массиву.
Таким образом, наши результаты массив теперь гласит: outcomes=[["rock","rock","rock"],["rock","rock","paper"]];
Тогда мы сталкиваемся с return
заявление и закрыть наш 4-й уровень рекурсии глубины и возобновить цикл по каждому элементу нашего 3-го уровня рекурсии в.
К тому времени наши концы петли Foreach в нашем 3-го уровня рекурсии, outcomes=[["rock","rock","rock"],["rock","rock","paper"],["rock","rock","scissors"]];
Тогда наш цикл Foreach заканчивает тем самым возвращаясь к нашей 2-го уровня петли Foreach рекурсии, где roundsLeft=2
и result=["rock"]
.
Продолжаем нашу вторую петлю нашего forEach для нашего второго уровня глубины рекурсии. play="paper"
. Тогда мы сталкиваемся:
findOutCome(roundsLeft-1, result.concat(play))
Таким образом, создается новый 3-й уровень глубины с roundsLeft=1
и result=["rock","paper"]
.
3-й уровень проходит через другой для каждого и устанавливает result=["rock","paper","rock"]
и roundsLeft=0
отправляет его на 4-й уровень глубины.
Наш результат добавляется к результатам. Таким образом, мы теперь имеем: outcomes=[["rock","rock","rock"],["rock","rock","paper"],["rock","rock","scissors"],["rock","paper","rock"]];
и т.д., и т.д. ... в конечном счете, наш outcomes
массив вырастает до 27 элементов в размерах и наш первый уровень рекурсии, которая была вызвана с roundsLeft=3
и result=[]
заканчивает свой цикл по каждому элементу. Наконец, мы встретим return outcomes;
и таким образом вернем наш ответ console.log(...)
, который выводит наш ответ на консоль. Теперь консоль отображает массив, содержащий 27 элементов, каждый из которых содержит массив размером 3 элемента.
Чтобы представить, как рекурсия работает, представьте себе значение (то есть, 4), тогда представьте, что рекурсия называется значением времени (4), теперь третья функция рекурсии должна принимать результат с 4-го, затем 2-го от 3-го и так далее на. Следовательно, вам всегда нужно возвращать значение или другой экземпляр рекурсии (т. Е. Return val == 0? 1: рекурсия (val-1);), в целом, просто подумайте в глубину. – NemanjaT