Campingplatzrätsel/ Druckversion

Aus Wikibooks

Hauptteil[Bearbeiten]

Bildschirmaufnahme eines Java-Programms zur Erstellung von Campingplatzrätseln.

Dieses Wikibook beschäftigt sich mit der softwaretechnischen Erstellung von Campingplatzrätseln mit der Hilfe eines strukturierten Java-Programms. Hierbei werden iterative Algorithmen eingesetzt, mit denen die Zeilen und Spalten des rechteckigen Campingplatzes abgearbeitet werden.

Campingplatzrätsel[Bearbeiten]

Das Ziel des Spieles besteht darin, anhand von Zeilen- und Spaltensummern von Zelten sowie der Lage von dargestellten Bäumen die Lage aller verborgenen Zelte herauszufinden.

Dieses Logikspiel wurde wurde Ende der 1980er Jahre vom Niederländer Leon Balmaekers erfunden. Der niederländische Spieleentwickler Peter Ritmeester veröffentlichte es zunächst unter der Bezeichnung "Alle ballen verzamelen" (zu Deutsch: "Alle Bälle einsammeln")in der seit 1993 herausgegebenen Zeitschrift Eureka (altgriechisch εὕρηκα = „Ich habe es gefunden“), dem Vorgänger der Zeitschrift Breinbrekers (wörtlich übersetzt: "Hirnbrecher").

Beim Campingplatzraetsel müssen Zelte auf einem rechteckigen Campingplatz mit quadratischen Feldern so verteilt werden, dass rechts, links, oben oder unten neben jedem auf dem Campingplatz vorhandenen Baum genau ein diesem Baum zugeordnetes Zelt gesetzt wird.

In den acht direkten Nachbarfeldern eines Zeltes darf kein weiteres Zelt aufgebaut sein.

Am Spielfeldrand wird angezeigt, wie viele Zelte sich in den betreffenden Spalten und Zeilen befinden. Die Gesamtzahl aller Zelte beziehungsweise auch aller Bäume steht in der unteren rechten Ecke.

Programmbestandteile[Bearbeiten]

Das hier vorgestellte Java-Programm berechnet ein rechteckiges Campingplatzfeld. Hierzu wird die Java-Klasse CampingplatzGraphs verwendet, die im Folgenden beschrieben wird.

CampingplatzGraphs[Bearbeiten]

In der Java-Klasse CampingplatzGraphs werden Instanzen der zu lösenden Campingplatzrätsel implementiert. Die Klasse CampingplatzGraphs dient ferner zur graphischen Darstellung der Campingplatzrätsel. Hierzu wird die Methode campingplatzZeichnen aufgerufen.

Das Campingplatzrätsel hat die Breite sizeX und die Höhe sizeY. Jedes Campingplatzrätsel hat für eine Pseudozufallszahlenfolge genau einen Startwert seed, mit dessen Hilfe ein definiertes Campingplatzrätsel generiert werden kann.

Alle Campingplatzfelder sind quadratisch und haben die gleichen Breiten und Höhen fieldSize.

Bei der hier vorgestellten Implementierung befindet sich das Campingplatzfeld mit dem kleinsten Rechtswert und dem kleinsten Hochwert (0 | 0) oben links, die positiven Rechtswerte laufen nach rechts und die positiven Hochwerte laufen nach unten. Die Eigenschaften des Campingplatzrätsels bleiben bei einer Achsenspiegelung um die horizontale oder vertikale Achse oder bei einer Punktspiegelung erhalten.

public final class CampingplatzGraphs extends javax.swing.JFrame implements java.awt.event.MouseListener
{
	// Oeffentliche Klassenkonstanten
	/**
	 * Wert fuer den Parameter "showTents" des Konstruktors ohne Anzeige der Loesung
	 */
	public final static boolean PUZZLE = false;
	/**
	 * Wert fuer den Parameter "showTents" des Konstruktors mit Anzeige der Loesung
	 */
	public final static boolean SOLUTION = true;

	// Klassenkonstanten
	// Fuer den Inhalt der Campingplatzfelder
	private final static long EMPTY = 0;
	private final static long TENT = 1;
	private final static long TREE = 2;
	private final static long CORRECT_GUESS = 3;
	private final static long WRONG_GUESS = 4;
	private final static long CORRECT_BLOCK = 5;
	private final static long WRONG_BLOCK = 6;

	// Fuer die Richtungen zu den Nachbarfeldern
	private final static long TOP = 0;
	private final static long RIGHT = 1;
	private final static long BOTTOM = 2;
	private final static long LEFT = 3;

	// Fuer die Groesse der Darstellung
	private final static int offset = 10; // fuer die umlaufende Breite des Randes
	private final static int offsetTop = 30; // fuer den Titelbanner des graphischen Fensters
	private final static int fieldSize = 64; // fuer die Groesse der Campingplatzfelder

	// Instanzkonstanten
	private final int sizeX; // fuer die Breite in Campingplatzfeldern
	private final int sizeY; // fuer die Hoehe in Campingplatzfeldern
	private final int widthsInPixels; // fuer die Breite in Bildpunkten
	private final int heightInPixels; // fuer die Hoehe in Bildpunkten
	private final long seed; // fuer den Startwert der Pseudozufallszahlenreihe

	// Instanzvariablen
	private long numberOfTents; // fuer die Anzahl der Zelte respektive Baeume
	private boolean showTents; // fuer die Steuerung der Anzeige der Zelte
	private long [][] fields; // fuer die Campingplatzfelder
	private long [] tentsInRow; // fuer die Anzahlen der Zelte in Reihen
	private long [] tentsInColumn; // fuer die Anzahlen der Zelte in Spalten
	private java.awt.image.BufferedImage bufferedImage; // fuer die graphische Anzeige
	private java.util.Random random; // fuer die Pseudozufallszahlenreihe
}

Konstruktor[Bearbeiten]

Der Konstruktor ist in Java eine spezielle öffentliche Methode, die namensgleich mit der Klasse zur Initialisierung von Instanzen verwendet wird.

Ein Campingplatzrätsel muss mit seiner Breite width und seiner Höhe height in Campingplatzfeldern sowie einer ersten Pseudozufallszahl seed' initialisiert werden. Der weitere Parameter showTents gibt an, ob die Lösung des Rätsels angezeigt werden soll (Wert CampingplatzGraphs.PUZZLE) oder nicht (Wert CampingplatzGraphs.SOLUTION):

	public CampingplatzGraphs (int width, int height, long seed, boolean showTents)
	{
		this.sizeX = width;
		this.sizeY = height;
		this.random = new java.util.Random (seed);
		this.seed = seed;
		this.setTitle ("Campingplatz " + width + " x " + height + " s " + seed);
		this.numberOfTents = 0;
		this.numberOfGuesses = 0;
		this.fields = new long [height] [width];
		this.tentsInRow = new long [height];
		this.tentsInColumn = new long [width];
		this.initArrays ();
		this.showTents = showTents;
		this.widthsInPixels = fieldSize * (width + 1) + 2 * offset;
		this.heightInPixels = fieldSize * (height + 1) + 2 * offset + 2 * offsetTop;
		this.setDefaultCloseOperation (javax.swing.WindowConstants.EXIT_ON_CLOSE);
		this.bufferedImage = new java.awt.image.BufferedImage (this.widthsInPixels, this.heightInPixels, java.awt.image.BufferedImage.TYPE_INT_RGB);
		this.addMouseListener (this);
	}

Bestimmung der zufälligen Lage von Zelten[Bearbeiten]

In den acht direkt an ein Zelt angrenzenden Campingplatzfeldern darf kein weiteres Zelt liegen, was mit der typengebundenen Methode tentIsPossible (int ix, int iy) überprüft werden kann.

Die kleinste mögliche Anzahl von Zelten ist insbesondere dann möglich, wenn sich an den Kanten des Campingplatzes wenige Zelte befinden. Jedes Zelt innerhalb der äußeren Parzellen hat einen zugeordneten Baum und sieben weitere direkte Nachbarfelder, die blockiert werden.

Die größte mögliche Anzahl von Zelten ist insbesondere dann möglich, wenn sich in jeder Ecke des Campingplatzes ein Zelt befindet, da jedes Zelt dort einen zugeordneten Baum hat und nur ein weiteres direktes Nachbarfeld blockiert wird.

Unter der Voraussetzung, dass keine potentiell nutzbare Parzelle frei bleiben soll, ergibt sich die maximale Anzahl der zu setzenden Zelte je nach Verteilung der Zelte aus der Anzahl Parzellen des Campingplatzes mit Spalten und Zeilen:

Bei 'ungeradzahligen Kantenlängen ergibt sich für die Anzahl der Spalten und die Anzahl der Reihen :

Bei geradzahligen Kantenlängen ergibt sich für die Anzahl der Spalten und die Anzahl der Reihen :

In diesem Fall kann also maximal je ein Viertel der Parzellen des Campingplatzes mit Zelten respektive mit Bäumen besetzt sein, und die andere Hälfte der Parzellen ist leer.

	private boolean tentIsPossible (int ix, int iy)
	{
		boolean tentPossible = (this.fields [iy] [ix] == EMPTY) && ((ix < (this.sizeX - 1)) || (iy < (this.sizeY - 1)));

		if (tentPossible)
		{
			if (iy > 0)
			{
				if (ix > 0)
				{
					tentPossible = tentPossible && (this.fields [iy - 1] [ix - 1] == EMPTY);
				}
				tentPossible = tentPossible && (this.fields [iy - 1] [ix] == EMPTY);
				if (ix < (this.sizeX - 1))
				{
					tentPossible = tentPossible && (this.fields [iy - 1] [ix + 1] == EMPTY);
				}
			}

			if (ix > 0)
			{
				tentPossible = tentPossible && (this.fields [iy] [ix - 1] == EMPTY);
			}
			tentPossible = tentPossible && (this.fields [iy] [ix] == EMPTY);
			if (ix < (this.sizeX - 1))
			{
				tentPossible = tentPossible && (this.fields [iy] [ix + 1] == EMPTY);
			}

			if (iy < (this.sizeY - 1))
			{
				if (ix > 0)
				{
					tentPossible = tentPossible && (this.fields [iy + 1] [ix - 1] == EMPTY);
				}
				tentPossible = tentPossible && (this.fields [iy + 1] [ix] == EMPTY);
				if (ix < (this.sizeX - 1))
				{
					tentPossible = tentPossible && (this.fields [iy + 1] [ix + 1] == EMPTY);
				}
			}
		}
		return tentPossible;
	}
Fallgrube bei der Verteilung der Bäume beim Campingplatzrätsel: dem Zelt unten rechts kann kein Baum mehr zugeordnet werden.

Der boolesche Ausdruck ((ix < (this.sizeX - 1)) || (iy < (this.sizeY - 1)) in der ersten Zeile der Blockanweisung der Methode trägt dem Umstand Rechnung, dass einem Zelt in der rechten unteren Ecke des Campingplatzes kein Baum mehr zugeordnet werden kann, falls die beiden Felder direkt darüber und direkt links daneben bereits mit Bäumen anderer Zelte blockiert sind. Dieses Problem ist rechts im Beispiel dargestellt, wo die Bäume direkt links und oberhalb des Zeltes rechts unten in der Ecke bereits durch andere Zelte besetzt sind. Dieses Problem kann nicht auftauchen, wenn in dem rechten unteren Feld kein Zelt positioniert wird.

Mit dem Aufruf der typengebundenen Methoden setTent () und setTents () werden die Positionen der zu erratenden Zelte bestimmt. Hierbei wird eine pseudozufällige Zahlenfolge genutzt, um die Zeilen und Spalten für potenzielle Zeltfelder zu berechnen. Mit der Methode tentsPossible () wird am Kopf der entsprechenden Schleife geprüft, ob es überhaupt noch möglich ist, neue Zelte zu setzen. Wird ein Platz für ein Zelt gefunden, wird die Instanzvariable numberOfTents inkrementiert.

	private boolean setTent (int ix, int iy)
	{
		boolean success = this.tentIsPossible (ix, iy);
		if (success)
		{
			this.fields [iy] [ix] = TENT;
		}
		return success;
	}

	private boolean tentsPossible ()
	{
		boolean tentPossible = false;

		int iy = 0; // oben starten
		while (! tentPossible && (iy < this.sizeY))
		{			
			int ix = 0; // links starten
			while (! tentPossible && (ix < this.sizeX))
			{
				tentPossible = this.tentIsPossible (ix, iy);
				ix++;
			}
			iy++;
		}
		return tentPossible;
	}

	private void setTents ()
	{
		boolean successful;
		while (this.tentsPossible ())
		{
			int x = this.pseudoRandomNumber (0, this.sizeX - 1);
			int y = this.pseudoRandomNumber (0, this.sizeY - 1);
			successful = this.setTent (x, y);
			if (successful)
			{
				this.numberOfTents++;
			}
		}
	}

Bestimmung der Lage der zugeordneten Bäume[Bearbeiten]

Die typengebundene Methode setTrees () dient zur Berechnung der zu den Zelten zugehörigen Bäume, die sich direkt oberhalb, rechts, unterhalb oder links eines jeden Zeltes befinden. Hierzu wird mit einer pseudozufällig bestimmten Himmelsrichtung (OBEN, RECHTS, UNTEN oder LINKS) begonnen, die durch den Methodenaufruf this.ganzePseudozufallszahl (OBEN, LINKS)' ermittelt wird. Nachdem ein Platz für einen Baum gefunden wurde, werden die Instanzvariablen für die Anzahl der Zelte in der betreffenden Zeile tentsInRow [iy] und für die Anzahl der Zelte in der betreffenden Spalte tentsInColumn [ix] inkrementiert, damit sie später angezeigt werden können.

	private void setTrees ()
	{
		int iy = 0; // oben starten
		while (iy < this.sizeY)
		{			
			int ix = 0; // links starten
			while (ix < this.sizeX)
			{
				if (this.fields [iy] [ix] == TENT)
				{
					boolean found = false;
					do
					{
						long randomDirection = this.pseudoRandomNumber (TOP, LEFT);
						if ((randomDirection == TOP) && (iy > 0))
						{
							found = this.fields [iy - 1] [ix] == EMPTY;
							setTree (ix, iy - 1);
						}
						else if ((randomDirection == RIGHT) && (ix < (sizeX - 1)))
						{
							found = this.fields [iy] [ix + 1] == EMPTY;
							setTree (ix + 1, iy);
						}
						else if ((randomDirection == BOTTOM) && (iy < (sizeY - 1)))
						{
							found = this.fields [iy + 1] [ix] == EMPTY;
							setTree (ix, iy + 1);
						}
						else if ((randomDirection == LEFT) && (ix > 1))
						{
							found = this.fields [iy] [ix - 1] == EMPTY;
							setTree (ix - 1, iy);
						}
					} while (! found);

					this.tentsInRow [iy]++;
					this.tentsInColumn [ix]++;
				}
				ix++;
			}
			iy++;
		}
	}

In manchen Fällen mit direkt benachbarten Baumpaaren kann anhand der Angabe der Zelte in den Spalten und Zeilen nicht eindeutig ermittelt werden, in welchen Zellen die Zelte liegen müssen. In diesen Fällen muss dann geraten werden.

Graphische Darstellung[Bearbeiten]

Die öffentliche, typengebundene Methode paint muss von der typengebundenen Methode init aufgerufen werden, um ein Labyrinth als Objekt der Java-Klasse java.awt.Graphics in einen Container beziehungsweise in ein Objekt vom Datentyp Component aus dem generischen Java-package awt (Abstract Window Toolkit) zu zeichnen. Sie überschreibt die paint-Methode ihrer Superklasse Window, von der die Java-Klassen javax.swing.JFrame und somit auch CampingplatzGraphs abgeleitet sind:

  • java.awt.Component
    • java.awt.Container
      • java.awt.Window
        • java.awt.Frame
          • javax.swing.JFrame
            • CampingplatzGraphs
	/**
	 *  Fuer die Initialisierung und der graphischen Ausgabe von Instanzen der Klasse
	 */
	public void init ()
	{
		this.setTents ();
		this.setTrees ();
		this.setSize (this.widthsInPixels, this.heightInPixels);
		this.setBackground (java.awt.Color.WHITE);
		java.awt.Graphics2D graphics2D = bufferedImage.createGraphics ();
		this.paint (graphics2D);
		this.setVisible (true);
		this.setAlwaysOnTop (true);
	}

	/**
	 * Ueberschreibt die Methode paint aus der Klasse java.awt.Window und zeichnet die Instanz
	 * @param graphics: graphisches Objekt der Klasse java.awt.Graphics
	 */
	public void paint (java.awt.Graphics graphics)
	{
		drawCampingSite (graphics, this);
	}

Maussteuerung[Bearbeiten]

Die Klasse CampingplatzGraphs implementiert die Klasse java.awt.event.MouseListener.[1] Diese verfügt über fünf typengebundene Methoden, die die Betätigung der Maustasten abfragt. Diese fünf Methoden müssen bei der Implementierung in der Klasse CampingplatzGraphs überschrieben werden.

Die Methode mouseClicked (java.awt.event.MouseEvent event) wird verwendet, um die Position der Maus im Fenster abzufragen, wenn eine Maustaste geklickt wurde. Hierzu werden die typengebundenen Methoden getX () und getY () der Klasse java.awt.event.MouseEvent des Parameters event aufgerufen. Die betätigen Maustasten können mit der typengebundenen Methode event.getButton () ermittelt werden. Die rechte Maustaste wird durch die Konstante java.awt.event.MouseEvent.BUTTON3 repräsentiert.[2]

Mit Hilfe der Methodenaufrufe getColumn (x) und getRow (y) kann aus den Fensterkoordinaten der Mausposition (x, y) das zugehörige Campingplatzfeld (column, row) ermittelt werden. Je nach Status des entsprechenden Campingplatzfelds und der betätigten Maustasten werden entweder mit einem Zelt markierte Felder, an denen ein Zelt vermutet wird (linke Maustaste), oder mit einem schwarzen Quadrat markierte Felder, an denen kein Zelt vermutet wird (rechte Maustaste), angezeigt.

Wenn genauso viele Zelte markiert wie gesucht sind, wird die Lösung des Rätsels eingeblendet.

Am Ende der Methode wird die Methode repaint () aufgerufen, um die Änderungen anzuzeigen.

	public void mouseClicked (java.awt.event.MouseEvent event)
	{
		final long right = java.awt.event.MouseEvent.BUTTON3;
		long button = event.getButton ();
		int x = event.getX ();
		int y = event.getY ();
		int column = getColumn (x);
		int row = getRow (y);
		long field = this.fields [row] [column];
		if ((this.showTents == PUZZLE) && (column >= 0) && (column < this.sizeX) && (row >= 0) && (row < this.sizeY))
		{
			if (field != TREE)
			{
				if (button == right)
				{
					if (field == EMPTY)
					{
						this.fields [row] [column] = CORRECT_BLOCK;
					}
					else if (field == TENT)
					{
						this.fields [row] [column] = WRONG_BLOCK;
					}
					else if (field == CORRECT_BLOCK)
					{
						this.fields [row] [column] = EMPTY;
					}
					else if (field == WRONG_BLOCK)
					{
						this.fields [row] [column] = TENT;
					}
				}
				else if (field == TENT)
				{
					this.fields [row] [column] = CORRECT_GUESS;
					this.numberOfGuesses++;
				}
				else if (field == EMPTY)
				{
					this.fields [row] [column] = WRONG_GUESS;
					this.numberOfGuesses++;
				}
				else if (field == CORRECT_GUESS)
				{
					this.fields [row] [column] = TENT;
					this.numberOfGuesses--;
				}
				else if (field == WRONG_GUESS)
				{
					this.fields [row] [column] = EMPTY;
					this.numberOfGuesses--;
				}
				this.repaint (10, x - fieldSize, y - fieldSize, 2 * fieldSize, 2 * fieldSize);
			}
			if (this.numberOfGuesses == this.numberOfTents)
			{
				this.showTents = SOLUTION;
				this.repaint ();
			}
		}
	}

Quelltext[Bearbeiten]

Mit dem folgenden Java-Programm mit der Klasse CampingplatzGraphs können graphische Campingplatzrätsel berechnet werden:

→ Java-Programm "CampingplatzGraphs"

Aufruf des Programms[Bearbeiten]

Mit dem Aufruf der folgenden öffentlichen Hauptmethode main kann ein zufällig erstelltes Campingplatzrätsel mit 7 mal 7 Feldern in der Breite und in der Höhe berechnet und gezeichnet werden: Ferner wird eine entsprechende Instanz mit der Lösung des Rätsels ausgegeben.

	public static void main (java.lang.String [] arguments)
	{
		int widthOfSite  = 7; // Breite des Campingplatzes
		int heightOfSite = 7; // Hoehe des Campingplatzes
		long seed = java.lang.System.currentTimeMillis (); // aktuelle Systemzeit in Millisekunden als Startwert fuer die Pseudozufallszahlenfolge

		CampingplatzGraphs campingSite = new CampingplatzGraphs (widthOfSite, heightOfSite, seed, CampingplatzGraphs.PUZZLE); // erzeugt und initialisiert die Instanz campingSite ohne Loesung
		campingSite.init (); // oeffnet ein Fenster mit der Anzeige von campingSite

		seed = campingSite.getSeed (); // holt den tatsaechlichen Startwert der Pseudozufallszahlenfolge der Instanz campingSite
		CampingplatzGraphs campingSiteTents = new CampingplatzGraphs (widthOfSite, heightOfSite, seed, CampingplatzGraphs.SOLUTION); // erzeugt und initialisiert die Instanz campingSiteTents mit Loesung
		campingSiteTents.init (); // oeffnet ein Fenster mit der Anzeige von campingSiteTents
		campingSiteTents.setState (java.awt.Frame.ICONIFIED); // minimiert das Fenster als Icon, damit der Inhalt zunaechst nicht angezeigt wird
	}

Nachwort[Bearbeiten]

Die hier angegebenen strukturierten Programmbeispiele können ohne große Umstände in jede andere strukturierte Programmiersprache übertragen werden. Durch die Modifikation und Ergänzung der angegebenen Algorithmen können mit Leichtigkeit anders gestaltete Campingplatzrätsel berechnet werden.

Es wäre erfreulich, wenn dieses Wikibook zu einem besseren und tieferen Verständnis der strukturierten Programmierung und als Einstieg in die Technik der iterativen Programmierung beitragen kann.

Einzelnachweise[Bearbeiten]

  1. java.awt.event.MouseListener, docs.oracle
  2. java.awt.event.MouseEvent, docs.oracle

Siehe auch[Bearbeiten]

Quelldateien[Bearbeiten]

CampingplatzGraphs[Bearbeiten]

/*
Source file: CampingplatzGraphs.java
Author: Markus Bautsch
Licence: public domain
Date: 19 October 2023
Version 1.1: 20 October 2023, implements java.awt.event.MouseListener
Version 1.2: 20 November 2023, invokes repaint (long time, int x, int y, int width, int height)
Programming language: Java
 */

/**
Graphische Ausgabe von Campingplatzraetseln.
<p>
Beim Campingplatzraetsel muessen Zelte auf einem rechteckigen Campingplatz mit quadratischen Feldern so verteilt werden,
dass rechts, links, oben oder unten neben jedem auf dem Campingplatz vorhandenen Baum genau ein diesem Baum zugeordnetes Zelt aufgestellt wird.
<p>
In den acht direkten Nachbarfeldern eines Zeltes darf kein weiteres Zelt vorhanden sein.
Am Spielfeldrand wird angezeigt, wie viele Zelte sich in den betreffenden Spalten und Zeilen befinden.
Die Gesamtzahl aller Zelte beziehungsweise auch aller Baeume steht in der unteren rechten Ecke.
<p>
Das Ziel des Spieles besteht darin, anhand dieser Zeilen- und Spaltensummern der Zelte sowie der Lage der Bäume die Lage aller Zelte herauszufinden.
 */

public final class CampingplatzGraphs extends javax.swing.JFrame implements java.awt.event.MouseListener
{
	// Oeffentliche Klassenkonstanten
	/**
	 * Wert fuer den Parameter "showTents" des Konstruktors ohne Anzeige der Loesung
	 */
	public final static boolean PUZZLE = false;
	/**
	 * Wert fuer den Parameter "showTents" des Konstruktors mit Anzeige der Loesung
	 */
	public final static boolean SOLUTION = true;

	// Klassenkonstanten
	private final static java.awt.Color backgroundColour = java.awt.Color.WHITE;
	// Fuer den Inhalt der Campingplatzfelder
	private final static long EMPTY = 0;
	private final static long TENT = 1;
	private final static long TREE = 2;
	private final static long CORRECT_GUESS = 3;
	private final static long WRONG_GUESS = 4;
	private final static long CORRECT_BLOCK = 5;
	private final static long WRONG_BLOCK = 6;

	// Fuer die Richtungen zu den Nachbarfeldern
	private final static long TOP = 0;
	private final static long RIGHT = 1;
	private final static long BOTTOM = 2;
	private final static long LEFT = 3;

	// Fuer die Groesse der Darstellung
	private final static int offset = 10; // fuer die umlaufende Breite des Randes
	private final static int offsetTop = 30; // fuer den Titelbanner des graphischen Fensters
	private final static int fieldSize = 64; // fuer die Groesse der Campingplatzfelder

	// Instanzkonstanten
	private final int sizeX; // fuer die Breite in Campingplatzfeldern
	private final int sizeY; // fuer die Hoehe in Campingplatzfeldern
	private final int widthsInPixels; // fuer die Breite in Bildpunkten
	private final int heightInPixels; // fuer die Hoehe in Bildpunkten
	private final long seed; // fuer den Startwert der Pseudozufallszahlenreihe

	// Instanzvariablen
	private long numberOfTents; // fuer die Anzahl der Zelte respektive Baeume
	private boolean showTents; // fuer die Steuerung der Anzeige der Zelte
	private long numberOfGuesses; // fuer die Anzahl der Zelte respektive Baeume
	private long [][] fields; // fuer die Campingplatzfelder
	private long [] tentsInRow; // fuer die Anzahlen der Zelte in Reihen
	private long [] tentsInColumn; // fuer die Anzahlen der Zelte in Spalten
	private java.awt.image.BufferedImage bufferedImage; // fuer die graphische Anzeige
	private java.util.Random random; // fuer die Pseudozufallszahlenreihe

	// serialVersionUID fuer die Serialisation, die in der Klasse javax.swing.JFrame implementiert ist.
	private final static long serialVersionUID = 1;

	/** Konstruktor fuer die Initialisierung von Instanzen der Klasse CampingplatzGraphs.
	 * @param width:  Anzahl der Felder des Campingplatzes in der Breite
	 * @param height: Anzahl der Felder des Campingplatzes in der Hoehe
	 * @param seed: Startwert fuer die pseudozufaelligen Lagen der Zelte auf dem Campingplatz
	 * @param showTents: fuer die Anzeige ohne Loesung = PUZZLE und fuer die Anzeige mit Loesung = SOLUTION
	 */
	public CampingplatzGraphs (int width, int height, long seed, boolean showTents)
	{
		this.sizeX = width;
		this.sizeY = height;
		this.random = new java.util.Random (seed);
		this.seed = seed;
		this.setTitle ("Campingplatz " + width + " x " + height + " s " + seed);
		this.numberOfTents = 0;
		this.numberOfGuesses = 0;
		this.fields = new long [height] [width];
		this.tentsInRow = new long [height];
		this.tentsInColumn = new long [width];
		this.initArrays ();
		this.showTents = showTents;
		this.widthsInPixels = fieldSize * (width + 1) + 2 * offset;
		this.heightInPixels = fieldSize * (height + 1) + 2 * offset + offsetTop;
		this.setDefaultCloseOperation (javax.swing.WindowConstants.EXIT_ON_CLOSE);
		this.bufferedImage = new java.awt.image.BufferedImage (this.widthsInPixels, this.heightInPixels, java.awt.image.BufferedImage.TYPE_INT_RGB);
		this.addMouseListener (this);
	}

	/**
	 *  Speichert eine Instanz in einer Datei im PNG-Format.
	 */
	public void saveFile ()
	{
		final java.lang.String fileExtension = "png";
		java.util.Iterator <javax.imageio.ImageWriter> iter = javax.imageio.ImageIO.getImageWritersByFormatName (fileExtension);
		javax.imageio.ImageWriter imageWriter = (javax.imageio.ImageWriter) iter.next ();
		javax.imageio.ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam ();
		imageWriteParam.setCompressionMode (javax.imageio.ImageWriteParam.MODE_DEFAULT); // for compressed file
		try
		{
			java.lang.String fileName = this.getTitle ();
			if (this.showTents)
			{
				fileName = fileName + " solution";
			}

			fileName = fileName + "." + fileExtension;
			javax.imageio.stream.FileImageOutputStream fileImageOutputStream = new javax.imageio.stream.FileImageOutputStream (new java.io.File (fileName));
			imageWriter.setOutput (fileImageOutputStream);
			javax.imageio.IIOImage iIOimg = new javax.imageio.IIOImage ((java.awt.image.RenderedImage) bufferedImage, null, null);
			java.lang.System.out.println ("Save " + fileName);
			imageWriter.write (null, iIOimg, imageWriteParam);
		}
		catch (java.lang.Exception exception)
		{
			exception.printStackTrace ();
		}
	}

	/**
	 * Die Methode gibt die verwendete erste Pseudozufallszahl der Instanz zurueck, mit welcher die Lage der Zelte und Baeume ermittelt wird.
	 * Diese Pseudozufallszahl kann verwendet werden, um ein bestehendes Raetsel erneut mit oder ohne Loesung anzeigen zu lassen,
	 * indem eine neue Instanz mit dem entsprechenden Parameter showTents erzeugt und mit der Methode init initialisiert wird.
	 * @return erste Pseudozufallszahl der Instanz
	 */
	public long getSeed ()
	{
		return this.seed;
	}

	/*
	 * Ermittelt eine pseudozufaellige Zahl zwischen min und max
	 * @param zmin: kleinste pseudozufaelligen Zahl
	 * @param zmax: groesste pseudozufaelligen Zahl
	 * @return: ganze Zahl zwischen zmin und zmax (einschliesslich)
	 */
	private int pseudoRandomNumber (long zmin, long zmax)
	{
		long nextPseudoRandomNumber = java.lang.Math.abs (this.random.nextLong ());
		long pseudoRandomNumber = (nextPseudoRandomNumber % (zmax - zmin + 1)) + zmin;
		return (int) pseudoRandomNumber;
	}

	/*
	 * Initialisiert einen Campingplatz mit leeren Feldern
	 * @param campingplatzGraph: CampingplatzGraphs
	 */
	private void initArrays ()
	{
		int ix; // Zaehler fuer Spalten in x-Richtung nach rechts
		int iy; // Zaehler fuer Zeilen in y-Richtung nach unten

		ix = 0; // links starten
		while (ix < this.sizeX)
		{			
			this.tentsInColumn [ix] = 0;
			ix++;
		}

		iy = 0; // oben starten
		while (iy < this.sizeY)
		{			
			ix = 0; // links starten
			while (ix < this.sizeX)
			{
				this.fields [iy] [ix] = EMPTY;
				ix++;
			}
			this.tentsInRow [iy] = 0;
			iy++;
		}
	}

	/*
	 * Ermittelt die linke Kante einer Campingplatzspalte
	 * @param ix: linke Kante einer Campingplatzspalte in Graphikfensterkoordinaten
	 */
	private static int getLeftEdge (int ix)
	{
		int leftEdge = offset + (ix * fieldSize);
		return leftEdge;
	}

	/*
	 * Ermittelt die obere Kante einer Campingplatzzeile
	 * @param iy: obere Kante einer Campingplatzzeile in Graphikfensterkoordinaten
	 */
	private static int getUpperEdge (int iy)
	{
		int upperEdge = offsetTop + offset + (iy * fieldSize);
		return upperEdge;
	}

	/*
	 * Ermittelt die Campingplatzspalte aus der x-Koordinate des Graphikfensters
	 * @param x: x-Koordinate des Graphikfensters
	 */
	private static int getColumn (int x)
	{
		int column = (x - offset) / fieldSize;
		return column;
	}

	/*
	 * Ermittelt die Campingplatzzeile aus der y-Koordinate des Graphikfensters
	 * @param y: y-Koordinate des Graphikfensters
	 */
	private static int getRow (int y)
	{
		int row = (y - offsetTop - offset) / fieldSize;
		return row;
	}

	/*
	 * Zeichnet ein leeres Campingplatzfeld
	 * @param java.awt.Graphics: Graphikfenster
	 * @param ix: Spalte des Campingplatzes
	 * @param iy: Zeile des Campingplatzes
	 */
	private static void drawFieldBackground (java.awt.Graphics graphics, int ix, int iy)
	{
		int leftEdge = getLeftEdge (ix);
		int upperEdge = getUpperEdge (iy);
		final java.awt.Color lawnColour = new java.awt.Color (63, 95, 0);
		graphics.setColor (lawnColour);
		graphics.fillRect (leftEdge + 1, upperEdge + 1, fieldSize - 2, fieldSize - 2);
	}

	/*
	 * Zeichnet ein geblocktes Campingplatzfeld
	 * @param java.awt.Graphics: Graphikfenster
	 * @param ix: Spalte des Campingplatzes
	 * @param iy: Zeile des Campingplatzes
	 */
	private static void drawBlock (java.awt.Graphics graphics, int ix, int iy)
	{
		int leftEdge = getLeftEdge (ix);
		int upperEdge = getUpperEdge (iy);
		final java.awt.Color blockColour = java.awt.Color.BLACK;
		graphics.setColor (blockColour);
		int start = fieldSize / 4;
		int width = fieldSize / 2;
		graphics.fillRect (leftEdge + start, upperEdge + start, width, width);
	}

	/*
	 * Zeichnet ein Zelt
	 * @param java.awt.Graphics: Graphikfenster
	 * @param ix: Spalte des Campingplatzes
	 * @param iy: Zeile des Campingplatzes
	 * @param guess: true, if still only a guess
	 */
	private static void drawTent (java.awt.Graphics graphics, int ix, int iy, boolean guess)
	{
		int leftEdge = getLeftEdge (ix);
		int upperEdge = getUpperEdge (iy);
		java.awt.Color tentColour;

		int [] xArray = new int [4];
		int [] yArray = new int [4];

		if (guess)
		{
			tentColour = new java.awt.Color (255, 191, 0);		
		}
		else
		{
			tentColour = new java.awt.Color (255, 127, 0);
		}
		xArray [0] = leftEdge +  fieldSize *  8 / 16;
		yArray [0] = upperEdge + fieldSize * 13 / 16;
		xArray [1] = leftEdge +  fieldSize *  7 / 16;
		yArray [1] = upperEdge + fieldSize *  6 / 16;
		xArray [2] = leftEdge +  fieldSize * 11 / 16;
		yArray [2] = upperEdge + fieldSize *  5 / 16;
		xArray [3] = leftEdge +  fieldSize * 14 / 16;
		yArray [3] = upperEdge + fieldSize * 10 / 16;
		graphics.setColor (tentColour);
		graphics.fillPolygon (xArray, yArray, 4);
		graphics.setColor (java.awt.Color.BLACK);
		graphics.drawPolygon (xArray, yArray, 4);

		tentColour = new java.awt.Color (191, 63, 0);
		xArray [2] = leftEdge +  fieldSize *  2 / 16;
		yArray [2] = upperEdge + fieldSize * 11 / 16;
		graphics.setColor (tentColour);
		graphics.fillPolygon (xArray, yArray, 3);
		graphics.setColor (java.awt.Color.BLACK);
		graphics.drawPolygon (xArray, yArray, 3);
	}

	/*
	 * Zeichnet einen Baum
	 * @param java.awt.Graphics: Graphikfenster
	 * @param ix: Spalte des Campingplatzes
	 * @param iy: Zeile des Campingplatzes
	 */
	private static void drawTree (java.awt.Graphics graphics, int ix, int iy)
	{
		int leftEdge = getLeftEdge (ix);
		int upperEdge = getUpperEdge (iy);
		int diameter = (fieldSize - 2) / 2;
		java.awt.Color treeColour;

		treeColour = new java.awt.Color (63, 63, 0);
		graphics.setColor (treeColour);
		graphics.fillRect (leftEdge + fieldSize * 7 / 16, upperEdge + fieldSize / 2, fieldSize / 8, fieldSize / 2);

		treeColour = new java.awt.Color (0, 159, 0);
		graphics.setColor (treeColour);
		graphics.fillOval (leftEdge + 1, upperEdge + 1 + fieldSize / 4, diameter, diameter);

		treeColour = new java.awt.Color (0, 175, 0);
		graphics.setColor (treeColour);
		graphics.fillOval (leftEdge + 1 + fieldSize / 2, upperEdge + 1 + fieldSize / 4, diameter, diameter);

		treeColour = new java.awt.Color (0, 191, 0);
		graphics.setColor (treeColour);
		graphics.fillOval (leftEdge + 1 + fieldSize / 4, upperEdge + 1, diameter, diameter);
	}

	/*
	 * Zeichnet ein Campingplatzfeld
	 * @param java.awt.Graphics: Graphikfenster
	 * @param ix: Spalte des Campingplatzes
	 * @param iy: Zeile des Campingplatzes
	 */
	private static void drawField (java.awt.Graphics graphics, CampingplatzGraphs campingplatzGraph, int ix, int iy)
	{
		drawFieldBackground (graphics, ix, iy);
		long field = campingplatzGraph.fields [iy] [ix];
		if ((field == CORRECT_BLOCK) || (field == WRONG_BLOCK) || (campingplatzGraph.showTents && (field == WRONG_GUESS)))
		{
			drawBlock (graphics, ix, iy);
		}
		if (campingplatzGraph.showTents && ((field == TENT) || (field == WRONG_BLOCK) || (field == CORRECT_GUESS)))
		{
			boolean noGuess = false;
			drawTent (graphics, ix, iy, noGuess);
		}
		else if ((field == CORRECT_GUESS) || (field == WRONG_GUESS))
		{
			boolean guess = true;
			drawTent (graphics, ix, iy, guess);
		}
		else if (field == TREE)
		{
			drawTree (graphics, ix, iy);
		}
	}

	/*
	 * Schreibt rechts die Anzahl der Zelte fuer alle Zeilen
	 * @param campingplatzGraph: CampingplatzGraphs
	 * @param iy: Zeile des Campingplatzes
	 */
	private static void drawNumberOfTentsPerRow (java.awt.Graphics graphics, CampingplatzGraphs campingplatzGraph)
	{
		int leftEdge = getLeftEdge (campingplatzGraph.sizeX) + fieldSize / 4;
		graphics.setColor (java.awt.Color.BLACK);
		java.awt.Font font = new java.awt.Font ("Arial", java.awt.Font.BOLD, fieldSize / 2);
		graphics.setFont (font);

		int iy = 0; // oben starten
		while (iy < campingplatzGraph.sizeY)
		{
			int upperEdge = getUpperEdge (iy) + fieldSize * 3 / 4;
			graphics.drawString ("" + campingplatzGraph.tentsInRow [iy], leftEdge, upperEdge);
			iy++;
		}
	}

	/*
	 * Schreibt unten die Anzahl der Zelte fuer alle Spalten
	 * @param campingplatzGraph: CampingplatzGraphs
	 */
	private static void drawNumberOfTentsPerColumn (java.awt.Graphics graphics, CampingplatzGraphs campingplatzGraph)
	{
		int upperEdge = getUpperEdge (campingplatzGraph.sizeY) + fieldSize / 2;
		graphics.setColor (java.awt.Color.BLACK);
		java.awt.Font font = new java.awt.Font ("Arial", java.awt.Font.BOLD, fieldSize / 2);
		graphics.setFont (font);

		int ix = 0; // links starten
		while (ix < campingplatzGraph.sizeX)
		{
			int leftEdge = getLeftEdge (ix) + fieldSize / 3;
			graphics.drawString ("" + campingplatzGraph.tentsInColumn [ix], leftEdge, upperEdge);
			ix++;
		}
	}

	/*
	 * Schreibt die Gesamtzahl der Zelte rechts unten in die Ecke
	 * @param campingplatzGraph: CampingplatzGraphs
	 */
	private static void drawNumberOfTents (java.awt.Graphics graphics, CampingplatzGraphs campingplatzGraph)
	{
		int leftEdge = getLeftEdge (campingplatzGraph.sizeX) + fieldSize / 4;
		int upperEdge = getUpperEdge (campingplatzGraph.sizeY) + fieldSize / 2;
		graphics.setColor (java.awt.Color.BLACK);
		java.awt.Font font = new java.awt.Font ("Arial", java.awt.Font.BOLD, fieldSize / 2);
		graphics.setFont (font);
		graphics.drawString ("" + campingplatzGraph.numberOfTents, leftEdge, upperEdge);
	}

	/*
	 * Zeichnet einen Campingplatz
	 * @param campingplatzGraph: CampingplatzGraphs
	 */
	private void drawCampingSite (java.awt.Graphics graphics, CampingplatzGraphs campingplatzGraph)
	{
		// Hintergrundfarbe setzen
		graphics.setColor (backgroundColour);
		graphics.fillRect (0, 0, campingplatzGraph.widthsInPixels, campingplatzGraph.heightInPixels);

		int iy = 0; // oben starten
		while (iy < campingplatzGraph.sizeY)
		{			
			int ix = 0; // links starten
			while (ix < campingplatzGraph.sizeX)
			{
				drawField (graphics, campingplatzGraph, ix, iy);
				ix++;
			}
			iy++;
		}

		drawNumberOfTentsPerRow (graphics, campingplatzGraph);
		drawNumberOfTentsPerColumn (graphics, campingplatzGraph);
		drawNumberOfTents (graphics, campingplatzGraph);
	}

	/*
	 * Setzt einen Baum auf ein Campingplatzfeld
	 * @param ix: Spalte des Campingplatzes
	 * @param iy: Zeile des Campingplatzes
	 * @return: true, wenn Zelt gesetzt werden konnte
	 */
	private void setTree (int ix, int iy)
	{
		boolean success = this.fields [iy] [ix] == EMPTY;
		if (success)
		{
			this.fields [iy] [ix] = TREE;
		}
	}

	/*
	 * Setzt die Baeume zu den Zelten und zaehlt die Zelte in Spalten und Reihen
	 */
	private void setTrees ()
	{
		int iy = 0; // oben starten
		while (iy < this.sizeY)
		{			
			int ix = 0; // links starten
			while (ix < this.sizeX)
			{
				if (this.fields [iy] [ix] == TENT)
				{
					boolean found = false;
					do
					{
						long randomDirection = this.pseudoRandomNumber (TOP, LEFT);
						if ((randomDirection == TOP) && (iy > 0))
						{
							found = this.fields [iy - 1] [ix] == EMPTY;
							setTree (ix, iy - 1);
						}
						else if ((randomDirection == RIGHT) && (ix < (sizeX - 1)))
						{
							found = this.fields [iy] [ix + 1] == EMPTY;
							setTree (ix + 1, iy);
						}
						else if ((randomDirection == BOTTOM) && (iy < (sizeY - 1)))
						{
							found = this.fields [iy + 1] [ix] == EMPTY;
							setTree (ix, iy + 1);
						}
						else if ((randomDirection == LEFT) && (ix > 1))
						{
							found = this.fields [iy] [ix - 1] == EMPTY;
							setTree (ix - 1, iy);
						}
					} while (! found);

					this.tentsInRow [iy]++;
					this.tentsInColumn [ix]++;
				}
				ix++;
			}
			iy++;
		}
	}

	/*
	 * Prueft, ob ein Zelt auf das angegebene Campingplatzfeld gesetzt werden kann
	 * @param ix: Spalte des Campingplatzes
	 * @param iy: Zeile des Campingplatzes
	 * @return: true, wenn Zelt gesetzt werden kann
	 */
	private boolean tentIsPossible (int ix, int iy)
	{
		boolean tentPossible = (this.fields [iy] [ix] == EMPTY) && ((ix < (this.sizeX - 1)) || (iy < (this.sizeY - 1)));

		if (tentPossible)
		{
			if (iy > 0)
			{
				if (ix > 0)
				{
					tentPossible = tentPossible && (this.fields [iy - 1] [ix - 1] == EMPTY);
				}
				tentPossible = tentPossible && (this.fields [iy - 1] [ix] == EMPTY);
				if (ix < (this.sizeX - 1))
				{
					tentPossible = tentPossible && (this.fields [iy - 1] [ix + 1] == EMPTY);
				}
			}

			if (ix > 0)
			{
				tentPossible = tentPossible && (this.fields [iy] [ix - 1] == EMPTY);
			}
			tentPossible = tentPossible && (this.fields [iy] [ix] == EMPTY);
			if (ix < (this.sizeX - 1))
			{
				tentPossible = tentPossible && (this.fields [iy] [ix + 1] == EMPTY);
			}

			if (iy < (this.sizeY - 1))
			{
				if (ix > 0)
				{
					tentPossible = tentPossible && (this.fields [iy + 1] [ix - 1] == EMPTY);
				}
				tentPossible = tentPossible && (this.fields [iy + 1] [ix] == EMPTY);
				if (ix < (this.sizeX - 1))
				{
					tentPossible = tentPossible && (this.fields [iy + 1] [ix + 1] == EMPTY);
				}
			}
		}
		return tentPossible;
	}

	/*
	 * Setzt ein Zelt auf ein Campingplatzfeld, wenn das Feld noch zur Verfuegung steht
	 * @param ix: Spalte des Campingplatzes
	 * @param iy: Zeile des Campingplatzes
	 * @return: true, wenn Zelt gesetzt werden konnte
	 */
	private boolean setTent (int ix, int iy)
	{
		boolean success = this.tentIsPossible (ix, iy);
		if (success)
		{
			this.fields [iy] [ix] = TENT;
		}
		return success;
	}

	/*
	 * Prueft, ob auf dem Campingplatz noch ein Zelt gesetzt werden kann
	 * @return: true, wenn noch ein Zelt gesetzt werden kann
	 */
	private boolean tentsPossible ()
	{
		boolean tentPossible = false;

		int iy = 0; // oben starten
		while (! tentPossible && (iy < this.sizeY))
		{			
			int ix = 0; // links starten
			while (! tentPossible && (ix < this.sizeX))
			{
				tentPossible = this.tentIsPossible (ix, iy);
				ix++;
			}
			iy++;
		}
		return tentPossible;
	}

	/*
	 * Verteilt auf dem Campingplatz pseudozufaellig Zelte und zaehlt sie
	 */
	private void setTents ()
	{
		boolean successful;
		while (this.tentsPossible ())
		{
			int x = this.pseudoRandomNumber (0, this.sizeX - 1);
			int y = this.pseudoRandomNumber (0, this.sizeY - 1);
			successful = this.setTent (x, y);
			if (successful)
			{
				this.numberOfTents++;
			}
		}
	}

	/**
	 * Ueberschreibt die Methode paint aus der Klasse java.awt.Window und zeichnet die Instanz
	 * @param graphics: graphisches Objekt der Klasse java.awt.Graphics
	 */
	public void paint (java.awt.Graphics graphics)
	{
		drawCampingSite (graphics, this);
	}

	/**
	 *  Fuer die Initialisierung und der graphischen Ausgabe von Instanzen der Klasse
	 */
	public void init ()
	{
		this.setTents ();
		this.setTrees ();
		this.setSize (this.widthsInPixels, this.heightInPixels);
		this.setBackground (java.awt.Color.WHITE);
		java.awt.Graphics2D graphics2D = bufferedImage.createGraphics ();
		this.paint (graphics2D);
		this.setVisible (true);
		this.setAlwaysOnTop (true);
	}

	public void mousePressed (java.awt.event.MouseEvent event)
	{
	}

	public void mouseReleased (java.awt.event.MouseEvent event)
	{
	}

	public void mouseEntered (java.awt.event.MouseEvent event)
	{
	}

	public void mouseExited (java.awt.event.MouseEvent event)
	{
	}

	public void mouseClicked (java.awt.event.MouseEvent event)
	{
		final long right = java.awt.event.MouseEvent.BUTTON3;
		long button = event.getButton ();
		int x = event.getX ();
		int y = event.getY ();
		int column = getColumn (x);
		int row = getRow (y);
		long field = this.fields [row] [column];
		if ((this.showTents == PUZZLE) && (column >= 0) && (column < this.sizeX) && (row >= 0) && (row < this.sizeY))
		{
			if (field != TREE)
			{
				if (button == right)
				{
					if (field == EMPTY)
					{
						this.fields [row] [column] = CORRECT_BLOCK;
					}
					else if (field == TENT)
					{
						this.fields [row] [column] = WRONG_BLOCK;
					}
					else if (field == CORRECT_BLOCK)
					{
						this.fields [row] [column] = EMPTY;
					}
					else if (field == WRONG_BLOCK)
					{
						this.fields [row] [column] = TENT;
					}
				}
				else if (field == TENT)
				{
					this.fields [row] [column] = CORRECT_GUESS;
					this.numberOfGuesses++;
				}
				else if (field == EMPTY)
				{
					this.fields [row] [column] = WRONG_GUESS;
					this.numberOfGuesses++;
				}
				else if (field == CORRECT_GUESS)
				{
					this.fields [row] [column] = TENT;
					this.numberOfGuesses--;
				}
				else if (field == WRONG_GUESS)
				{
					this.fields [row] [column] = EMPTY;
					this.numberOfGuesses--;
				}
				this.repaint (10, x - fieldSize, y - fieldSize, 2 * fieldSize, 2 * fieldSize);
			}
			if (this.numberOfGuesses == this.numberOfTents)
			{
				this.showTents = SOLUTION;
				this.repaint ();
			}
		}
	}
}