Campingplatzrätsel/ CampingplatzGraphs

/*
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 ();
			}
		}
	}
}