/*
Source file: SimForestModel.java
Author: Markus Bautsch
Licence: public domain
Date: 31 October 2022
Version: 1.0
Programming language: Java
*/
/*
Modell fuer die Simulation von Waldbraenden in einer rechteckigen Flaeche
*/
public class SimForestModel
{
// Klassenkonstanten fuer die Klassenvariablen currentGround und nextGround
public final static long SOIL = 0;
public final static long TREE = 1;
public final static long WATER = 2;
public final static long FIRE = 3;
// Instanzvariablen
private int sizeX = 200;
private int sizeY = 200;
private long annualNumberOfLightnings = 3; // Anzahl der Blitzschlaege innerhalb des Gebiets in einem Jahr
private double probabilitySpreadOfForestFire = 0.7; // nach Blitzschlag
private double fireExtinctionIndex = 0.9; // Wahrscheinlichkeit, dass ein Feuer erlischt
private double treeGrowthIndex = 0.02; // Wahrscheinlichkeit, dass ein Baum waechst
private long [] [] currentGround;
private long [] [] nextGround;
/* Konstruktor fuer die Initialisierung von Instanzen der Klasse SimForestModel
* @param x: Fuer die horizontale Groesse in Pixeln
* @param y: Fuer die vertikale Groesse in Pixeln
*/
public SimForestModel (int x, int y)
{
this.sizeX = x;
this.sizeY = y;
this.currentGround = new long [x] [y];
this.nextGround = new long [x] [y];
}
/*
* Gibt die Breite des Waldbodenmodells zurueck
*/
public int getWidth ()
{
return sizeX;
}
/*
* Gibt die Hoehe des Waldbodenmodells zurueck
*/
public int getHeight ()
{
return sizeY;
}
/*
* Gibt den Status des Waldbodenmodells an der Stelle (x,y) zurueck
*/
public long getGroundState (int x, int y)
{
return currentGround [x] [y];
}
/*
* Setzt den Status des Waldbodenmodells an der Stelle (x,y)
*/
public void setGroundState (int x, int y, long state)
{
currentGround [x] [y] = state;
}
/*
* Setzt die Anzahl der Blitzschlaege in einem Jahr
*/
public void setAnnualNumberOfLightnings (long number)
{
if (number < 0)
{
number = 0;
}
annualNumberOfLightnings = number;
}
/*
* Prueft den Wertebereich fuer eine Wahrscheinlichkeit zwischen Null und Eins
*/
private double checkProbability (double probability)
{
probability = java.lang.Math.abs (probability);
if (probability > 1)
{
probability = 1;
}
return probability;
}
/*
* Setzt die Wahrscheinlichkeit fuer die Ausbreitung eines Brandes nach einem Blitzschlag
*/
public void setProbabilitySpreadOfForestFire (double probability)
{
probabilitySpreadOfForestFire = checkProbability (probability);
}
/*
* Setzt die Wahrscheinlichkeit fuer das Erloeschen eines Feuers an einer Stelle des Waldbodens
*/
public void setFireExtinctionIndex (double probability)
{
fireExtinctionIndex = checkProbability (probability);
}
/*
* Setzt die Wahrscheinlichkeit fuer das Wachsen eines neuen Baumes an einer Stelle des Waldbodens
*/
public void setTreeGrowthIndex (double probability)
{
treeGrowthIndex = checkProbability (probability);
}
/*
* Methode fuer die Simulation eines Blitzschlags
* Gibt zurueck, ob ein Baum entzuendet wurde
*/
private boolean simulateLightning ()
{
int locationX = (int) PseudoRandom.nextInteger (sizeX);
int locationY = (int) PseudoRandom.nextInteger (sizeY);
boolean forestIsBurning = false;
if (currentGround [locationX] [locationY] == TREE)
{
currentGround [locationX] [locationY] = FIRE;
forestIsBurning = true;
}
return forestIsBurning;
}
/*
* Methode fuer die Ausbreitung des Waldbrands
* Gibt zurueck, ob ein benachbarter Baum brennt
*/
private boolean fireNextToTree (int x, int y)
{
boolean fireNextToTree = false;
double probability = PseudoRandom.nextProbability ();
if (probability < probabilitySpreadOfForestFire) // fuer rechts/links, oben/unten
{
fireNextToTree = ((x > 0) && (currentGround [x - 1] [y] == FIRE))
|| ((x < (sizeX - 1)) && (currentGround [x + 1] [y] == FIRE))
|| ((y > 0) && (currentGround [x] [y - 1] == FIRE))
|| ((y < (sizeY - 1)) && (currentGround [x] [y + 1] == FIRE));
}
if (!fireNextToTree && (probability < (probabilitySpreadOfForestFire / 4))) // fuer die vier Diagonalen
{
fireNextToTree = ((x > 0) && (y > 0) && (currentGround [x - 1] [y - 1] == FIRE))
|| ((x < (sizeX - 1)) && (y > 0) && (currentGround [x + 1] [y - 1] == FIRE))
|| ((x > 0) && (y < (sizeY - 1)) && (currentGround [x - 1] [y + 1] == FIRE))
|| ((x < (sizeX - 1)) && (y < (sizeY - 1)) && (currentGround [x + 1] [y + 1] == FIRE));
}
return fireNextToTree;
}
/*
* Methode zum Kopieren des neu berechneten Waldbodens zum aktuellen Wandboden
*/
private void copyNextToCurrentGround ()
{
for (int y = 0; y < sizeY; y++)
{
for (int x = 0; x < sizeX; x++)
{
currentGround [x] [y] = nextGround [x] [y];
}
}
}
/*
* Methode fuer die Simulation eines Waldbrands
* Gibt zurueck, wie viele Baeume des Waldes brennen
*/
public long simulateBurning ()
{
long numberOfTreesBurning = 0;
for (int y = 0; y < sizeY; y++)
{
for (int x = 0; x < sizeX; x++)
{
long currentState = currentGround [x] [y];
nextGround [x] [y] = currentState;
if (currentState == TREE)
{
if (fireNextToTree (x, y))
{
nextGround [x] [y] = FIRE;
numberOfTreesBurning++;
}
}
else if (currentState == FIRE)
{
double probability = PseudoRandom.nextProbability ();
if (probability < fireExtinctionIndex)
{
nextGround [x] [y] = SOIL;
}
else
{
numberOfTreesBurning++;
}
}
}
}
copyNextToCurrentGround ();
return numberOfTreesBurning;
}
/*
* Methode zum Simulieren des Wachstums eines neuen Baumes
*/
private void newTree (int x, int y)
{
double probability = PseudoRandom.nextProbability ();
if (probability < treeGrowthIndex)
{
nextGround [x] [y] = TREE;
}
}
/*
* Methode fuer die Simulation des jaehrlichen Baumwuchses
*/
private void simulateTreeGrowth ()
{
for (int y = 0; y < sizeY; y++)
{
for (int x = 0; x < sizeX; x++)
{
long currentState = currentGround [x] [y];
nextGround [x] [y] = currentState;
if (currentState == SOIL)
{
newTree (x, y);
}
}
}
}
/*
* Methode fuer die Simulation eines Jahres
* Gibt zurueck, ob der Wald brennt
*/
private boolean simulateLightnings ()
{
boolean forestIsBurning = false;
for (long i = 0; i < annualNumberOfLightnings; i++)
{
boolean forestIsIgnited = simulateLightning ();
forestIsBurning = forestIsBurning || forestIsIgnited;
}
return forestIsBurning;
}
/*
* Methode fuer die Simulation eines Jahres
* Gibt zurueck, ob der Wald brennt
*/
public boolean simulateYear ()
{
simulateTreeGrowth ();
copyNextToCurrentGround ();
boolean forestIsBurning = simulateLightnings ();
return forestIsBurning;
}
}