1. #1

    Registriert seit
    19.11.2011
    Beiträge
    496
    Thanked 412 Times in 268 Posts

    Standard Conway's Game of Life

    Hallo,

    damit dieses Subforum auch mal genutzt wird, hier eine Aufgabe: Es soll Conway's Game of Life implementiert werden.
    Dazu ersteinmal grundlegende Informationen aus dem Wikipedia-Artikel:

    Das Spiel des Lebens von John Horton Conway ist ein System, das auf einem zweidimensionalen zelluären Automaten basiert.
    Das Spielfeld ist in Spalten und Zeilen unterteilt. Jedes Quadrat ist eine Zelle, die zwei Zustände haben kann. Entweder lebt sie, oder sie ist tot. Jede Zelle hat acht Nachbarn (oben, unten, links, rechts und die diagonal angrenzenden Zellen) und diese muss jede Zelle auch kennen, denn die Folgegeneration wird unter Beachtung nachfolgender Regeln erzeugt:
    • Eine tote Zelle mit genau drei lebenden Nachbarn wird in der Folgegeneration leben
    • Lebende Zellen mit weniger als zwei lebenden Nachbarn sterben in der nächsten Generation
    • Lebende Zellen mit zwei oder drei lebenden Nachbarn bleiben auch in der Folgegeneration am leben
    • Lebende Zellen mtt mehr als drei Nachbarn sterben in der Folgegeneration


    Aufgaben

    Anfänger: Schreibe eine Klasse für das Spiel des Lebens. Als eine kleine Orientierung sei ein unvollständiges Interface gegeben, das es zu implementieren gilt. Außerdem soll eine beliebige Anfangsgeneration manuell erstellt werden und die ersten 5 Generationen auf der Konsole ausgegeben werden.
    Code:
    public interface GameOfLifeModel {
        // Anzahl Zeilen des Spielfeldes
        public static final int ROWS = 60;
        
        // Anzahl Spalten des Spielfeldes
        public static final int COLS = 80;
        
        // Kantenlänge eines Quadrates (Zelle)
        public static final int CELL_SIZE = 10;
        
        // Berechnet die Folgegeneration und speichert diese.
        public void nextGeneration();
        
        // Gibt die aktuelle Generation zurück.
        // das zweidimensionale boolean-Array ist eine mögliche Form
        // der internen Repräsentation.
        public boolean[][] getGeneration();
    }
    Fortgeschritten:
    • Je größer das Spielfeld, desto besser. Es gibt eine Möglichkeit, ein unendliches Spielfeld zu simulieren, in dem man es torus-förmig macht.
    • Erstelle ein GUI, das folgende Funktionalitäten besitzt:
      • Der Benutzer kann die Generation "zeichnen"
      • Es gibt Buttons für die Berechnung und Anzeige der Folgegeneration und zum Zurücksetzen (alle Zellen sind tot)
      • Optional: der Benutzer kann eine Animation starten und die Geschwindigkeit einstellen. Die "Animation" soll dann automatisch die Folgegeneration berechnen und anzeigen, bis der Benutzer die Animation stoppt.



    Wer auch die fortgeschrittenen Aufgaben löst, muss natürlich die Lösung der Konsolenausgabe nicht posten.

    Meine Lösung:
    Spoiler:Java7/JavaFx

    Spoiler:GameOfLifeMain.java

    Code:
    package gameoflife;
    
    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.stage.Stage;
    
    public class GameOfLifeMain extends Application {
        @Override
        public void start(Stage stage) throws Exception {
            Parent root = FXMLLoader.load(getClass().getResource("UI_GameOfLife.fxml"));
            Scene scene = new Scene(root);
            stage.setTitle("Conway's Game of Life");
            stage.setScene(scene);
            stage.setResizable(false);
            stage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }

    Spoiler:UI_GameOfLife.fxml

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import java.lang.*?>
    <?import java.util.*?>
    <?import javafx.scene.*?>
    <?import javafx.scene.canvas.*?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.layout.*?>
    <?import javafx.scene.shape.*?>
    <?import javafx.scene.text.*?>
    
    <AnchorPane id="AnchorPane" minHeight="634.0" prefHeight="660.0" prefWidth="820.0" style="-fx-background-color: #f3f3f3;" xmlns:fx="http://javafx.com/fxml" fx:controller="gameoflife.UI_GameOfLifeController">
      <children>
        <HBox id="HBox" alignment="CENTER" layoutX="10.0" layoutY="10.0" spacing="20.0">
          <children>
            <HBox id="HBox" alignment="CENTER" spacing="10.0">
              <children>
                <Button id="nextGenerationButton" mnemonicParsing="false" onAction="#nextGenerationButtonFired" text="Nächste Generation" />
                <Button mnemonicParsing="false" onAction="#resetButtonFired" text="Reset" />
              </children>
            </HBox>
            <HBox id="HBox" alignment="CENTER" spacing="5.0">
              <children>
                <Label text="Generation:" />
                <Text fx:id="generationCount" strokeType="OUTSIDE" strokeWidth="0.0" text="0" />
              </children>
            </HBox>
          </children>
        </HBox>
        <HBox id="HBox" alignment="CENTER" layoutX="438.0" spacing="15.0" AnchorPane.topAnchor="10.0">
          <children>
            <HBox id="HBox" alignment="CENTER" spacing="5.0">
              <children>
                <Button mnemonicParsing="false" onAction="#startButtonFired" text="Start" />
                <Button mnemonicParsing="false" onAction="#stopButtonFired" text="Stop" />
              </children>
            </HBox>
            <HBox id="HBox" alignment="CENTER" spacing="5.0">
              <children>
                <Label text="Speed:" />
                <Slider fx:id="slider" majorTickUnit="10.0" min="1.0" minorTickCount="1" />
              </children>
            </HBox>
          </children>
        </HBox>
        <BorderPane id="generationPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="800.0" style="
    " AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0">
          <center>
            <Canvas fx:id="canvas" height="600.0" onMouseDragged="#mouseControl" onMousePressed="#mouseControl" width="800.0" />
          </center>
        </BorderPane>
      </children>
    </AnchorPane>

    Spoiler:UI_GameOfLifeController.java

    Code:
    package gameoflife;
    
    import java.net.URL;
    import java.util.ResourceBundle;
    import javafx.animation.Animation;
    import javafx.animation.Transition;
    import javafx.beans.property.IntegerProperty;
    import javafx.beans.property.SimpleIntegerProperty;
    import javafx.event.ActionEvent;
    import javafx.fxml.FXML;
    import javafx.fxml.Initializable;
    import javafx.scene.canvas.Canvas;
    import javafx.scene.canvas.GraphicsContext;
    import javafx.scene.control.Slider;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.paint.Color;
    import javafx.scene.text.Text;
    import javafx.util.Duration;
    
    public class UI_GameOfLifeController implements Initializable {
        private GameOfLifeModel model;
        private Animation timer;
        
        @FXML private Canvas canvas;
        @FXML private Text generationCount;
        @FXML private Slider slider;
    
        @FXML
        private void nextGenerationButtonFired(ActionEvent ae) {
            timer.stop();
            model.nextGeneration();
            drawGeneration();
        }
    
        @FXML
        private void startButtonFired(ActionEvent ae) {
            timer.play();
        }
    
        @FXML
        private void stopButtonFired(ActionEvent ae) {
            timer.stop();
        }
    
        @FXML
        private void resetButtonFired(ActionEvent ae) {
            timer.stop();
            model.initDefaultGeneration();
            drawGeneration();
        }
    
        @FXML
        private void mouseControl(MouseEvent me) {
            int x = (int)me.getX();
            int y = (int)me.getY();
            if (canvas.contains(x, y)) {
                int xc = x / GameOfLifeModel.CELL_SIZE;
                int yc = y / GameOfLifeModel.CELL_SIZE;
                if (me.isSecondaryButtonDown()) {
                    model.setCell(yc, xc, false);
                } else if (me.isPrimaryButtonDown()) {
                    model.setCell(yc, xc, true);
                } 
                drawGeneration();
            }
        }
    
        private void drawGeneration() {
            final GraphicsContext gc = canvas.getGraphicsContext2D();
            final int ROWS = GameOfLifeModel.ROWS;
            final int COLS = GameOfLifeModel.COLS;
            final int CELL_SIZE = GameOfLifeModel.CELL_SIZE;
            final boolean[][] generation = model.getGeneration();
            gc.setFill(Color.GRAY);
            gc.setStroke(Color.BLACK);
            gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
            gc.setFill(Color.WHITE);
            int x = 0, y = 0;
            for (int row = 0; row < ROWS; ++row) {
                for (int col = 0; col < COLS; ++col) {
                    if (generation[row][col]) {
                        gc.fillRect(x, y, CELL_SIZE, CELL_SIZE);
                    }
                    x += CELL_SIZE;
                }
                x = 0;
                y += CELL_SIZE;
            }
        }
    
        @Override
        public void initialize(URL url, ResourceBundle rb) {
            model = new GameOfLifeModel();
            final IntegerProperty speed = new SimpleIntegerProperty(1);
            slider.valueProperty().bindBidirectional(speed);
            generationCount.textProperty().bind(model.generationCountProperty().asString());
            timer = new Transition() {
                {
                    setCycleDuration(Duration.millis(500));
                    setCycleCount(Animation.INDEFINITE);
                }
                @Override
                protected void interpolate(double d) {
                    model.nextGeneration();
                    drawGeneration();
                    setRate(speed.get());
                }
            };
            drawGeneration();
        }
    }

    Spoiler:GameOfLifeModel.java

    Code:
    package gameoflife;
    
    import java.util.Arrays;
    import javafx.beans.property.IntegerProperty;
    import javafx.beans.property.SimpleIntegerProperty;
    
    public class GameOfLifeModel {
        public static final int CELL_SIZE = 10;  
        public static final int ROWS = 60;
        public static final int COLS = 80;
        
        private boolean[][] generation;
        private IntegerProperty generationCount;
        
        public GameOfLifeModel() {
            generation = new boolean[ROWS][COLS];
            generationCount = new SimpleIntegerProperty(0);
            initDefaultGeneration();
        }
    
        public final void initDefaultGeneration() {
            for (int row = 0; row < ROWS; ++row) {
                for (int col = 0; col < COLS; ++col) {
                    generation[row][col] = false;
                }
            }
            generationCount.set(0);
        }
    
        public void nextGeneration() {
            boolean[][] newGen = new boolean[ROWS][COLS];
            for (int row = 0; row < ROWS; ++row) {
                for (int col = 0; col < COLS; ++col) {
                    int neighbours = countNeighbours(row, col);
                    if (!getCell(row, col)) {
                        if (neighbours == 3) {
                            setCell(newGen, row, col, true);
                        }
                    } else {
                        if (neighbours < 2) {
                            setCell(newGen, row, col, false);
                        } else if (neighbours <= 3) {
                            setCell(newGen, row, col, true);
                        } else {
                            setCell(newGen, row, col, false);
                        }
                    }
                }
            }
            if (!Arrays.equals(newGen, generation)) {
                generation = newGen;
                generationCount.set(generationCount.get() + 1);
            }
        }
        
        public boolean[][] getGeneration() {
            return generation;
        }
        
        public IntegerProperty generationCountProperty() {
            return generationCount;
        }
        
        public void setCell(int row, int col, boolean alive) {
            setCell(generation, row, col, alive);
        }
    
        private int countNeighbours(int row, int col) {
            int counter = 0;
            for (int i = -1; i <= 1; i++) {
                for (int k = -1; k <= 1; k++) {
                    if (getCell(row + i, col + k)) {
                        counter++;
                    }
                }
            }
            if (getCell(row, col)) {
                counter--;
            }
            return counter;
        }
    
        private boolean getCell(int row, int col) {
            row %= ROWS;
            col %= COLS;
            row += row < 0 ? ROWS : 0;
            col += col < 0 ? COLS : 0;
            return generation[row][col];
        }
    
        private void setCell(boolean[][] newGen, int row, int col, boolean alive) {
            row %= ROWS;
            col %= COLS;
            row += row < 0 ? ROWS : 0;
            col += col < 0 ? COLS : 0;
            newGen[row][col] = alive;
        }
    }


    Spoiler:Download (JAR)

    Mit der linken Maustaste lebende Zellen zeichnen. Mit der rechten Maustaste töten.
    GameOfLife.jar

    Geändert von U-Labs (24.06.2024 um 15:57 Uhr) Grund: Abload.de Bilder wegen geplanter Abschaltung auf U-IMG übertragen

Ähnliche Themen

  1. Stanfour - Life without you
    Von BMG im Forum Musik ♫
    Antworten: 3
    Letzter Beitrag: 31.10.2012, 06:28
  2. Kim Dotcom - Live my Life
    Von Bossgen im Forum Musik ♫
    Antworten: 4
    Letzter Beitrag: 28.09.2012, 15:53
  3. Facebook Time Life
    Von helfen im Forum Internet und Technik
    Antworten: 13
    Letzter Beitrag: 30.01.2012, 13:34
  4. Facebook Time Life
    Von helfen im Forum Internet und Technik
    Antworten: 3
    Letzter Beitrag: 17.12.2011, 22:07
Diese Seite nutzt Cookies, um das Nutzererlebnis zu verbessern. Klicken Sie hier, um das Cookie-Tracking zu deaktivieren.