如何计算细胞自动机中的细胞邻居与环绕

时间:2017-08-25 19:20:21

标签: java cellular-automata

所以我正在制作一个模拟类似生命的细胞自动机的程序,但是我在使用计算细胞活近邻的方法时遇到了一些麻烦。问题是我希望能够改变网格环绕的方式 - 也就是说,它是否从从左到右(即圆柱形)包裹,从从上到下< / strong>和从左到右(即环形),或根本不是(即平坦) - 我无法弄清楚如何制作我的方法说明这一点。这是我到目前为止所做的:

public int getLiveNeighbors(int row, int col)
{
    int count = 0;

    // "topology" is an int that represents wraparound:
    // 0 = flat; 1 = cylindrical; 2 = toroidal
    int top = topology != 2 ? row - 1 : (row + ROWS - 1) % ROWS;
    int bottom = topology != 2 ? row + 1 : (row + 1) % ROWS;
    int left = topology != 0 ? (col + COLS - 1) % COLS : col - 1;
    int right = topology != 0 ? (col + 1) % COLS : col + 1;

    for (int r = top; r < bottom + 1; r++)
        for (int c = left; c < right + 1; c++)
            if (!(r == row && c == col) && getCell(r, c).equals(LIVE))
                count++;
}

我认为关键是if循环中的for - 语句 - 必须有一些方法来检查rc是否为if在网格的范围内,同时记住“边界”的定义将根据网格是否/如何环绕而变化。在过去,我通过为八个不同的['12,-1', '0.01,3']语句设置三个不同的集合(每个环绕设置一个)来解决这个问题,以单独检查包含原始单元格邻域的八个单元格中的每一个;你可以想象,它不是很漂亮,但至少它起作用了。

我不太擅长解释自己的代码,所以我希望这不会太混乱 - 我自己感觉有点笨拙(ha)。如果有人有任何问题,请随时提问!

3 个答案:

答案 0 :(得分:0)

您可能已经拥有类似Board的类,其方法类似getCell(x, y)(您的代码中至少存在此类方法)。

我只是将这种方法设为宽松,因为它会接受负xyxy大于或等于COLS }和ROWS。因此,你可以迭代col - 1col + 1row - 1row + 1(减去colrow)并不关心这些坐标是什么“全面”。 Board的任务是正确地进行坐标查找。

使您的代码更难的原因是您在一个地方处理不同的拓扑。这很难说。

您可以通过实现BoardCylindricalBoardToroidalBoardFlatBoard的不同子类来简化这一过程。每个子类都会以不同的方式实现getCell,但在子类的上下文中,它将是清楚可以理解的。

答案 1 :(得分:0)

您正在寻找Strategy Pattern

  

通常情况下,班级的行为只有不同。对于这种情况,最好将算法隔离在不同的类中,以便能够在运行时选择不同的算法。

在这种情况下,你需要这样的东西(为了清晰起见缩写):

class Point {
    int x;
    int y;
}
interface WrapStrategy {
    Point moveUp(Point p);
    Point moveDown(Point p);
    Point moveLeft(Point p);
    Point moveRight(Point p);
}
class CylinderWrapping implements WrapStrategy {
    int height;
    int circumference;
    Point moveUp(Point p) {
        if (p.y <= 0)
            return null; // cannot move up
        return new Point(p.x, p.y - 1);
    }
    Point moveDown(Point p) {
        if (p.y >= height - 1)
            return null; // cannot move down
        return new Point(p.x, p.y + 1);
    }
    Point moveLeft(Point p) {
        if (p.x <= 0)
            return new Point(circumference - 1, p.y);
        return new Point(p.x - 1, p.y);
    }
    Point moveRight(Point p) {
        if (p.x >= circumference - 1)
            return new Point(0, p.y);
        return new Point(p.x + 1, p.y);
    }
}

答案 2 :(得分:0)

试试这个:

import java.awt.Point;

public class Neighbours {

    public static void main(String[] args) {
        Neighbours inst=new Neighbours();
        int r=3;//<ROWS
        int c=3;//<COLS
        for(int i :new int[]{0,1,2}){
            inst.type=i;
            System.out.format("There are %d neighbours of point (%d,%d), topography type %d\n", inst.countLiveNeighbours(r, c), c, r,i);
        }
    }

    int ROWS=4;
    int COLS=4;
    int type=0;//0=flat, 1=cylinder, 2=toroid

    /**
     * Is x,y a neighbour of r,c?
     * @return coordinates of neighbour or null
     */
    Point neighbour(int x, int y, int r, int c){
        if((x==c)&&(y==r))
            return null;
        switch (type){
/*this is wrong for the reasons explained below
        case 0: return ((x<COLS)&&(y<ROWS)) ? new Point (x,y) : null;
        case 1: return y<ROWS ? new Point(x%COLS,y) : null;
        case 2: return new Point(x%COLS,y%ROWS);
*/
 //replacement statements produce the correct behaviour
    case 0: return ((x<COLS)&&(x>-1)&&(y<ROWS)&&(y>-1)) ? new Point (x,y) : null;
    case 1: return ((y<ROWS)&&(y>-1)) ? new Point(Math.floorMod(x,COLS),y) : null;
    case 2: return new Point(Math.floorMod(x,COLS),Math.floorMod(y,ROWS));
        }
        return null;
    }

    int countLiveNeighbours(int r, int c){
        int result=0;
        for(int x=c-1; x<c+2; x++)
            for(int y=r-1; y<r+2; y++){
                Point p=neighbour(x,y,r,c);
                if(live(p)){
                    System.out.format("\tpoint (%d,%d)\n",(int)p.getX(),(int)p.getY());
                    result++;
                }
            }
        return result;
    }

    boolean live(Point p){
        boolean result=true;
        if(p==null)
            return false;
        //perform tests for liveness here and set result
        return result;
    }
}