Waldbrandsimulation/ SimForestFrame

/*
Source file: SimForestFrame.java
Author: Markus Bautsch
Licence: public domain
Date: 31 October 2022
Version: 1.1
Programming language: Java
 */

/*
Graphische aktualisierte Ausgabe von Rechtecken
 */

public final class SimForestFrame extends javax.swing.JFrame implements java.awt.event.ActionListener
{
	// serialVersionUID fuer die Serialisation, die in der Klasse javax.swing.JFrame implementiert ist
	private final static long serialVersionUID = 1L;

	// Klassenkonstanten
	final private static int [] SoilColour = {64, 32, 0};
	final private static int [] TreeColour = {0, 255, 0};
	final private static int [] FireColour = {255, 0, 0};
	final private static int [] WaterColour = {0, 0, 255};

	final private static java.lang.String title = "Forest Fire";
	final private static int offset = 10;
	final private static int offsetTop = 30;

	final private static int fireDelay = 1; // Verzögerung während eines Wandbrands in Millisekunden
	final private static int annualDelay = 500; // Verzoegerung nach einem simulierten Jahr in Millisekunden

	// Instanzvariablen
	private int sizeX = 200;
	private int sizeY = 200;
	private long currentYear = 0;
	private long numberOfYears = 1;
	private boolean forestIsBurning = false;
	private SimForestModel model;
	private java.awt.image.BufferedImage bufferedImage;
	private java.awt.image.WritableRaster imageRaster;
	private javax.swing.Timer timer = new javax.swing.Timer (annualDelay, this);  // Fuer die Anzeige des JFrames mit Verzoegerung

	/* Konstruktor fuer die Initialisierung von Instanzen der Klasse SimForestFrame
	 * @param x: Fuer die horizontale Groesse in Pixeln
	 * @param y: Fuer die vertikale Groesse in Pixeln
	 * @param count: Fuer die Anzahl der Simulationsdurchlaeufe in Jahren
	 */
	public SimForestFrame (int x, int y, long count)
	{
		super (title);
		this.model = new SimForestModel (x, y);
		this.sizeX = x;
		this.sizeY = y;
		this.numberOfYears = count;
		// Rahmengroesse, Hintergrund und das Layout werden gesetzt
		this.setSize (this.sizeX + 2 * offset, this.sizeY + 2 * offset + offsetTop);
		this.setBackground (java.awt.Color.BLACK);
		this.bufferedImage = new java.awt.image.BufferedImage (this.sizeX, this.sizeY, java.awt.image.BufferedImage.TYPE_INT_RGB);
		this.imageRaster = bufferedImage.getWritableTile (0, 0);
		this.setDefaultCloseOperation (javax.swing.WindowConstants.EXIT_ON_CLOSE);
	}

	/*
	 * Gibt das Simulationsmodell der Klasse SimForestModel vom SimForestFrame zurueck
	 */
	public SimForestModel getModel ()
	{
		return model;
	}

	/*
	 * Standard-Methode paint zum Zeichnen des Rechtecks mit dem Waldboden
	 */
	public void paint (java.awt.Graphics graphics)
	{
		for (int y = 0; y < sizeY; y++)
		{
			for (int x = 0; x < sizeX; x++)
			{
				long groundState = model.getGroundState (x, y);
				if (groundState == SimForestModel.SOIL)
				{
					imageRaster.setPixel (x, y, SoilColour);
				}
				else if (groundState == SimForestModel.TREE)
				{
					imageRaster.setPixel (x, y, TreeColour);
				}
				else if (groundState == SimForestModel.WATER)
				{
					imageRaster.setPixel (x, y, WaterColour);
				}
				else if (groundState == SimForestModel.FIRE)
				{
					imageRaster.setPixel (x, y, FireColour);
				}
			}
		}
		graphics.drawImage (bufferedImage, offset, offset + offsetTop, null);
		java.awt.Toolkit.getDefaultToolkit ().sync (); // Dieser Methodenaufruf stellt sicher, dass die Ausgabe vollständig aktualisiert ist
	}

	/*
	 *  Methode fuer die Initialisierung einer Instanz von SimForestFrame
	 */
	public void init ()
	{
		java.awt.Graphics2D graphics2D = bufferedImage.createGraphics ();
		this.timer.start ();
		this.paint (graphics2D);
		this.setVisible (true);
		this.setAlwaysOnTop (true);
	}

	/*
	 *  Ueberschriebene Standard-Methode actionPerformed fuer die synchronisierte Aktualisierung einer Instanz SimForestFrame
	 */
	public void actionPerformed (java.awt.event.ActionEvent event)
	{
		long numberOfTreesBurning = 0;
		if (forestIsBurning)
		{
			numberOfTreesBurning = model.simulateBurning ();
			forestIsBurning = (numberOfTreesBurning > 0);
			if (forestIsBurning)
			{
				timer.setDelay (fireDelay);
			}
			else
			{
				timer.setDelay (annualDelay);
			}
		}
		else if (currentYear < numberOfYears)
		{
			currentYear++;
			forestIsBurning = model.simulateYear ();
		}
		else
		{
			timer.stop ();
		}
		java.lang.String currentTitel = title + " / year " + currentYear + " / " + " burning trees = " + numberOfTreesBurning;
		setTitle (currentTitel);
		repaint ();
	}
}