细胞自动机的java实现
一丶
先说说这个题目吧,还是第一次接触这种类型的题目:生命游戏中,对于任意细胞,规则如下:
每个细胞有两种状态-存活或死亡,每个细胞与以自身为中心的周围八格细胞产生互动。
当前细胞为存活状态时,当周围低于2个(不包含2个)存活细胞时, 该细胞变成死亡状态。(模拟生命数量稀少)
当前细胞为存活状态时,当周围有2个或3个存活细胞时, 该细胞保持原样。
当前细胞为存活状态时,当周围有3个以上的存活细胞时,该细胞变成死亡状态。(模拟生命数量过多)
当前细胞为死亡状态时,当周围有3个存活细胞时,该细胞变成存活状态。 (模拟繁殖)
可以把最初的细胞结构定义为种子,当所有在种子中的细胞同时被以上规则处理后, 可以得到第一代细胞图。按规则继续处理当前的细胞图,可以得到下一代的细胞图,周而复始。
二丶
1.看到这个题目的第一反应是将整个生命环境看作一个矩阵,其中的每一个细胞以二维坐标的形式存在于环境中,那么这个细胞类就有三个属性在生命游戏中的:x坐标,y坐标,生命状态。但是,这样做了以后发现两个问题:
1)环境边界处的细胞生命状态判断实现很难。
2)细胞之间的生命状态无法实现关联关系。
2.之后是将单个细胞单独做一个(BasicUnit类),还是以3*3九宫格的方式判段我们抽象出来的单元细胞的生命状态,再将其放入生命游戏沙盘(LifeGame类)中演变,当然,还是写一个细胞信息类(Cell类)将从BasicUnit类中判断得来的细胞生命状态和在LifeGame类中的坐标两个信息存储起来。
3.到此,整个生命游戏的实现逻辑就构建好了,接下来就是编码实现的事情了。
4.编码过程中遇到很多坑,这里就不多提了,碰到的坑都是为了以后少进坑做贡献。
5.下面讲这三个类代码贴出来(不能直接跑,用了单元测试,测试每个类的逻辑是否实现,要跑的话需要自己写一个run类)
BasicUnit类:
package org.coach.tdd.template;
/**
* Created by lzy on 17-6-3.
*/
/**
* BasicUnit类判断单元细胞的生命状态。
*/
public class BasicUnit {
private static final int DEATH = 0;
private static final int LIVE = 1;
private int[][] testUnit = new int[3][3]; //将一个细胞及其周围相邻细胞看作一个基本单元
private int status = DEATH;
public void setTestUnit(int[][] testUnit) {
this.testUnit = testUnit;
}
/**
* .
* 获得单元细胞生命状态
*
* @param basicUnit 该细胞周围细胞生命状态
* @return 该细胞生命状态
*/
public int getUnitCelltatus(int[][] basicUnit) {
int numberofcell = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (1 == basicUnit[i][j]) {
if (1 == i && 1 == j) {
} else {
numberofcell += 1;
}
}
}
}
if (3 == numberofcell) {
return 1;
} else if (2 == numberofcell) {
return basicUnit[1][1];
}
return 0;
}
}
Cell类:
package org.coach.tdd.template;
/**
* Created by lzy on 17-6-3.
*/
/**
* Cell类存储细胞的坐标,生命状态,周围细胞状态。
*/
public class Cell {
private int location_x = 0;
private int location_y = 0;
private int cellStatus = 0;
private int[][] aroundCells = new int[3][3];
/**
* 构造方法的描述
*
* @param location_x 细胞的x坐标
* @param location_y 细胞的y坐标
* @param cellStatus 细胞的状态
*/
public Cell(int location_x, int location_y, int cellStatus) {
this.location_x = location_x;
this.location_y = location_y;
this.cellStatus = cellStatus;
}
public int getLocation_x() {
return location_x;
}
public int getLocation_y() {
return location_y;
}
public int getCellStatus() {
return cellStatus;
}
public void setCellStatus(int cellStatus) {
this.cellStatus = cellStatus;
}
/**
* 获取更新后的细胞状态
*
* @return
*/
public int getAfterTurnCellStatus() {
BasicUnit basicUnit = new BasicUnit();
this.setCellStatus(basicUnit.getUnitCelltatus(aroundCells));
return this.getCellStatus();
}
}
LifeGame类:
package org.coach.tdd.template;
/**
* Created by lzy on 17-6-3.
*/
/**
* LifeGame类生命游戏具体操作类
*/
public class LifeGame {
public static final int LEFTUP = 1;
public static final int RIGHTUP = 2;
public static final int LEFTDOWN = 3;
public static final int RIGHTDOWN = 4;
private int framesize = 0; //框架大小,表示为正方体框架的边长
private int[][] frame;
private int[][] nextframe;
public LifeGame(int framesize) {
this.framesize = framesize;
}
public int[][] getNextframe() {
return nextframe;
}
public void setFrame(int[][] frame) {
this.frame = frame;
}
public void init() {
frame = new int[framesize][framesize];
nextframe = new int[framesize][framesize];
}
public void putCell(Cell cell) {
frame[cell.getLocation_x()][cell.getLocation_y()] = cell.getCellStatus();
}
public int locationIsCorner(int x, int y) {
if (0 == x && 0 == y) {
return LEFTUP;
} else if (0 == x && framesize - 1 == y) {
return RIGHTUP;
} else if (framesize - 1 == x && 0 == y) {
return LEFTDOWN;
} else if (framesize - 1 == x && framesize - 1 == y) {
return RIGHTDOWN;
}
return 0;
}
public int locationIsLine(int x, int y) {
if (0 == x && 0 != y && framesize - 1 != y) {
return 11;
} else if (framesize - 1 == x && 0 != y && framesize - 1 != y) {
return 12;
} else if (0 == y && 0 != x && framesize - 1 != x) {
return 13;
} else if (framesize - 1 == y && 0 != x && framesize - 1 != x) {
return 14;
}
return 0;
}
/**
* 获取指定坐标细胞周围细胞状态
*
* @param x cell_x坐标
* @param y cell_y坐标
* @return 指定坐标细胞周围细胞状态
*/
public int[][] getAroundStatus(int x, int y) {
//corner
int[][] aroundUnit = new int[3][3];
int isCorner = locationIsCorner(x, y);
int isLine = locationIsLine(x, y);
if (isCorner != 0) {
switch (isCorner) {
case 1: {
aroundUnit = new int[][]{{frame[x][y + 1], frame[x + 1][y], frame[x + 1][y + 1]}, {0, frame[x][y], 0}, {0, 0, 0}};
break;
}
case 2: {
aroundUnit = new int[][]{{frame[x][y - 1], frame[x + 1][y - 1], frame[x + 1][y]}, {0, frame[x][y], 0}, {0, 0, 0}};
break;
}
case 3: {
aroundUnit = new int[][]{{frame[x - 1][y], frame[x - 1][y + 1], frame[x][y + 1]}, {0, frame[x][y], 0}, {0, 0, 0}};
break;
}
case 4: {
aroundUnit = new int[][]{{frame[x - 1][y], frame[x - 1][y - 1], frame[x][y - 1]}, {0, frame[x][y], 0}, {0, 0, 0}};
break;
}
default:
break;
}
}
//line
else if (isLine != 0) {
switch (isCorner) {
case 11: {
aroundUnit = new int[][]{{frame[x][y - 1], frame[x][y + 1], frame[x + 1][y - 1]}, {frame[x + 1][y], frame[x][y], frame[x + 1][y + 1]}, {0, 0, 0}};
break;
}
case 12: {
aroundUnit = new int[][]{{frame[x - 1][y - 1], frame[x - 1][y], frame[x - 1][y + 1]}, {frame[x][y - 1], frame[x][y], frame[x][y + 1]}, {0, 0, 0}};
break;
}
case 13: {
aroundUnit = new int[][]{{frame[x - 1][y], frame[x - 1][y + 1], frame[x][y + 1]}, {frame[x + 1][y], frame[x][y], frame[x + 1][y + 1]}, {0, 0, 0}};
break;
}
case 14: {
aroundUnit = new int[][]{{frame[x - 1][y - 1], frame[x - 1][y], frame[x][y - 1]}, {frame[x + 1][y - 1], frame[x][y], frame[x + 1][y]}, {0, 0, 0}};
break;
}
default:
break;
}
} else {
aroundUnit = new int[][]{{frame[x - 1][y - 1], frame[x - 1][y], frame[x - 1][y + 1]}, {frame[x][y - 1], frame[x][y], frame[x][y + 1]}, {frame[x + 1][y - 1], frame[x + 1][y], frame[x + 1][y + 1]}};
}
return aroundUnit;
}
/**
* 更新环境中所有细胞生命状态
*
* @return 环境中是否还在活着的细胞
*/
public boolean isfreshFrame() {
// boolean flag =false;
boolean hasLife = false;
BasicUnit basicUnit = new BasicUnit();
for (int i = 0; i < framesize; i++) {
for (int j = 0; j < framesize; j++) {
int[][] aroundUnit = getAroundStatus(i, j);
int status = basicUnit.getUnitCelltatus(aroundUnit);
nextframe[i][j] = status;
}
}
for (int i = 0; i < framesize; i++) {
for (int j = 0; j < framesize; j++) {
System.out.print(frame[i][j]);
}
System.out.println("");
}
System.out.println("");
for (int i = 0; i < framesize; i++) {
for (int j = 0; j < framesize; j++) {
if (1 == nextframe[i][j]) {
hasLife = true;
}
System.out.print(nextframe[i][j]);
}
System.out.println("");
}
// flag=true;
return hasLife;
}
/**
* 运行整个生命游戏
*
* @param lifeGame 生命游戏的初始对象
* @return 运行成功
*/
public boolean run(LifeGame lifeGame) {
while (lifeGame.isfreshFrame()) {
lifeGame.setFrame(lifeGame.getNextframe());
System.out.println("");
}
return true;
}
}
最后附上该项目github地址:github地址
小结:博客为个人学习之余沉淀所学知识所用,有纠正之处,劳烦大家指出,共同进步。