如何更有效地编码此Cellular Automata项目?

时间:2018-11-30 11:54:41

标签: javascript html cellular-automata

我是编程的新手,并且对蜂窝自动机很感兴趣,因此我决定尝试使用JavaScript编写脚本,以进行编码实践,从而可以制作个性化的脚本。我创建的元胞自动机项目用于一个简单的二进制(黑白)二维表CA,该表查看一个单元格的8个最近邻居的颜色以及该单元格本身的颜色,并根据该规则中给出的规则更新其颜色。 CA表下方的“规则集”表。唯一的问题是,我编写的代码要花很长时间才能处理每次迭代,这显然是因为它需要所有大循环。实际上,在撰写本文时,我意识到我可以通过在if语句找到正确的配置时停止当前邻居颜色配置与所有可能配置的集合之间的比较搜索来降低所需的处理能力,但这可能不会降低所需的处理能力达到我希望的水平,我确信还有更多方法可以使其更快。如果有人能给我一些有关如何进一步降低处理能力的建议,我将不胜感激。另外,请以通俗易懂的方式解释您的答案。谢谢!这是代码:

<!DOCTYPE html>
<html>
<head>
<title></title>


<style>
table {border-collapse: collapse;}
table, td, th {border: 1px solid black;}
td {width:1px; height:1px;}
</style>

</head>
<body>

<button onclick="Toggle()">Toggle</button>  

<!-- Toggle runs the Iterate function with a setInterval -->

<button onclick="Iterate()">Iterate</button>
<br>


<script>


document.write("<table>")
for (row=0; row<100; row++) {
document.write("<tr>")
for (col=0; col<100; col++) 
{document.write("<td id = 'R" + row + "C" + col + "'  style='background-color: white' ondblclick='MouseDown(this)' onmousedown='MouseDown(this)' onmouseover='MouseUp(this)'>" + "</td>")}
document.write("</tr>")}
document.write("</table>")

// This is the cellular automata table

document.write("<br>")

document.write("<table>")
for (row=0; row<16; row++) {
document.write("<tr>")
for (col=0; col<32; col++) 
{document.write("<td id = 'id" + (col+32*row) + "'  style='background-color: white' ondblclick='MouseDown(this)' onmousedown='MouseDown(this)' onmouseover='MouseUp(this)'>" + "</td>")}
document.write("</tr>")}
document.write("</table>")

// This is the 'ruleset' table


let determiner = 0
function MouseDown(cell) {determiner = 1
if (cell.style.backgroundColor == "white") {cell.style.backgroundColor = "black"}
else {cell.style.backgroundColor = "white"}}
window.addEventListener('mouseup', function(event){determiner = 0})
function MouseUp(cell) {if (determiner == 1) {
if (cell.style.backgroundColor == "white") {cell.style.backgroundColor = "black"}
else {cell.style.backgroundColor = "white"}}}

// This section provides the click & drag cell colour changing functions



for (i=0; i<512; i++) {
if (i % 512 < 256){this["j1"] = "white"} else {this["j1"] = "black"}
if (i % 256 < 128){this["j2"] = "white"} else {this["j2"] = "black"}
if (i % 128 < 64){this["j3"] = "white"} else {this["j3"] = "black"}
if (i % 64 < 32){this["j4"] = "white"} else {this["j4"] = "black"}
if (i % 32 < 16){this["j5"] = "white"} else {this["j5"] = "black"}
if (i % 16 < 8){this["j6"] = "white"} else {this["j6"] = "black"}
if (i % 8 < 4){this["j7"] = "white"} else {this["j7"] = "black"}
if (i % 4 < 2){this["j8"] = "white"} else {this["j8"] = "black"}
if (i % 2 < 1){this["j9"] = "white"} else {this["j9"] = "black"}
this["compare"+i] = {unit00: j1,unit01: j2,unit02: j3,unit10: j4,unit11: j5,unit12: j6,unit20: j7,unit21: j8,unit22: j9}
}

// This creates an object for each possible block of 9 cells to compare with the actual blocks of cells around each cell in the Iterate() function


function Iterate() {
this["groupvec"] = []
for (i=0; i<100; i++) {
for (j=0; j<100; j++) {
if (i !== 0 && i !== 99) {rownum = [i-1, i, i+1]}
else if (i == 0) {rownum = [99, 0, 1]}
else if (i == 99) {rownum = [98, 99, 0]}
if (j !== 0 && j !== 99) {colnum = [j-1, j, j+1]}
else if (j == 0) {colnum = [99, 0, 1]}
else if (j == 99) {colnum = [98, 99, 0]}
this["group"+"R"+i+"C"+j] = {}
for (r in rownum) {
for (c in colnum) {
this["group"+"R"+i+"C"+j]['unit'+r.toString()+c.toString()] = document.getElementById("R" + rownum[r] + "C" + colnum[c]).style.backgroundColor
}}
this["groupvec"].push( JSON.stringify(this["group"+"R"+i+"C"+j]) )
}}
for (i=0; i<100; i++) {
for (j=0; j<100; j++) {
for (k=0; k<512; k++) {
if (groupvec[j+(100*i)] == JSON.stringify(window["compare"+k.toString()])) {
document.getElementById("R"+i+"C"+j).style.backgroundColor = document.getElementById("id"+k).style.backgroundColor
}}}}}

// This function finds the colours of the cells in a block of 9 cells around each cell, compares them with the 'compare' objects and then changes their colour to the colour of the 'ruleset' table with the same index as the 'compare' object.

let toggler = null
function Toggle() {
if (toggler == null) {toggler = setInterval(Iterate.bind(null), 1000)}
else {clearInterval(toggler); toggler = null}
}

// This provides an automated run function for the CA

</script>


</body>
</html>

1 个答案:

答案 0 :(得分:0)

您的代码每次循环循环5 210 000次(100行* 100列* 3单元* 3单元+ 100行* 100列* 512个规则集单元)。每次迭代都需要大量工作,而使用HTML <table>会不断加重您的工作,并且不断地从中读取和编写样式。

如果您想要更持久的解决方案,请尝试使用Canvas来显示CA的状态,并使用JavaScript数组来处理该状态。您也许仍然可以使用表在开始时设置规则集,然后将其存储在一个数组中,以便在检查它时就在检查内存中的数据数组。

然后您的代码可能看起来像这样,它循环了80 000次(尽管如果并入规则集则可能会更多):

const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
const width = 100;
const height = 100;
const cellWidth = 4;
const cellHeight = 4;

// Access cells with automaton[row][column]
let automaton = Array(height).fill(Array(width).fill(0)));

// Initialise your automaton somehow
// ...

function iterate() {
    // Create the next automaton state to write updates to
    let nextAutomaton = Array(height).fill(Array(width).fill(0)));
    for (let y = 0; y < height; ++y) {
        for (let x = 0; x < width; ++x) {
            // Get the surrounding 8 cells
            // (n + MAX + 1) % MAX will wrap around
            // (n + MAX - 1) % MAX will wrap around
            const surroundingIndices = [
                { x: x, y: (y + height - 1) % height },                       // above
                { x: (x + width + 1) % width, y: (y + height - 1) % height }, // above right
                { x: (x + width + 1) % width, y: y },                         // right
                { x: (x + width + 1) % width, y: (y + height + 1) % height }, // below right
                { x: x, y: (y + height + 1) % height },                       // below
                { x: (x + width - 1) % width, y: (y + height + 1) % height }, // below left
                { x: (x + width - 1) % width, y: y },                         // left
                { x: (x + width - 1) % width, y: (y + height - 1) % height }  // above left
            ];
            for (int i = 0; i < 8; ++i) {
               const cell = automaton[surroundingIndices.y][surroundingIndices.x];
               // Do something based on the value of this surrounding cell
               // This could depend on your ruleset
               // ...
            }
            // Set this cell's value in the next state
            nextAutomaton[y][x] = 1;
            // Render the cell
            context.fillStyle = 'red';
            context.fillRect(x, y, cellWidth, cellHeight);
        }
    }
    // Overwrite the old automaton state
    automaton = nextAutomaton;
}

要设置自动机动画效果,您将需要使用window.requestAnimationFrame,它必须使用iterate函数递归调用,并且可以使用切换按钮启动或停止(请参见{{3} }。