我目前正在制作一个游戏,说明John Conways的“生命游戏”我一直在学习关闭和模块化模式,并且正在尝试实现我在Javascript中学到的更多内容。 如果您有兴趣,可以在这里查看我的回购。 所有这些方法都在'Game'对象中。 我有它的工作,但我试图限制变量,使其尽可能的功能(在函数之间传递网格数组)。 我想要一些建议,我应该保持更高的范围变量不变或更重要。
在结构方面哪种解决方案更好?
// initial grid // will be bigger than this but is 3x3 for this question. let grid = [ [1,0,0], [0,1,0], [0,0,1] ]解决方案1:我最初的解决方法:
function nextGrid(){ grid = applyRules(grid) renderGrid(grid) } function applyRules(grid){ // makes changes } function renderGrid(grid){ // makes changes } // call nextGrid() to generate subsequent new grids.解决方案2:更多地研究闭包,这样更好吗?
function nextGrid() { let prevGrid = grid; return function(){ prevGrid = applyRules(prevGrid) renderGrid(prevGrid) } } function applyRules(prevGrid){ // makes changes } function renderGrid(grid){ // makes changes } const next = nextGrid(); // call next() to generate subsequent new grids.I am currently making a game that illustrates John Conways 'Game of Life' I've been learning about closures and the modular patterns and am trying to implement more of what I'm learning in Javascript. You can check out my repo here if your interested. All of these methods are inside a 'Game' object. I have it working, but am trying to limit variables and make it as functional as possible (passing the grid array between functions). I would like some advice on wether I should be keeping higher scope variable immutable or wether it doesnt matter.
Which solution is better practise, in terms of structure?
// initial grid // will be bigger than this but is 3x3 for this question. let grid = [ [1,0,0], [0,1,0], [0,0,1] ]Solution 1: My initial way of solving:
function nextGrid(){ grid = applyRules(grid) renderGrid(grid) } function applyRules(grid){ // makes changes } function renderGrid(grid){ // makes changes } // call nextGrid() to generate subsequent new grids.Solution 2: Having looked into closures more, is this better?
function nextGrid() { let prevGrid = grid; return function(){ prevGrid = applyRules(prevGrid) renderGrid(prevGrid) } } function applyRules(prevGrid){ // makes changes } function renderGrid(grid){ // makes changes } const next = nextGrid(); // call next() to generate subsequent new grids.最满意答案
你的解决方案都采用突变。 在您的第一个解决方案中,您将改变全局变量grid 。 在第二个解决方案中,您将改变局部变量prevGrid 。 一个真正有用的程序将使用递归而不是变异。 例如,这就是我要做的:
const game = /* initial game state */; play(game); function play(game) { render(game); setTimeout(play, 100, update(game)); }正如您所看到的,我们不是改变全局变量game ,而是每100毫秒调用一次更新的游戏状态。 我们在第三行的初始通话play(game)开始游戏。 如果我们将其评论出来,则不会显示任何内容。
以下是几行代码中Conway生命游戏的完整示例:
const glyph = [" ", "■"]; document.querySelectorAll("pre.life").forEach(e => play(e, read(e.innerHTML))); function read(text) { return text.split("\n").map(l => l.split("").map(c => glyph.indexOf(c))); } function play(pre, game) { pre.innerHTML = show(game); setTimeout(play, 100, pre, update(game)); } function show(game) { return game.map(line => line.map(cell => glyph[cell]).join("")).join("\n"); } function update(game) { return game.map((line, i) => line.map((cell, j) => { const back = game[i - 1], next = game[i + 1], h = j - 1, k = j + 1; const neighbors = (back && back[h] || 0) + (back && back[j] || 0) + (back && back[k] || 0) + (line[h] || 0) + (line[k] || 0) + (next && next[h] || 0) + (next && next[j] || 0) + (next && next[k] || 0); switch (neighbors) { case 3: return 1; case 2: return cell; default: return 0; } })); }pre.life { line-height: 0.666; }<pre class="life"> ■ ■ ■ ■■ ■■ ■■ ■ ■ ■■ ■■ ■■ ■ ■ ■■ ■■ ■ ■ ■■ ■ ■ ■ ■ ■ ■ ■ ■■ </pre>以上模式是Gosper滑翔机枪 。
Both your solutions employ mutation. In your first solution you mutate the global variable grid. In your second solution you mutate the local variable prevGrid. A truly functional program would use recursion instead of mutation. For example, this is what I'd do:
const game = /* initial game state */; play(game); function play(game) { render(game); setTimeout(play, 100, update(game)); }As you can see, instead of mutating the global variable game we call play with an updated game state every 100 milliseconds. Our initial call play(game) on the third line starts the game. If we comment it out, nothing will be displayed.
Here's a complete example of Conway's Game of Life in a few lines of code:
const glyph = [" ", "■"]; document.querySelectorAll("pre.life").forEach(e => play(e, read(e.innerHTML))); function read(text) { return text.split("\n").map(l => l.split("").map(c => glyph.indexOf(c))); } function play(pre, game) { pre.innerHTML = show(game); setTimeout(play, 100, pre, update(game)); } function show(game) { return game.map(line => line.map(cell => glyph[cell]).join("")).join("\n"); } function update(game) { return game.map((line, i) => line.map((cell, j) => { const back = game[i - 1], next = game[i + 1], h = j - 1, k = j + 1; const neighbors = (back && back[h] || 0) + (back && back[j] || 0) + (back && back[k] || 0) + (line[h] || 0) + (line[k] || 0) + (next && next[h] || 0) + (next && next[j] || 0) + (next && next[k] || 0); switch (neighbors) { case 3: return 1; case 2: return cell; default: return 0; } })); }pre.life { line-height: 0.666; }<pre class="life"> ■ ■ ■ ■■ ■■ ■■ ■ ■ ■■ ■■ ■■ ■ ■ ■■ ■■ ■ ■ ■■ ■ ■ ■ ■ ■ ■ ■ ■■ </pre>The above pattern is the Gosper glider gun.
更多推荐
发布评论