2017-08-25 69 views
1

因此,我正在制作一个模拟类似生命的细胞自动机的程序,但我在计算细胞活的邻居时使用了一些方法。问题是我希望能够改变网格如何环绕 - 也就是说,它是否从左到右包围从左到右(即圆柱形),从顶部到底部从左到右(即环形)或根本不是(即,平坦的) - 我无法弄清楚如何使我的方法说明。这是我到目前为止有:如何使用环绕计数细胞自动机中的细胞邻居

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++; 
} 

的关键,我认为,是for -loop的if语句来 - 必须有某种方式来检查rc是否的边界内网格,同时牢记“边界”的定义将根据网格是否/如何环绕而变化。在过去,我已经通过对八个不同的if-陈述分别检查由原始细胞的邻域组成的八个细胞中的每一个而有三个不同的组(每个环绕设置一个)正如你可以想象的那样,它不是很漂亮,但至少它工作。

我不是很擅长解释我自己的代码,所以我希望这不是太混乱 - 我自己感觉有点傻(哈哈)。如果有人有任何问题,随时问!

回答

0

你可能已经有一个像Board这样的类,像getCell(x, y)这样的方法(至少这种方法存在于你的代码中)。

我只是让这种方法在某种意义上宽松,它将接受负xyxy大于或等于COLSROWS。因此,您只需重复col - 1col + 1row - 1row + 1(减号为colrow),而不用担心这些坐标会“全盘”。这是Board正确执行坐标查找的任务。

什么让你的代码更难以处理不同的拓扑在一个地方。这很难遵循。

您可以通过实施Board的不同子类来简化操作,如CylindricalBoard,ToroidalBoardFlatBoard。每个子类都会实现getCell的不同,但在子类的上下文中,它将显而易见。

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); 
    } 
} 
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; 
    } 
} 
+0

好,我也去了快这里是因为x和y的负指数情况(网格从0,0开始)。另外,事实证明Java%操作符返回一个余数而不是一个合适的模数。这与负数有关(例如-1%4 = -1而不是3)。 Math.floorMod会产生正确的行为。请参阅上面的替换案例声明。 – stegzzz