使用Java實現(xiàn)生命游戲串行代碼示例
生命游戲介紹
生命游戲,是英國數學家約翰·何頓·康威在1970年發(fā)明的細胞自動機。
一個方格游戲棋盤上,每個方格中都可放置一個生命細胞,每個生命細胞只有兩種狀態(tài):“生”或“死”(狀態(tài)往往隨機決定)。然后細胞根據某些規(guī)則,計算出下一代每個細胞的狀態(tài),并且不停迭代。
在游戲的進行中,雜亂無序的細胞會逐漸演化出各種精致、有形的結構;這些結構往往有很好的對稱性,而且每一代都在變化形狀。一些形狀已經鎖定,不會逐代變化。有時,一些已經成形的結構會因為一些無序細胞的“入侵”而被破壞。但是形狀和秩序經常能從雜亂中產生出來。
現(xiàn)設定其規(guī)則是:
- 如果一個細胞周圍有3個細胞為生(一個細胞周圍共有8個細胞),則該細胞為生(即該細胞若原先為死,則轉為生,若原先為生,則保持不變) 。
- 如果一個細胞周圍有2個細胞為生,則該細胞的生死狀態(tài)保持不變;
- 在其它情況下,該細胞為死(即該細胞若原先為生,則轉為死,若原先為死,則保持不變)
下面就此規(guī)則,使用java來編寫100*100的棋盤,并使用簡單的JavaFX來實現(xiàn)簡易圖形化來觀察游戲的迭代過程。
一、效果展示
1.初始界面
100*100的棋盤上隨機生成“生”和“死”細胞(黑為生,白為死)。底部有“運行”和“暫停”按鈕。

2.啟動游戲

二、代碼實現(xiàn)
package com.itheima.gameOfLife;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import java.util.Random;
public class GameOfLife extends Application {
private static final int GRID_SIZE = 100;
private static final int CELL_SIZE = 10; // 每個細胞的像素大小
private static final int GENERATIONS = 1000; // 演化代數
private int[][] grid = new int[GRID_SIZE][GRID_SIZE]; // 當前代棋盤
private int[][] nextGrid = new int[GRID_SIZE][GRID_SIZE]; // 下一代棋盤
private Pane pane = new Pane();
private AnimationTimer timer;
private boolean isRunning = false; // 運行狀態(tài)標志
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
initializeGrid(); // 隨機初始化棋盤
// 創(chuàng)建JavaFX界面
BorderPane root = new BorderPane();
Scene scene = new Scene(root, GRID_SIZE * CELL_SIZE, GRID_SIZE * CELL_SIZE + 50);
primaryStage.setTitle("生命游戲");
primaryStage.setScene(scene);
// 創(chuàng)建按鈕,便于停止觀察當前棋盤狀態(tài)
Button startButton = new Button("運行");
Button pauseButton = new Button("暫停");
startButton.setOnAction(e -> startGame());
pauseButton.setOnAction(e -> pauseGame());
// 設置按鈕位置
root.setBottom(new Pane(startButton, pauseButton));
Pane buttonPane = new Pane();
buttonPane.getChildren().addAll(startButton, pauseButton);
buttonPane.setPrefSize(GRID_SIZE * CELL_SIZE, 50);
buttonPane.setLayoutY(GRID_SIZE * CELL_SIZE);
startButton.setLayoutX(20);
pauseButton.setLayoutX(80);
root.setCenter(pane);
root.setBottom(buttonPane);
primaryStage.show();
drawGrid(); // 繪制初始棋盤
// 使用AnimationTimer更新棋盤
timer = new AnimationTimer() {
private int generationCount = 0;
@Override
public void handle(long now) {
if (isRunning && generationCount < GENERATIONS) {
runGeneration(); // 運行一代
drawGrid(); // 更新繪制
generationCount++;
} else if (generationCount >= GENERATIONS) {
stop(); // 結束動畫
}
}
};
}
// 隨機初始化棋盤
private void initializeGrid() {
Random random = new Random();
for (int i = 0; i < GRID_SIZE; i++) {
for (int j = 0; j < GRID_SIZE; j++) {
grid[i][j] = random.nextInt(2); // 隨機生成0或1
}
}
}
// 啟動
private void startGame() {
if (!isRunning) {
isRunning = true; // 設置為運行狀態(tài)
timer.start(); // 啟動計時器
}
}
// 暫停
private void pauseGame() {
isRunning = false; // 設置為暫停狀態(tài)
timer.stop(); // 停止計時器
}
// 運行一代
private void runGeneration() {
for (int i = 0; i < GRID_SIZE; i++) {
for (int j = 0; j < GRID_SIZE; j++) {
int liveNeighbors = countLiveNeighbors(i, j);
if (grid[i][j] == 1) { // 當前細胞是活的
nextGrid[i][j] = (liveNeighbors == 2 || liveNeighbors == 3) ? 1 : 0;
} else { // 當前細胞是死的
nextGrid[i][j] = (liveNeighbors == 3) ? 1 : 0;
}
}
}
copyNextGridToCurrent();
}
// 計算鄰居活細胞數量
private int countLiveNeighbors(int row, int col) {
int liveNeighbors = 0;
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
if (i == 0 && j == 0) continue; // 跳過自身
int newRow = (row + i + GRID_SIZE) % GRID_SIZE; // 考慮邊界
int newCol = (col + j + GRID_SIZE) % GRID_SIZE;
liveNeighbors += grid[newRow][newCol];
}
}
return liveNeighbors;
}
// 將nextGrid復制到grid
private void copyNextGridToCurrent() {
for (int i = 0; i < GRID_SIZE; i++) {
System.arraycopy(nextGrid[i], 0, grid[i], 0, GRID_SIZE);
}
}
// 繪制當前棋盤狀態(tài)
private void drawGrid() {
pane.getChildren().clear(); // 清除舊的圖形
for (int i = 0; i < GRID_SIZE; i++) {
for (int j = 0; j < GRID_SIZE; j++) {
Rectangle cell = new Rectangle(j * CELL_SIZE, i * CELL_SIZE, CELL_SIZE, CELL_SIZE);
cell.setFill(grid[i][j] == 1 ? Color.BLACK : Color.WHITE); // 黑色表示活細胞,白色表示死細胞
cell.setStroke(Color.GRAY); //細胞之間的邊框
pane.getChildren().add(cell); // 將細胞添加到面板
}
}
}
}
三、代碼解釋
1.常量設置
private static final int GRID_SIZE = 100; private static final int CELL_SIZE = 10; // 每個細胞的像素大小 private static final int GENERATIONS = 1000; // 演化代數 private int[][] grid = new int[GRID_SIZE][GRID_SIZE]; // 當前代棋盤 private int[][] nextGrid = new int[GRID_SIZE][GRID_SIZE]; // 下一代棋盤 private Pane pane = new Pane(); private AnimationTimer timer; private boolean isRunning = false; // 運行狀態(tài)標志
GRID_SIZE: 定義了棋盤的大小,當前設置為 100。即棋盤是一個 100 x 100 的格子。
CELL_SIZE: 定義了每個細胞的像素大小,當前設置為 10。因此,每個細胞在界面上將顯示為一個 10 x 10 像素的正方形。
棋盤總大小: 因此,整個棋盤的實際像素大小為:
- 寬度:
GRID_SIZE * CELL_SIZE = 100 * 10 = 1000像素 - 高度:
GRID_SIZE * CELL_SIZE = 100 * 10 = 1000像素
2.圖形化
// 創(chuàng)建JavaFX界面
BorderPane root = new BorderPane();
Scene scene = new Scene(root, GRID_SIZE * CELL_SIZE, GRID_SIZE * CELL_SIZE + 50);
primaryStage.setTitle("生命游戲");
primaryStage.setScene(scene);
// 創(chuàng)建按鈕
Button startButton = new Button("運行");
Button pauseButton = new Button("暫停");
startButton.setOnAction(e -> startGame());
pauseButton.setOnAction(e -> pauseGame());
// 將按鈕放置在界面底部
root.setBottom(new Pane(startButton, pauseButton));
Pane buttonPane = new Pane();
buttonPane.getChildren().addAll(startButton, pauseButton);
buttonPane.setPrefSize(GRID_SIZE * CELL_SIZE, 50);
buttonPane.setLayoutY(GRID_SIZE * CELL_SIZE);
startButton.setLayoutX(20);
pauseButton.setLayoutX(80);
root.setCenter(pane);
root.setBottom(buttonPane);
primaryStage.show();
drawGrid(); // 繪制初始棋盤
// 使用AnimationTimer更新棋盤
timer = new AnimationTimer() {
private int generationCount = 0;
@Override
public void handle(long now) {
if (isRunning && generationCount < GENERATIONS) {
runGeneration(); // 運行一代
drawGrid(); // 更新繪制
generationCount++;
} else if (generationCount >= GENERATIONS) {
stop(); // 結束動畫
}
}
};
}上面這段代碼是JavaFX的核心部分,創(chuàng)建棋盤界面和處理游戲邏輯。部分解釋已經在代碼中注釋出來。
在“使用AnimationTimer更新棋盤”這部分中,創(chuàng)建了一個 AnimationTimer 對象,并重寫其handle方法,用于定時更新棋盤狀態(tài)。
3.計算“生死”情況與統(tǒng)計鄰居細胞數量
//根據規(guī)則判斷生死
private void runGeneration() {
for (int i = 0; i < GRID_SIZE; i++) {
for (int j = 0; j < GRID_SIZE; j++) {
int liveNeighbors = countLiveNeighbors(i, j);
if (grid[i][j] == 1) { // 當前細胞是活的
nextGrid[i][j] = (liveNeighbors == 2 || liveNeighbors == 3) ? 1 : 0;
} else { // 當前細胞是死的
nextGrid[i][j] = (liveNeighbors == 3) ? 1 : 0;
}
}
}
copyNextGridToCurrent();
}
// 計算鄰居活細胞數量
private int countLiveNeighbors(int row, int col) {
int liveNeighbors = 0;
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
if (i == 0 && j == 0) continue; // 跳過自身
int newRow = (row + i + GRID_SIZE) % GRID_SIZE; // 考慮邊界
int newCol = (col + j + GRID_SIZE) % GRID_SIZE;
liveNeighbors += grid[newRow][newCol];
}
}
return liveNeighbors;
}比較簡單的代碼,使用最基本的雙重循環(huán)來遍歷整個棋盤的細胞,得到其鄰居的數量用于判斷下一次迭代的狀態(tài)。
在“計算鄰居活細胞數量”中,用取模運算來處理邊界情況,使得棋盤具有環(huán)繞效果。例如,如果當前細胞在第一行,且要檢查上方的細胞,則通過取模確保索引循環(huán)回到棋盤的底部。
四、結語
以上主要淺顯的實現(xiàn)了生命游戲的基本邏輯,并用簡單的圖形可視化來創(chuàng)建一個直觀的界面來觀察細胞的迭代,更直接的觀察到由簡單規(guī)則產生的復雜動態(tài)行為。在這個串行的生命游戲基礎上,后續(xù)可以改寫為多線程的生命游戲,并通過一些方法來比對串行與并行代碼的效率。
到此這篇關于使用Java實現(xiàn)生命游戲串行的文章就介紹到這了,更多相關Java生命游戲串行代碼內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
啟動Tomcat報錯Unsupported major.minor version xxx的解決方法
這篇文章主要為大家詳細介紹了啟動Tomcat報錯Unsupported major.minor version xxx的解決方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-11-11

