Как правильно применить игровой тик Конвея? - PullRequest
0 голосов
/ 06 января 2020

В алгоритме игры жизни Конвея он гласит:

Первое поколение создается путем одновременного применения вышеуказанных правил к каждой ячейке в семени; рождения и смерти происходят одновременно, и дискретный момент, в который это происходит, иногда называется тик.

Как я могу применить функцию отображения к каждому элементу массива одновременно? Это действительно то, что он спрашивает? Мой код, кажется, работает, но как только начинается жизнь, он ведет себя хаотично и ни в коем случае не умирает полностью, он только расширяется, пока не займет всю мою ширину / высоту. Так что, очевидно, что-то не так в моей реализации, и с моей точки зрения я мог связать это только с моим неправильным представлением о том, что на самом деле означает тик и как он применяется.

Вот моя реализация:

conways(xRow: number, yRow: number) {

    // Any live cell with fewer than two live neighbours dies, as if by underpopulation.
    // Any live cell with two or three live neighbours lives on to the next generation.
    // Any live cell with more than three live neighbours dies, as if by overpopulation.
    // Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.

    let matrix = [], tracker = [];
    const tileSize = new Dimension(Math.floor(this.dimensions.width / xRow), Math.floor(this.dimensions.height / yRow));

    for (let i = 0; i < xRow; i++) matrix[i] = new Array(yRow);

    for (let i = 0; i < matrix.length; i++) {
        for (let j = 0; j < matrix[i].length; j++) {
            if (Math.floor(Math.random() * 10) === 1) {
                matrix[i][j] = new GameObject(Model.RECTANGLE, new Point(i * tileSize.width, j * tileSize.height), new Dimension(tileSize.width, tileSize.height), "black");
                matrix[i][j].addProperty("alive", true);
            }
            else {
                matrix[i][j] = new GameObject(Model.RECTANGLE, new Point(i * tileSize.width, j * tileSize.height), new Dimension(tileSize.width, tileSize.height), "white");
                matrix[i][j].addProperty("alive", false);
            }
            this.render.requestStage(matrix[i][j]);
        }
    }

    let isAlive = (position: Point, world: GameObject[][]) => {
        let neighboursCount = 0;

        const cellStatus = world[position.x][position.y].props["alive"];

        if (world[position.x + 1] && world[position.x + 1][position.y] && 
            world[position.x + 1][position.y].props["alive"]) neighboursCount++;

        if (world[position.x - 1] && world[position.x - 1][position.y] && 
            world[position.x - 1][position.y].props["alive"]) neighboursCount++;

        if (world[position.x] && world[position.x][position.y + 1] && 
            world[position.x][position.y + 1].props["alive"]) neighboursCount++;

        if (world[position.x] && world[position.x][position.y - 1] &&
            world[position.x][position.y - 1].props["alive"]) neighboursCount++;

        if (world[position.x - 1] && world[position.x - 1][position.y + 1] && 
            world[position.x - 1][position.y + 1].props["alive"]) neighboursCount++;

        if (world[position.x + 1] && world[position.x + 1][position.y + 1] && 
            world[position.x + 1][position.y + 1].props["alive"]) neighboursCount++;

        if (world[position.x - 1] && world[position.x - 1][position.y - 1] && 
            world[position.x - 1][position.y - 1].props["alive"]) neighboursCount++;

        if (world[position.x + 1] && world[position.x + 1][position.y - 1] && 
            world[position.x + 1][position.y - 1].props["alive"]) neighboursCount++;

        if (cellStatus) {
            if (neighboursCount < 2) return false;
            if (neighboursCount === 2 || neighboursCount === 3) return true;
            if (neighboursCount > 3) return false;
        }
        else if (!cellStatus && neighboursCount === 3) return true;
        else return false;
    }

    setInterval(() => {
        for (let i = 0; i < matrix.length; i++) {
            for (let j = 0; j < matrix.length; j++) {
                let alive = isAlive(new Point(i, j), matrix);
                if (alive) {
                    matrix[i][j].color = "black";
                    matrix[i][j].props["alive"] = true;
                }
                else {
                    matrix[i][j].props["alive"] = false;
                    matrix[i][j].color = "white";
                }
            }
        }
    }, 100);
}

Пожалуйста, не возражайте против пользовательских конструкторов и функций, так как это мой взгляд на «библиотеку Graphi c», которая фактически ссылается только на Canvas API и ImageData. То, что я делаю, в основном:

-Создание матрицы размера w / h.

-При итерации по ней, есть 1/10 шансов, что ячейка будет жива , (Я получаю случайное начальное число, потому что я еще не добавил ввод)

-Рендерим все это на экран.

-Каждые 10 мс я применяю правила Конвея к каждой ячейке итеративно, и я измените их цвет / состояние соответственно.

1 Ответ

1 голос
/ 06 января 2020

Используя стратегию буфера, предложенную Майком и Хайдом, я получил ее на работу. Вот изменения для заинтересованных:

conways(xRow: number, yRow: number) {

        // Any live cell with fewer than two live neighbours dies, as if by underpopulation.
        // Any live cell with two or three live neighbours lives on to the next generation.
        // Any live cell with more than three live neighbours dies, as if by overpopulation.
        // Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.

        let matrix = [], bufferMatrix = [];
        const tileSize = new Dimension(Math.floor(this.dimensions.width / xRow), Math.floor(this.dimensions.height / yRow));

        for (let i = 0; i < xRow; i++) matrix[i] = new Array(yRow);
        for (let i = 0; i < xRow; i++) bufferMatrix[i] = new Array(yRow);

        for (let i = 0; i < matrix.length; i++) {
            for (let j = 0; j < matrix[i].length; j++) {
                if (Math.floor(Math.random() * 10) === 1) {
                    matrix[i][j] = new GameObject(Model.RECTANGLE, new Point(i * tileSize.width, j * tileSize.height), new Dimension(tileSize.width, tileSize.height), "black");
                    matrix[i][j].addProperty("alive", true);
                    bufferMatrix[i][j] = new GameObject(Model.RECTANGLE, new Point(i * tileSize.width, j * tileSize.height), new Dimension(tileSize.width, tileSize.height), "black");
                    bufferMatrix[i][j].addProperty("alive", true);
                }
                else {
                    matrix[i][j] = new GameObject(Model.RECTANGLE, new Point(i * tileSize.width, j * tileSize.height), new Dimension(tileSize.width, tileSize.height), "white");
                    matrix[i][j].addProperty("alive", false);
                    bufferMatrix[i][j] = new GameObject(Model.RECTANGLE, new Point(i * tileSize.width, j * tileSize.height), new Dimension(tileSize.width, tileSize.height), "white");
                    bufferMatrix[i][j].addProperty("alive", false);
                }
                this.render.requestStage(matrix[i][j]);
            }
        }

        let isAlive = (position: Point, world: GameObject[][]) => {
            let neighboursCount = 0;

            const cellStatus = world[position.x][position.y].props["alive"];

            if (world[position.x + 1] && world[position.x + 1][position.y] && 
                world[position.x + 1][position.y].props["alive"]) neighboursCount++;

            if (world[position.x - 1] && world[position.x - 1][position.y] && 
                world[position.x - 1][position.y].props["alive"]) neighboursCount++;

            if (world[position.x] && world[position.x][position.y + 1] && 
                world[position.x][position.y + 1].props["alive"]) neighboursCount++;

            if (world[position.x] && world[position.x][position.y - 1] &&
                world[position.x][position.y - 1].props["alive"]) neighboursCount++;

            if (world[position.x - 1] && world[position.x - 1][position.y + 1] && 
                world[position.x - 1][position.y + 1].props["alive"]) neighboursCount++;

            if (world[position.x + 1] && world[position.x + 1][position.y + 1] && 
                world[position.x + 1][position.y + 1].props["alive"]) neighboursCount++;

            if (world[position.x - 1] && world[position.x - 1][position.y - 1] && 
                world[position.x - 1][position.y - 1].props["alive"]) neighboursCount++;

            if (world[position.x + 1] && world[position.x + 1][position.y - 1] && 
                world[position.x + 1][position.y - 1].props["alive"]) neighboursCount++;

            if (cellStatus) {
                if (neighboursCount < 2) return false;
                if (neighboursCount === 2 || neighboursCount === 3) return true;
                if (neighboursCount > 3) return false;
            }
            else if (!cellStatus && neighboursCount === 3) return true;
            else return false;
        }

        setInterval(() => {
            this.render.clearStage();
            for (let i = 0; i < matrix.length; i++) {
                for (let j = 0; j < matrix.length; j++) {
                    let alive = isAlive(new Point(i, j), matrix);
                    if (alive) {
                        bufferMatrix[i][j].color = "black";
                        bufferMatrix[i][j].props["alive"] = true;
                    }
                    else {
                        bufferMatrix[i][j].props["alive"] = false;
                        bufferMatrix[i][j].color = "white";
                    }
                    this.render.requestStage(matrix[i][j]);
                }
            }
            // Matching properties from bufferedMatrix and matrix without losing reference.
            for (let i = 0; i < matrix.length; i++) {
                for (let j = 0; j < matrix.length; j++) {
                    matrix[i][j].color = bufferMatrix[i][j].color;
                    matrix[i][j].props["alive"] = bufferMatrix[i][j].props["alive"];
                }
            }
        }, 100);
    }
...