import java.io.IOException;

/***********************************************************************************
 * Task / Aufgabe
 ***********************************************************************************
 * *  Implement the A* algorithm to solve the puzzle problem known from
 *    the exercises. Use the following heuristic to calculate the distance:
 * 
 *    - The distance from start is the number of steps needed to reach the current
 *      state, e.g., the direct neighbour state has distance 1 and so on.
 *    - The distance to destination is the number of blocks on wrong positions, e.g.,
 *       1 2 3		1 2 3
 *       4 5 6		4 5 6
 *       8 7 #		7 8 #
 *      (start)   (destination)
 *      The distance from start to destination would be 2. (Note: start cannot be solved.)
 *      (7 and 8 are on wrong positions)
 *	Hints: 	When testing, be aware that some puzzle states cannot be solved.
 *			Try not to consider predecessor states, since they have already 
 *			been processed. 
 *      
 * *  Implementieren Sie den A* Algorithmus, um das in den Übungen behandelte Puzzle 
 *    Problem zu lösen.
 *    Verwenden Sie folgende Heuristik für die Berechnung der Entfernungskosten:
 * 
 *    - Die Entfernung vom Startknoten ist die Anzahl der benötigten Schritte
 *      bis zum aktuellen Zustand, z.B. der unmittelbare Nachbarzustand hat
 *      die Entfernung 1, usw.
 *    - Die Entfernung zum Zielknoten ist die Anzahl der Puzzleteile, 
 *      die an den falschen Positionen sind, z.B.
 *       1 2 3		1 2 3
 *       4 5 6		4 5 6
 *       8 7 #		7 8 #
 *      (Start)    (Ziel)
 *      The Entfernung zwischen Start und Ziel wäre 2.(Achtung: Start ist unlösbar.)
 *      (7 und 8 sind an falschen Positionen)
 *	Hinweise: 	Achten Sie beim Testen, dass bestimmte Zustände möglicherweise
 *				nicht lösbar sind. Versuchen Sie die Vorgängerzustände nicht zu
 *				betrachten, da sie ja schon bearbeitet wurden. 
 ***********************************************************************************/

/***********************************************************************************
 * Questions / Fragen
 ***********************************************************************************
 * 
 * ----------------------------------------------------------------
 * a) Choose and implement another two heuristics to calculate the distance, 
 *    e.g., one could use the heuristic introduced in the exercises or similar 
 *    versions of it.
 * 	  Use TPTP to profile Puzzle.main() with all three heuristics. 
 * 	  i)  Which heuristic did you choose? Why? Discuss them.
 *    	  Which heuristic was the best? 
 *    ii) What was the largest puzzle (NxN) used?
 *    
 * Enter at least 5 different, meaningful runs in the table below. 
 * 
 * a) Wählen und implementieren Sie zwei zusätzliche Heuristiken für die 
 * 	  Berechnung der Enfernungskosten. Sie können z.B. die in der Übung
 *    vorgestellte Heuristik verwenden, oder ähnliches.
 *    Verwenden Sie TPTP um Puzzle.main() zu profilen.
 *    i)  Welche Heuristiken haben Sie gewählt? Wieso? Diskutieren Sie sie.
 *        Welche Heuristik war die beste? 
 *    ii) Welche Größe(NxN) hatten die verwendeten Puzzles?
 *    
 * Tragen Sie mindestens 5 verschiedene, aussagekräftige Resultate in der Tabelle ein.
 * ----------------------------------------------------------------
 * 
 * TODO: Answer / Antwort
 * 
 * 				|    heuristic 1   	|    heuristic 2   	|   heuristic 3
 * -------------+-------+-----------+-------+-----------+-------+--------
 * NxN puzzle	|	ms	|  steps	|	ms	|  steps	|	ms	|  steps
 * -------------+-------+-----------+-------+-----------+-------+--------	
 * 				|					|					|	
 * 				|					|					|	
 * 				|					|					|	
 * 				|					|					|	
 * 				|					|					|	
 *  
 *   ms    - time needed to find the solution
 *   steps - steps needed to reach the destination
 ***********************************************************************************/

/**
 * The class from where the puzzle is loaded and prepared for processing
 */

public class Puzzle extends PuzzleAStar
{
	/**
	 * Initialise the puzzle states (Start and Destination)
	 * 
	 * @param start
	 * @param destination
	 */
	public Puzzle (PuzzleMove start, PuzzleMove destination)
	{
		setStartState(start);
		setDestinationState(destination);
	}
	
	/**
	 * The main method
	 * 
	 * @param args
	 * @throws IOException
	 */
	public static void main(String[] args) throws IOException
	{
		// TODO: Implement all necessary calls here
		
		// TODO: Use to read the puzzle input, for instance, the following code
		// PuzzleInputOutput pio = new PuzzleInputOutput("test.txt");
		
		/* TODO: Initialise the puzzle and process it, e.g.,
		 * 
	     * ...
		 * Puzzle puzzle = new Puzzle(start, destination);
		 * ...
		 * TODO: Do not forget to set the heuristic you are using to calculate the destination
		 * ...
		 * puzzle.findDestination();
		 * ...
		 */
		
		// TODO: Use System.out.println(xy) to give information about:
		//		 - the heuristic currently used
		//		 - current start state
		//		 - the destination
		
		// TODO: Try different scenarios, test your implementation thoroughly
		
		/* TODO: Some hints
		 * Similar code can be used to create the graph and operate on it
		 * 
		 * DirectedGraph<PuzzleMove, Integer> graph = 
		 * 						new SimpleDirectedWeightedGraph<PuzzleMove, Integer>(Integer.class);
		 * 
		 * int id = 0;
		 * ...
		 * PuzzleMove pa = new PuzzleMove();
         * PuzzleMove pb = new PuzzleMove();
         * ...
		 * graph.addVertex(pa);
         * graph.addVertex(pb);
         * graph.addEdge(pa, pb, id);
         * ...
         * 
         * Very useful can be the graph methods edgesOf(x), getEdgeSource(y) and getEdgeTarget(z).
         * 
		 */
	}
}
