生命游戏Java实现

来源:互联网 发布:西瓜影音mac 编辑:程序博客网 时间:2024/05/17 21:44

关于生命游戏

之前在学校看到ThoughtWorks举办的线下结对编程的比赛一等奖是大疆无人机,冲着无人机就拉着实验室小伙伴马总一起报了个名。然后题目就是实现一个界面版的生命游戏,所以才了解了生命游戏。
关于生命游戏,可以参考维基百科。
下图是效果图:

规则

生命游戏中,对于任意细胞,规则如下:
每个细胞有两种状态-存活或死亡,每个细胞与以自身为中心的周围八格细胞产生互动。(如图,黑色为存活,白色为死亡)
当前细胞为存活状态时,当周围低于2个(不包含2个)存活细胞时, 该细胞变成死亡状态。(模拟生命数量稀少)

当前细胞为存活状态时,当周围有2个或3个存活细胞时, 该细胞保持原样。

当前细胞为存活状态时,当周围有3个以上的存活细胞时,该细胞变成死亡状态。(模拟生命数量过多)

当前细胞为死亡状态时,当周围有3个存活细胞时,该细胞变成存活状态。 (模拟繁殖)
可以把最初的细胞结构定义为种子,当所有在种子中的细胞同时被以上规则处理后, 可以得到第一代细胞图。按规则继续处理当前的细胞图,可以得到下一代的细胞图,周而复始。

根据上面的规则得出下面的代码:

 /**     * 上一个状态到下一个状态的转移     * 根据规则可以总结得出两条规则:     * 1. 对于周围活着的细胞为3的情况,下一个状态该细胞总是为活     * 2. 对于周围活着的细胞为2的情况,下一个状态与上一状态相同     */    public void transform(){        int[][] nextMatrix=new int[height][width];        for (int y = 0; y < matrix.length; y++) {            for (int x = 0; x < matrix[0].length; x++) {                nextMatrix[y][x]=0;                int nearNum= findLifedNum(y,x);                //等于3,则下一状态总是活                if(nearNum==3){                    nextMatrix[y][x]=1;                }                //等于2,则与上一状态一样                else if(nearNum==2){                    nextMatrix[y][x]=matrix[y][x];                }            }        }        matrix=nextMatrix;    }    /**     * 统计每个细胞周围活着的个数     * @param x 横坐标     * @param y 纵坐标     * @return     */    public int findLifedNum(int y, int x){        int num=0;        //左边        if(x!=0){            num+=matrix[y][x-1];        }        //左上角        if(x!=0&&y!=0){            num+=matrix[y-1][x-1];        }        //上边        if(y!=0){            num+=matrix[y-1][x];        }        //右上        if(x!=width-1&&y!=0){            num+=matrix[y-1][x+1];        }        //右边        if(x!=width-1){            num+=matrix[y][x+1];        }        //右下        if(x!=width-1&&y!=height-1){            num+=matrix[y+1][x+1];        }        //下边        if(y!=height-1){            num+=matrix[y+1][x];        }        //左下        if(x!=0&&y!=height-1){            num+=matrix[y+1][x-1];        }        return num;    }

实现

首先看我们做的效果,如下图:

关于初始状态的输入

初始状态是通过文件加载的方式来实现的,为了加载很多的情况,又写了一个工具类负责随机产生case,代码如下:

/**     * 创建测试案例     */    private static void createCaseFile() {        Random random = new Random();        int rows = 1 + random.nextInt(100);        int cols = 1 + random.nextInt(100);        int duration = 200;        int num = 300;        File file = new File(cols+"_"+rows+"_"+System.nanoTime() + ".txt");        PrintWriter writer = null;        try {            writer = new PrintWriter(new FileWriter(file));            StringBuilder sb = new StringBuilder(cols + " " + rows + " " + duration + " " + num);            writer.write(sb.append("\n").toString());            //开始逐行初始化            for (int y = 0; y < rows; y++) {                sb = new StringBuilder();                for (int x = 0; x < cols; x++) {                    if (random.nextInt(3) % 3 == 0) {                        sb.append("1 ");                    } else {                        sb.append("0 ");                    }                }                sb.deleteCharAt(sb.length()-1).append("\n");                writer.write(sb.toString());            }        } catch (IOException e) {            e.printStackTrace();        } finally {            if (writer != null) {                writer.close();            }        }    }

关于界面

使用的Swing编程,java的界面做出来确实不咋的。不过我们加入了暂停、继续功能,这个是通过控制一个变量来做的,每两帧动画之间通过线程睡眠实现的。核心代码如下:

 private class GameControlTask implements Runnable {        @Override        public void run() {            while (!stop) {                cellMatrix.transform();                showMatrix();                try {                    TimeUnit.MILLISECONDS.sleep(duration);                } catch (InterruptedException ex) {                    ex.printStackTrace();                }            }        }    }

其中cellMatrix代表了一帧的状态,调用transform()将会进行下一次变换,showMatrix负责更新界面。

总结

最后,由于界面比较酷炫,可以支持暂停、继续功能,代码结构比较优美及注释比较完整,最后和我的小伙伴拿了个无人机,还是挺爽的。
关于代码,可以参考TxGameOfLife。