Life game

The game of life is the most famous set of rules in Cellular Automaton. It consists of a two-dimensional array of cells, each of which can be ‘alive’ or ‘dead’. And for any one cell, it has eight neighbors.

The rules of the game

After initialization, the game of life evolves and multiplies according to the following rules:

Each cell ‘lives’ or’ dies’ depending on the state of its eight neighbors.

  • “Underpopulation” : Any living cell that has fewer than two living neighbors dies.
  • “Normal” : Any living cell continues to live if it has two or three living neighbors.
  • “Overpopulation” : Any living cell that has more than three living neighbors dies.
  • “Reproduction” : Any dead cell will survive if it has exactly three living neighbors.

Demand for design

At the beginning of the game, it is necessary to dynamically set the size (length and width) of the cell array, randomly or set the initial cell, optionally set the upper limit of cell reproduction algebra, and then continuously evolve and reproduce until the state is stable or reaches the upper limit.

Logical text description

Given the current cell array, traverse each cell, judge the survival and preservation of the cell in the next generation according to the situation of its neighbors. After traversal, judge whether there is any difference between the current generation and the next generation or whether the number of iterations reaches the upper limit. If you need to continue evolution, name the next generation as the current generation and perform the above logic.

Need to implement

The project framework

mvn archetype:generate -DgroupId=com.zju -DartifactId=TheGameOfLife -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false -DarchetypeCatalog=internalCopy the code

The core code

Entity class

Cell array class, indicating the size of the array and the state of a generation of cells.

/** * CellularArray */ public class CellularArray {private int[][] cells; private int row; private int col; public CellularArray() { } public CellularArray(int row, int col) { this.row = row; this.col = col; this.cells = new int[row][col]; }... public int getCell(int x, int y) { if (x < 0 || this.row <= x || y < 0 || this.col <= y) { return -1; } return this.cells[x][y]; } public boolean setCell(int x, int y, int cell) { if (x < 0 || this.row <= x || y < 0 || this.col <= y) { return false;  } this.cells[x][y] = cell; return true; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (this.getClass() ! = obj.getClass()) return false; CellularArray other = (CellularArray) obj; if (this.row ! = other.getRow() || this.col ! = other.getCol()) return false; for (int i = 0; i < this.row; ++i) { for (int j = 0; j < this.col; ++j) { if (this.cells[i][j] ! = other.getCell(i, j)) { return false; } } } return true; }}Copy the code

Cell state enumeration class, specifically defines the state of the cell, keep the code readable.

/** * CellState */ public enum CellState {DEAD(0), LIVE(1); private int value; CellState(int value) { this.value = value; } public int getValue() { return value; }}Copy the code
The Service class
package com.zju.service; import com.zju.meta.CellState; import com.zju.meta.CellularArray; import org.springframework.stereotype.Service; import java.util.Random; @service public class TheGameOfLifeService {// direction array private int[] direct = {-1, 0, 1}; * @param now cell array * @param x * @param y * @return */ private int countLiveNeighbor(CellularArray now, int x, int y) { int count = 0; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (CellState.LIVE.getValue() == now.getCell(x + this.direct[i], y + this.direct[j])) { ++count; } } } if (CellState.LIVE.getValue() == now.getCell(x, y)) { --count; } return count; } @param now cell array @return */ public CellularArray generate(CellularArray now) {if (null == now) { return null; } int liveCount; CellularArray next = new CellularArray(now.getRow(), now.getCol()); for (int i = 0; i < next.getRow(); ++i) { for (int j = 0; j < next.getCol(); ++j) { liveCount = this.countLiveNeighbor(now, i, j); If (CellState. LIVE. GetValue () = = now. The getCell (I, j) && (liveCount < 2 | | liveCount > 3)) {/ / population too little, overpopulation next setCell (I, j, CellState.DEAD.getValue()); } else if (cellState.live.getValue () == now.getCell(I, j) && (2 <= liveCount && liveCount <= 3)) {// normal next.setcell (I, j, CellState.LIVE.getValue()); } else if (cellState.dead.getValue () == now.getCell(I, j) && (3 == liveCount)) {// Multiply next.setcell (I, j, CellState.LIVE.getValue()); } } } return next; } /** * Given a cell array, yields a random result * @param cellularArray cell array * @return */ public cellularArray randInit(cellularArray) cellularArray) { if (null == cellularArray) return null; Random r = new Random(); int value; for (int i = 0; i < cellularArray.getRow(); ++i) { for (int j = 0; j < cellularArray.getCol(); ++j) { value = r.nextInt(2); cellularArray.setCell(i, j, value); } } return cellularArray; } @param cellularArray * @return */ public cellularArray emptyInit(cellularArray cellularArray) {  if (null == cellularArray) return null; for (int i = 0; i < cellularArray.getRow(); ++i) { for (int j = 0; j < cellularArray.getCol(); ++j) { cellularArray.setCell(i, j, CellState.DEAD.getValue()); } } return cellularArray; }}Copy the code
The Controller class
package com.zju.controller;
import com.zju.meta.CellularArray;
import com.zju.service.TheGameOfLifeService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
@Controller
@RequestMapping("/")
public class TheGameOfLifeController {
    private static final int defaultRow = 15;
    private static final int defaultCol = 15;
    @Resource
    private TheGameOfLifeService service;
    @ResponseBody
    @RequestMapping("/randInit")
    public Object getRandInit(@RequestParam(required = false) Integer row, @RequestParam(required = false) Integer col) {
        if (null == row) row = defaultRow;
        if (null == col) col = defaultCol;
        CellularArray cellularArray = service.randInit(new CellularArray(row, col));
        return cellularArray;
    }
    @ResponseBody
    @RequestMapping("/generate")
    public Object generate(@RequestBody CellularArray now) {
        CellularArray next = service.generate(now);
        return next;
    }
    @ResponseBody
    @RequestMapping("/empty")
    public Object empty(@RequestParam(required = false) Integer row, @RequestParam(required = false) Integer col) {
        if (null == row) row = defaultRow;
        if (null == col) col = defaultCol;
        CellularArray next = service.emptyInit(new CellularArray(row,col));
        return next;
    }
}Copy the code
The Spring configuration

Spring-mvc configures FastJSON as a JSON converter and also configures support for text/ Plain and Application/JSON media types.




    
        
            
                
                    text/plain
                    application/json
                
            
            
                
                    WriteMapNullValue
                    DisableCircularReferenceDetect
                    WriteDateUseDateFormat
                
            
        
    
Copy the code
Web configuration

    The Game Of Life
    
        spring-mvc
        org.springframework.web.servlet.DispatcherServlet
        
            contextConfigLocation
            classpath:Spring/*.xml
        
        1
    
    
        spring-mvc
        /backend/*
    
    
        /index.html
    
Copy the code
Display the page

The HTML file



    
    
    
    The Game Of Life
    
    
    
    



     
The length of the
The width of the
The current algebra.
Random initialization algebraic zeroing cell zeroing reproduction
Copy the code

Javascript files

In the Ajax configuration, set dataType: “JSON” and contentType: “Application/JSON” to unify the data transfer format with the backend.

var cellularArray; Function createTable(cellularArray) {$("#table").empty(); var rowCount = cellularArray.row; var colCount = cellularArray.col; var table = $(""); table.appendTo($("#table")); var cells = cellularArray.cells; for (var i = 0; i < rowCount; ++i) { var tr = $(""); tr.appendTo(table); for (var j = 0; j < colCount; ++j) { var td; if (cells[i][j] == 0) { td = $(""); } else { td = $(""); } td.appendTo(tr); } } $("#table").append("
     
"+" "+"
"); } function checkCell(cell) {var x = parseInt($(cell).attr("data-x")); var y = parseInt($(cell).attr("data-y")); var cells = cellularArray.cells; cells[x][y] = (cells[x][y] + 1) % 2; this.createTable(cellularArray); } $("#initButton").click(function () { var rowCount = $("#rowText").val(); var colCount = $("#colText").val(); $.ajax({ url: "/backend/randInit", type: "GET", dataType: "JSON", contentType: "application/json", data: { row: rowCount, col: colCount }, success: function (result) { cellularArray = result; createTable(cellularArray); }}); $("#generateCount").val(0); }); $("#generateButton").click(function () { var rowCount = $("#rowText").val(); var colCount = $("#colText").val(); var generateCount = $("#generateCount").val(); $.ajax({ type: "POST", url: "/backend/generate", dataType: "JSON", contentType: "application/json", data: JSON.stringify(cellularArray), success: function (result) { cellularArray = result; createTable(cellularArray); }}); $("#generateCount").val(parseInt(generateCount) + 1); }); $("#countCleanButton").click(function () { $("#generateCount").val(0); }); $("#cellCleanButton").click(function () { var rowCount = $("#rowText").val(); var colCount = $("#colText").val(); $.ajax({ url: "/backend/empty", type: "GET", dataType: "JSON", contentType: "application/json", data: { row: rowCount, col: colCount }, success: function (result) { cellularArray = result; createTable(cellularArray); $("#generateCount").val(0); $("#rowText").val(cellularArray.row); $("#colText").val(cellularArray.col); }}); });Copy the code

The CSS file

.td-white {
    background-color: white;
    width: 20px;
    height: 20px;
}
.td-black {
    background-color: black;
    width: 20px;
    height: 20px;
}
body {
    margin: 10px;
}Copy the code

test

The page can configure the size of the cell array, simulate the results of cell proliferation, and manually change the cell life and death.

gliders

The pulsar

The source code

Github.com/TedHacker/P…

summary

Some of the problems

  • How do I transfer an array to the back end

    Convert the array to JSON format for transfer.

  • Unify data transmission specifications for the front and back ends

    Configuring Ajax requests to be JSON and spring-Confing to support THE JSON media format.

  • Javascript asynchronous callback

    Numerical changes that depend on the result of the callback need to be written in the callback function, otherwise data inconsistencies are likely to occur