细胞自动机的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;
- }
- }
复制代码 表现与数据分离
表现与数据数据分离
表现:顾名思义,就是表达出来的现象,在前端来看,就是html+css,就是平常所看到的的网页的架子;
数据:一般是从后端数据库或从哪爬过来的数据,然后在前台显示出来,即是网页中各个结构上的内容;
好处与坏处
好处:模块化 –> 容易测试 –> 降低bug频率;
坏处:程序结构复杂,比较耗时,上手有学习曲线;
应用场景:
项目具有明显的数据需求,比如要与很多Service交互,业务流程复杂,表单很多
非应用场景:
项目是典型的静态信息展示型页面,或是微型的内部app,或是产品idea验证时期的MVP。- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <title></title>
-
-
- </head>
- <body>
- <select id="pili">
- <option value="叶小钗">叶小钗</option>
- <option value="一页书">一页书</option>
- <option value="素还真">素还真</option>
- </select>
-
- </body>
- </html>
复制代码
- 我们好像就在view中使用了选择器获取dom。
- 我们的数据似乎在model中,我们可以随意改变,但是并不会影响到我们dom。
- view和model是完全独立的,我们的controller恰好把他们串联起来了。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |