大家可能看完翁恺老师的课程会对于细胞自动机想要真正的源代码,现在就展示各个类的源代码。
cellmachine/CellMachine.java
package cellmachine;
import javax.swing.JFrame;
import cell.Cell;
import field.View;
import field.Field;
public class CellMachine {
public static void main(String[] args) {
Field field = new Field(30,30);
for( int row = 0; row<field.getHeight(); row++ ) {
for( int col = 0; col<field.getWidth(); col++ ) {
field.place(row, col, new Cell());
}
}
for( int row = 0; row<field.getHeight(); row++ ) {
for( int col = 0; col<field.getWidth(); col++ ) {
Cell cell = field.get(row, col);
if( Math.random() < 0.2 ) {
cell.reborn();
}
}
}
View view = new View(field);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setTitle("Cells");
frame.add(view);
frame.pack();
frame.setVisible(true);
for( int i = 0; i<1000; i++ ) {
for( int row = 0; row<field.getHeight(); row++ ) {
for( int col = 0; col<field.getWidth(); col++ ) {
Cell cell = field.get(row, col);
Cell[] neighbour = field.getNeighbour(row, col);
int numOfLive = 0;
for( Cell c : neighbour ) {
if( c.isAlive() ) {
numOfLive++;
}
}
System.out.print("["+row+"]"+"["+col+"]:");
System.out.print(cell.isAlive()?"live":"dead");
System.out.print(":"+numOfLive+"-->");
if( cell.isAlive() ) {
if( numOfLive<2 || numOfLive>3 ) {
cell.die();
System.out.print("die");
}
}else if( numOfLive == 3 ) {
cell.reborn();
System.out.print("reborn");
}
System.out.println();
}
}
System.out.print("UPDATE");
frame.repaint();
try {
Thread.sleep(200);
}catch( InterruptedException e) {
e.printStackTrace();
}
}
}
}
cell/Cell.java
package cell;
import java.awt.Graphics;
public class Cell {
private boolean alive = false;
public void die() { alive = false; }
public void reborn() { alive = true; }
public boolean isAlive() { return alive; }
public void draw(Graphics g, int x, int y, int size) {
g.drawRect(x, y, size, size);
if( alive ) {
g.fillRect(x, y, size, size);
}
}
}
field/View.java
package field;
import java.awt.Dimension;
public class View extends JPanel {
private static final long serialVersionUID = -5258995676212660595L;
private static final int GRID_SIZE = 16;
private Field theField;
public View(Field field) {
theField = field;
}
@Override
public void paint(Graphics g) {
super.paint(g);
for( int row = 0; row<theField.getHeight(); row++ ) {
for( int col = 0; col<theField.getWidth(); col++ ) {
Cell cell = theField.get(row, col);
if( cell != null) {
cell.draw(g, col*GRID_SIZE, row*GRID_SIZE, GRID_SIZE);
}
}
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(theField.getWidth()*GRID_SIZE+1, theField.getHeight()*GRID_SIZE+1);
}
public static void main(String[] args) {
Field field = new Field(10,10);
for( int row = 0; row<field.getHeight(); row++ ) {
for( int col = 0; col<field.getWidth(); col++ ) {
field.place(row, col, new Cell());
}
}
View view = new View(field);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setTitle("Cells");
frame.add(view);
frame.pack();
frame.setVisible(true);
}
}
field/Field.java
package field;
import java.util.ArrayList;
import cell.Cell;
public class Field {
private int width;
private int height;
private Cell[][] field;
public Field (int width,int height) {
this.width = width;
this.height = height;
field = new Cell[height][width];
}
public int getHeight() { return height; }
public int getWidth() { return width; }
public Cell place(int row, int col, Cell o) {
Cell ret = field[row][col];
field[row][col] = o;
return ret;
}
public Cell[] getNeighbour(int row, int col) {
ArrayList<Cell> list = new ArrayList<Cell>();
for( int i = -1; i<2; i++ ) {
for( int j = -1; j<2; j++ ) {
int r = row+i;
int c = col+j;
if( r>-1 && r<height && c>-1 && c<width && !(r == row && c == col)) {
list.add(field[r][c]);
}
}
}
return list.toArray(new Cell[list.size()]);
}
public Cell get(int row, int col) {
return field[row][col];
}
public void clear() {
for( int i = 0; i<height; i++ ) {
for( int j = 0; j<width; j++ ) {
field[i][j] = null;
}
}
}
}
老师在最后还说到了几个点:
数据与表现分离
程序业务逻辑与表现无关
表现可以是图形的也可以是文本的
表现可以是当地的也可以是远程的
View和Field的关系
表现与数据的关系
View只管根据Field画出图形
Field只管数据的存放
一旦数据更新以后,通知View重新画出整个画面
不去精心设计哪个局部需要更新
这样简化了程序逻辑
是在计算机运算速度提高的基础上实现的
责任驱动的设计
将程序要实现的功能分配到合适的类/对象中去是设计中非常重要的一环
网格化
图形界面本身有更多的解析度
但是将画面格式化以后,数据就更容易处理了
同时,也提出了几个问题:
问题0
为什么不是在Cell中提供setAlive(boolean)函数?
卫视采用复杂的die()、reborn()两个函数?
问题1
为什么Field.getNeighbour()不直接看Cell。isAlive来返回一个数字,而是要返回一个数组让外面来数数?
问题2
为什么不是由Cell自己判断自己的邻居的情况来决定自己是否应该被die或reborn?
本人现在还是没有弄清这几个问题的解,还希望各位知道的小伙伴们能够在评论区中指点迷津。