大家可能看完翁愷老師的課程會對於細胞自動機想要真正的源代碼,現在就展示各個類的源代碼。
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?
本人現在還是沒有弄清這幾個問題的解,還希望各位知道的小夥伴們能夠在評論區中指點迷津。