Javakurs/Übungsaufgaben/DiffusionLimitedAggregation/Musterlösung: Unterschied zwischen den Versionen
Jörg F (Diskussion | Beiträge) K (hat „Javakurs2007/DiffusionLimitedAggregation/Musterlösung“ nach „Javakurs/Übungsaufgaben/DiffusionLimitedAggregation/Musterlösung“ verschoben: wikistruktur) |
K (fix alignment) |
||
(2 dazwischenliegende Versionen von einem anderen Benutzer werden nicht angezeigt) | |||
Zeile 3: | Zeile 3: | ||
public class DLA { | public class DLA { | ||
− | |||
public static void main(String[] args) { | public static void main(String[] args) { | ||
− | // Feld | + | // Feld erstellen, in dem gespeichert wird, ob an gegebenen Koordinaten |
+ | // ein Partikel ist | ||
int[][] field = new int[400][400]; | int[][] field = new int[400][400]; | ||
− | // | + | // Maximalwerte fuer Koordinaten der Partikel, lassen sich aus den |
− | + | // Dimensionen von field berechnen (.length verwenden) | |
int maxX = field.length; | int maxX = field.length; | ||
int maxY = field[0].length; | int maxY = field[0].length; | ||
Zeile 20: | Zeile 20: | ||
drawPad.setColor(Pad.white); | drawPad.setColor(Pad.white); | ||
− | // "Samen" erzeugen | + | // "Samen" erzeugen, also den ersten Pixel aufs Feld setzen (Color: |
− | // | + | // Pad.white) |
+ | // Hier: Pixel wird genau in die Mitte des Feldes gesetzt - andere | ||
+ | // Startpixel waeren moeglich | ||
setPixel(drawPad, field, maxX / 2, maxY / 2, Pad.white); | setPixel(drawPad, field, maxX / 2, maxY / 2, Pad.white); | ||
− | // | + | // Abstand des Partikels, der am weitesten vom Zentrum des Feldes |
+ | // entfernt ist | ||
int maxR = 0; | int maxR = 0; | ||
+ | |||
+ | // Falls der Startpunkt auch ein anderer sein kann als das Zentrum des | ||
+ | // Feldes: | ||
+ | // Berechne fuer alle bereits vorhandenen Partikel den Abstand zum | ||
+ | // Zentrum des Feldes | ||
+ | // speichere das Maximum dieser Abstaende in maxR | ||
for (int x = 0; x < maxX; x++) { | for (int x = 0; x < maxX; x++) { | ||
for (int y = 0; y < maxY; y++) { | for (int y = 0; y < maxY; y++) { | ||
if (testPixel(field, x, y)) { | if (testPixel(field, x, y)) { | ||
− | + | maxR = (int) Math.max(maxR, Math.sqrt(Math.pow((x - maxX / 2), 2) + Math.pow((y - maxY / 2), 2))); | |
− | maxR = (int) Math.max(maxR, Math.sqrt(Math.pow( | ||
− | |||
− | |||
} | } | ||
} | } | ||
} | } | ||
− | // Abbruchbedingung | + | // Abbruchbedingung: Hat einer der Partikel sich aus dem Feld heraus |
+ | // bewegt? | ||
boolean isAtBorder = false; | boolean isAtBorder = false; | ||
− | // | + | // Schleife: Erstelle solange neue Partikel, wie die Abbruchbedingung |
− | // | + | // false ist |
while (!isAtBorder) { | while (!isAtBorder) { | ||
− | // | + | // auf einem gedachten Kreis um den Mittelpunkt mit Radius maxR + 20 |
− | // | + | // einen Partikel "erzeugen" |
+ | // d.h. die Koordinaten eines zufaelligen Punktes auf dem Kreisrand | ||
+ | // berechnen | ||
+ | // neuer Partikel ist somit an Position movingPixelX ; movingPixelY | ||
+ | |||
double x = Math.random() * 360; | double x = Math.random() * 360; | ||
− | int movingPixelX = limit((int) (Math.cos(x) * (maxR + 20)) + maxX | + | int movingPixelX = limit((int) (Math.cos(x) * (maxR + 20)) + maxX / 2, 0, maxX); |
− | + | int movingPixelY = limit((int) (Math.sin(x) * (maxR + 20)) + maxY / 2, 0, maxY); | |
− | int movingPixelY = limit((int) (Math.sin(x) * (maxR + 20)) + maxY | ||
− | |||
− | // | + | // Nun Start der brownschen Bewegung |
− | while (!isTouching(field, movingPixelX, movingPixelY) | + | // Partikel bewegt sich, bis er einen bereits vorhandenen Partikel |
− | + | // beruehrt oder bis er das Feld verlaesst | |
− | + | ||
− | // | + | while (!isTouching(field, movingPixelX, movingPixelY) && inRange(movingPixelX, movingPixelY, maxR + 30, maxX, maxY)) { |
+ | |||
+ | // zufaelliges Verschieben des Partikels um +/- 1 Pixel mit | ||
+ | // moveRandom | ||
movingPixelX = moveRandom(movingPixelX); | movingPixelX = moveRandom(movingPixelX); | ||
movingPixelY = moveRandom(movingPixelY); | movingPixelY = moveRandom(movingPixelY); | ||
} | } | ||
− | // | + | // Brownsche Bewegung zu Ende - Ist Partikel auf einen bereits |
+ | // vorhandenen Partikel gestossen? | ||
if (isTouching(field, movingPixelX, movingPixelY)) { | if (isTouching(field, movingPixelX, movingPixelY)) { | ||
+ | // Wenn ja: Partikel ist jetzt "fest" an dieser Stelle, zeichne | ||
+ | // einen Punkt dort | ||
// Farbwertberechnung fuer 1337 blau-Effekt | // Farbwertberechnung fuer 1337 blau-Effekt | ||
− | int k = limit( | + | int k = limit(255 - (int) (255 * ((double) maxR * 2) / (double) maxX), 0, 255); |
− | |||
− | |||
Color c = new Color(255, k, k); | Color c = new Color(255, k, k); | ||
Zeile 71: | Zeile 84: | ||
setPixel(drawPad, field, movingPixelX, movingPixelY, c); | setPixel(drawPad, field, movingPixelX, movingPixelY, c); | ||
− | // | + | // Abstand des neu gesetzten Partikels zum Mittelpunkt des |
− | // wenn groesser als | + | // Feldes berechnen |
− | maxR = (int) Math.max(maxR, Math.sqrt(Math.pow( | + | // wenn groesser als alter maximaler Abstand maxR, dann Maximum |
− | + | // mit neuem Abstandswert ueberschreiben | |
− | + | maxR = (int) Math.max(maxR, Math.sqrt(Math.pow(((double) movingPixelX - (double) maxX / 2), 2) + Math.pow(((double) movingPixelY - (double) maxY / 2), 2))); | |
− | + | ||
− | if (movingPixelX - 1 <= 0 || movingPixelX + 1 >= maxX | + | // Falls der Partikel das Feld verlassen hat: Zeichnung ist |
− | + | // fertig, setze Abbruchkriterium der aeusseren Schleife auf | |
+ | // true | ||
+ | if (movingPixelX - 1 <= 0 || movingPixelX + 1 >= maxX || movingPixelY - 1 <= 0 || movingPixelY + 1 >= maxY) { | ||
isAtBorder = true; | isAtBorder = true; | ||
} | } | ||
Zeile 88: | Zeile 103: | ||
} | } | ||
− | + | public static void setPixel(Pad drawPad, int[][] field, int x, int y, Color c) { | |
− | + | /** | |
− | public static void setPixel(Pad drawPad, int[][] field, int x, int y, | + | * Pruefe, ob sich der Partikel an Koordinaten (x,y) innerhalb des |
− | + | * Feldes befindet Wenn ja, speichere ihn fest im Feld an dieser Stelle | |
− | + | * zeichne dort einen Punkt | |
+ | */ | ||
if (x > 0 && y > 0 && x < field.length - 1 && y < field[0].length - 1) { | if (x > 0 && y > 0 && x < field.length - 1 && y < field[0].length - 1) { | ||
− | |||
field[x][y] = 1; | field[x][y] = 1; | ||
− | |||
drawPad.setColor(c); | drawPad.setColor(c); | ||
drawPad.drawDot(x, y); | drawPad.drawDot(x, y); | ||
Zeile 118: | Zeile 132: | ||
*/ | */ | ||
public static boolean inRange(int x, int y, int maxR, int maxX, int maxY) { | public static boolean inRange(int x, int y, int maxR, int maxX, int maxY) { | ||
− | |||
// Mittelpunkt des Rechtecks ausrechen | // Mittelpunkt des Rechtecks ausrechen | ||
int middleX = maxX / 2; | int middleX = maxX / 2; | ||
int middleY = maxY / 2; | int middleY = maxY / 2; | ||
− | |||
// Der Abstand vom Mittelpunkt sqrt(a² + b²) mit Hilfe der in Java | // Der Abstand vom Mittelpunkt sqrt(a² + b²) mit Hilfe der in Java | ||
// intigrierten Klasse "Math" | // intigrierten Klasse "Math" | ||
− | int distance = (int) Math.sqrt(Math.pow((x - middleX), 2) | + | int distance = (int) Math.sqrt(Math.pow((x - middleX), 2) + Math.pow((y - middleY), 2)); |
− | |||
− | |||
if (distance < maxR) { | if (distance < maxR) { | ||
return true; | return true; | ||
} | } | ||
− | |||
return false; | return false; | ||
} | } | ||
Zeile 147: | Zeile 156: | ||
*/ | */ | ||
public static boolean isTouching(int[][] field, int x, int y) { | public static boolean isTouching(int[][] field, int x, int y) { | ||
− | |||
// ist eigentlich unschön, in diesem Fall aber wesentlich einfacher zu | // ist eigentlich unschön, in diesem Fall aber wesentlich einfacher zu | ||
// lesen und zu verstehen | // lesen und zu verstehen | ||
Zeile 156: | Zeile 164: | ||
return true; | return true; | ||
} | } | ||
− | |||
return false; | return false; | ||
− | |||
− | |||
} | } | ||
Zeile 179: | Zeile 184: | ||
y = limit(y, 0, field[0].length - 1); | y = limit(y, 0, field[0].length - 1); | ||
// länge des zweiten arrays | // länge des zweiten arrays | ||
− | |||
if (field[x][y] > 0) { | if (field[x][y] > 0) { | ||
return true; | return true; | ||
} | } | ||
− | |||
return false; | return false; | ||
} | } | ||
Zeile 199: | Zeile 202: | ||
*/ | */ | ||
public static int limit(int value, int lower, int upper) { | public static int limit(int value, int lower, int upper) { | ||
− | |||
if (value < lower) { | if (value < lower) { | ||
return lower; | return lower; | ||
} | } | ||
− | |||
if (value > upper) { | if (value > upper) { | ||
return upper; | return upper; | ||
} | } | ||
− | |||
return value; | return value; | ||
} | } | ||
Zeile 219: | Zeile 219: | ||
*/ | */ | ||
public static int moveRandom(int movePixel) { | public static int moveRandom(int movePixel) { | ||
− | |||
// erstelle eine random-Zahl zwischen 1 und | // erstelle eine random-Zahl zwischen 1 und | ||
int random = 1 + (int) (Math.random() * 3); | int random = 1 + (int) (Math.random() * 3); | ||
Zeile 234: | Zeile 233: | ||
return movePixel + 1; | return movePixel + 1; | ||
} | } | ||
− | |||
} | } | ||
− | |||
} | } | ||
− | |||
</pre> | </pre> |
Aktuelle Version vom 4. März 2013, 19:29 Uhr
import java.awt.Color; public class DLA { public static void main(String[] args) { // Feld erstellen, in dem gespeichert wird, ob an gegebenen Koordinaten // ein Partikel ist int[][] field = new int[400][400]; // Maximalwerte fuer Koordinaten der Partikel, lassen sich aus den // Dimensionen von field berechnen (.length verwenden) int maxX = field.length; int maxY = field[0].length; // Fenster fuer Grafikausgabe vorbereiten und anzeigen Pad drawPad = new Pad(); drawPad.setBackground(Pad.black); drawPad.setPadSize(maxX, maxY); drawPad.setVisible(true); drawPad.setColor(Pad.white); // "Samen" erzeugen, also den ersten Pixel aufs Feld setzen (Color: // Pad.white) // Hier: Pixel wird genau in die Mitte des Feldes gesetzt - andere // Startpixel waeren moeglich setPixel(drawPad, field, maxX / 2, maxY / 2, Pad.white); // Abstand des Partikels, der am weitesten vom Zentrum des Feldes // entfernt ist int maxR = 0; // Falls der Startpunkt auch ein anderer sein kann als das Zentrum des // Feldes: // Berechne fuer alle bereits vorhandenen Partikel den Abstand zum // Zentrum des Feldes // speichere das Maximum dieser Abstaende in maxR for (int x = 0; x < maxX; x++) { for (int y = 0; y < maxY; y++) { if (testPixel(field, x, y)) { maxR = (int) Math.max(maxR, Math.sqrt(Math.pow((x - maxX / 2), 2) + Math.pow((y - maxY / 2), 2))); } } } // Abbruchbedingung: Hat einer der Partikel sich aus dem Feld heraus // bewegt? boolean isAtBorder = false; // Schleife: Erstelle solange neue Partikel, wie die Abbruchbedingung // false ist while (!isAtBorder) { // auf einem gedachten Kreis um den Mittelpunkt mit Radius maxR + 20 // einen Partikel "erzeugen" // d.h. die Koordinaten eines zufaelligen Punktes auf dem Kreisrand // berechnen // neuer Partikel ist somit an Position movingPixelX ; movingPixelY double x = Math.random() * 360; int movingPixelX = limit((int) (Math.cos(x) * (maxR + 20)) + maxX / 2, 0, maxX); int movingPixelY = limit((int) (Math.sin(x) * (maxR + 20)) + maxY / 2, 0, maxY); // Nun Start der brownschen Bewegung // Partikel bewegt sich, bis er einen bereits vorhandenen Partikel // beruehrt oder bis er das Feld verlaesst while (!isTouching(field, movingPixelX, movingPixelY) && inRange(movingPixelX, movingPixelY, maxR + 30, maxX, maxY)) { // zufaelliges Verschieben des Partikels um +/- 1 Pixel mit // moveRandom movingPixelX = moveRandom(movingPixelX); movingPixelY = moveRandom(movingPixelY); } // Brownsche Bewegung zu Ende - Ist Partikel auf einen bereits // vorhandenen Partikel gestossen? if (isTouching(field, movingPixelX, movingPixelY)) { // Wenn ja: Partikel ist jetzt "fest" an dieser Stelle, zeichne // einen Punkt dort // Farbwertberechnung fuer 1337 blau-Effekt int k = limit(255 - (int) (255 * ((double) maxR * 2) / (double) maxX), 0, 255); Color c = new Color(255, k, k); // den Partikel setzen und zeichnen setPixel(drawPad, field, movingPixelX, movingPixelY, c); // Abstand des neu gesetzten Partikels zum Mittelpunkt des // Feldes berechnen // wenn groesser als alter maximaler Abstand maxR, dann Maximum // mit neuem Abstandswert ueberschreiben maxR = (int) Math.max(maxR, Math.sqrt(Math.pow(((double) movingPixelX - (double) maxX / 2), 2) + Math.pow(((double) movingPixelY - (double) maxY / 2), 2))); // Falls der Partikel das Feld verlassen hat: Zeichnung ist // fertig, setze Abbruchkriterium der aeusseren Schleife auf // true if (movingPixelX - 1 <= 0 || movingPixelX + 1 >= maxX || movingPixelY - 1 <= 0 || movingPixelY + 1 >= maxY) { isAtBorder = true; } } // System.out.println(maxX + "\t" + maxY + "\t " + maxR + "\t" // + movingPixelX + "\t" + movingPixelY + "\t"+isAtBorder); } } public static void setPixel(Pad drawPad, int[][] field, int x, int y, Color c) { /** * Pruefe, ob sich der Partikel an Koordinaten (x,y) innerhalb des * Feldes befindet Wenn ja, speichere ihn fest im Feld an dieser Stelle * zeichne dort einen Punkt */ if (x > 0 && y > 0 && x < field.length - 1 && y < field[0].length - 1) { field[x][y] = 1; drawPad.setColor(c); drawPad.drawDot(x, y); } } /** * Prüft ob sich ein Punkt innerhalb eines Radius vom Mittelpunkt eines * Rechtecks befindet * * @param x * die x Koordinate des fields * @param y * die y Koordinate des fields * @param maxR * der Radius * @param maxX * die x Koordinate des Rechtecks * @param maxY * die y Koordinate des Rechtecks+30 */ public static boolean inRange(int x, int y, int maxR, int maxX, int maxY) { // Mittelpunkt des Rechtecks ausrechen int middleX = maxX / 2; int middleY = maxY / 2; // Der Abstand vom Mittelpunkt sqrt(a² + b²) mit Hilfe der in Java // intigrierten Klasse "Math" int distance = (int) Math.sqrt(Math.pow((x - middleX), 2) + Math.pow((y - middleY), 2)); if (distance < maxR) { return true; } return false; } /** * Testet ob das gegebene Pixel an ein anderes grenzt * * @param field * das Array von Pixeln * @param x * die x Koordinate des fields * @param y * die y Koordinate des fields * @return grenzt an ein anders Pixel (true) oder nicht (false) */ public static boolean isTouching(int[][] field, int x, int y) { // ist eigentlich unschön, in diesem Fall aber wesentlich einfacher zu // lesen und zu verstehen if (testPixel(field, x - 1, y - 1) || testPixel(field, x - 1, y) || testPixel(field, x - 1, y + 1) || testPixel(field, x, y - 1) || testPixel(field, x, y + 1) || testPixel(field, x + 1, y - 1) || testPixel(field, x + 1, y) || testPixel(field, x + 1, y + 1)) { return true; } return false; } /** * Testet ob der Wert des Pixels größer 0 ist. (Falls der Wert außerhalb der * Grenzen ist wird er mit der limit() Methode gelimited) * * @param field * das Array von Pixeln * @param x * die x Koordinate des fields * @param y * die y Koordinate des fields * @return ob der Wert größer 0 ist (true) oder nicht (false) */ public static boolean testPixel(int[][] field, int x, int y) { // länge des ersten arrays x = limit(x, 0, field.length - 1); y = limit(y, 0, field[0].length - 1); // länge des zweiten arrays if (field[x][y] > 0) { return true; } return false; } /** * Limitiert einen Wert auf einen Bereich * * @param value * der zu limitierende Wert * @param lower * die untere Grenze * @param upper * die obere Grenze * @return den limitierten Wert */ public static int limit(int value, int lower, int upper) { if (value < lower) { return lower; } if (value > upper) { return upper; } return value; } /** * Bewegt eine Pixelkoordinate randommäßig -1, +1 oder gar nicht * * @param movePixel * die zu bewegende Pixel-Koordinate * @return die Bewegte Pixel-Koordinate */ public static int moveRandom(int movePixel) { // erstelle eine random-Zahl zwischen 1 und int random = 1 + (int) (Math.random() * 3); // Math.random() gibt eine double-Zahl >= 0.0 und < 1.0 zurück switch (random) { case 1: return movePixel - 1; case 2: return movePixel; default: return movePixel + 1; } } }