所以我正在制作一个模拟类似生命的细胞自动机的程序,但是我在使用计算细胞活近邻的方法时遇到了一些麻烦。问题是我希望能够改变网格环绕的方式 - 也就是说,它是否从从左到右(即圆柱形)包裹,从从上到下< / 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
- 语句 - 必须有一些方法来检查r
和c
是否为if
在网格的范围内,同时记住“边界”的定义将根据网格是否/如何环绕而变化。在过去,我通过为八个不同的['12,-1', '0.01,3']
语句设置三个不同的集合(每个环绕设置一个)来解决这个问题,以单独检查包含原始单元格邻域的八个单元格中的每一个;你可以想象,它不是很漂亮,但至少它起作用了。
我不太擅长解释自己的代码,所以我希望这不会太混乱 - 我自己感觉有点笨拙(ha)。如果有人有任何问题,请随时提问!
答案 0 :(得分:0)
您可能已经拥有类似Board
的类,其方法类似getCell(x, y)
(您的代码中至少存在此类方法)。
我只是将这种方法设为宽松,因为它会接受负x
和y
或x
和y
大于或等于COLS
}和ROWS
。因此,你可以迭代col - 1
到col + 1
和row - 1
到row + 1
(减去col
和row
)并不关心这些坐标是什么“全面”。 Board
的任务是正确地进行坐标查找。
使您的代码更难的原因是您在一个地方处理不同的拓扑。这很难说。
您可以通过实现Board
,CylindricalBoard
和ToroidalBoard
等FlatBoard
的不同子类来简化这一过程。每个子类都会以不同的方式实现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;
}
}