四次猜测
我们的第一项工作是允许用户进行 4 次猜测。在 Wordle 中,一个 5 个字母的单词允许 6 次猜测,因此对于 Numble,我们将允许 4 次猜测一个三位数字。
为此,我们必须删除该 guess 属性并向 State 对象添加另外两个属性:
const State = {
started: false,
digits: Array(10).fill("grey"),
guesses: Array(4).fill(Array(3).fill(null)),
guessCount: 0,
count: 0,
start, finish, check, appear, remove,
View
}
正如你所看到的,我们现在有一个 guesses 属性来代替 guess 我们之前的属性。的值 guesses 是一个 2D 数组,由 4 个数组组成,每个数组的长度为 3,并用 null. 如果您不熟悉该 Array.fill() 函数,它是创建数组的快捷方式,这意味着我们不必完整地写出数组。
4 个嵌套数组中的每一个都代表用户将做出的 4 个猜测之一。例如,如果第一个猜测是 123,则 guesses 数组将如下所示:
[[1,2,3], [null, null, null], [null, null, null], [null, null, null]]
每次用户进行猜测时,该数组都会更新以匹配他们的猜测,有效地记录他们在游戏中所做的所有猜测。
此外,我们还有一个 guessCount 属性,其值设置为 0。虽然与 count 属性类似,但它可以让我们跟踪用户的猜测次数。
该图应该可以帮助您可视化并完全理解对 count 和 guessCount 属性的需求:

如您所见, guessCount 是猜测存储在哪个嵌套数组的 count 索引,并且是每个猜测的每个单独数字的索引。
现在我们需要对 View 函数进行一些更改:
const View = state => html`
<h1>Numble</h1>
${state.started ?
html`<div id="guesses">
${state.guesses.map((guess, i) => html`<div class="row">${guess.map((number,j)=> html`<div class="grey">${number}</div>`)}</div>`)}
</div>
<p id="feedback">${state.feedback}</p>
<div id="keyboard">
${state.digits.map((digit,index) => html`<button onclick=${state.appear(index)}>${index}</button>`)}
<button onclick=${state.remove}>DELETE</button>
<button onclick=${state.check}>ENTER</button>
</div>
<button onclick=${state.finish}>END</button>`
:
html`<button onclick=${state.start}>START</button>`
}`
这与我们之前创建的几乎相同 View ,但是 id 为“guesses”的 div 已更改。事实上,我们现在使用 2D 数组来像网格一样显示 4 个猜测,我们将需要一个嵌套地图。
编码提示:当使用嵌套地图时,对于每个地图的索引,我们将使用 i 第一个地图和 j 第二个地图。你可以使用任何你认为对你来说最容易的东西,只要它们不一样!
第一个地图循环遍历每个猜测作为网格的一行。然后,第二张地图遍历该猜测的每个单独的数字,并显示相关的 HTML 以显示已被猜测的数字或一个空圆圈。有了这个,你的屏幕应该是这样的:

这种新布局意味着我们还必须更改 appear 和 remove 功能。它相对简单,但同样需要双映射。
const appear = guess => event => {
Update(state => ({
guesses: state.guesses.map((array,i) => i === state.guessCount ? array.map((digit,j) => j === state.count ? guess : digit) : array) ,
count: state.count + 1
}))
}
我们正在 guesses 这里更新属性,这就是拥有两个不同 count 属性将变得非常有用的地方。
第一个映射检查要更改的行:如果数组的索引与用户的猜测匹配,则可以发生第二个映射,否则保持值相同。
第二张地图执行与我们在第二条中创建的完全相同的逻辑 appear 。
就像以前一样,该 remove 功能的工作原理几乎相同。
const remove = event => {
Update(state => ({
guesses: state.guesses.map((array,i) => i === state.guessCount ? array.map((digit,j)=> j === state.count - 1 ? null : digit) : array),
count: state.count - 1
}))
}
remove 这里的第一张地图只是识别用户正在做出的猜测,第二张地图遵循与我们原始函数相同的逻辑 。
然而 count ,属性递减以确保用户可以重新进行猜测。
最后,我们需要对 check 函数进行一些更改。这是每次用户提交猜测时运行的函数。
const check = event => {
Update(state => {
const numble = state.guesses[state.guessCount].join("") === state.number
return {
feedback: numble ? "NUMBLE!" : state.guessCount < 3 ? "Keep going..." : `Nope! It was ${state.number}`,
guessCount: state.guessCount + 1,
count: 0
}
})
}
这里只有两件事发生了变化,并且都在返回的对象中。该 feedback 属性添加了一些逻辑来使应用程序更具动态性。反馈现在将显示一条消息,让用户知道他们的进展情况。
在这种情况下,我们有:如果 numble 是 true ,换句话说,如果用户的猜测是正确的,则反馈变为“NUMBLE”;如果 numble 是 false,检查猜测是否小于三(这实质上是检查用户是否做出了最终猜测)。如果是,则反馈为“继续……”,否则为“不!是(答案)”。