college/ss2010/gdi2/java/Project2/src/PuzzleAStar.java
2013-12-19 19:05:28 +01:00

244 lines
6.1 KiB
Java

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.jgrapht.DirectedGraph;
import org.jgrapht.graph.SimpleDirectedWeightedGraph;
/**
* This class represents the implementation of the A* algorithm
*/
public abstract class PuzzleAStar {
private DirectedGraph<PuzzleMove, Integer> graph; // vertex: PuzzleMove
// edge: Integer (use an int value as a unique ID)
private PuzzleMove startState; // the start state of the puzzle
private PuzzleMove destinationState; // the destination state of the puzzle
private PuzzleMove currentState; // the current explored puzzle state
private List<PuzzleMove> movesToProcess; // the number of moves not taken yet
private long startPuzzleTime; // Timing variables
private long endPuzzleTime;
/**
* Initializes PuzzleAStar
*/
void init() {
//Create ArrayList for moves
movesToProcess = new ArrayList<PuzzleMove>();
//Create graph
graph = new SimpleDirectedWeightedGraph<PuzzleMove, Integer>(Integer.class);
//Set currentState to startState
this.currentState = startState;
//Add StartState to graph
graph.addVertex(startState);
}
/**
* This method implements the A* algorithm for the puzzle
*/
public void findDestination() {
//check input data
if(currentState == null){
return;
}
//save the start time
startPuzzleTime = System.currentTimeMillis();
//integer identification for edges
int edgecount = 0;
//Add all possible Moves of startState to movesToProcess
movesToProcess.addAll(currentState.successorMoves());
//Do as long destination is not reached
while(!currentState.equals(destinationState))
{
PuzzleMove nextstep = null;
for(int i=0; i< movesToProcess.size(); i++)
{
//calculate distance of Move - need to be done here cuz PuzzleMove has no
//access to destinationState
movesToProcess.get(i).calculateDistance(this.destinationState);
//identify best move in movesToProcess
if(nextstep == null)
{
//no move found till now
nextstep = movesToProcess.get(i);
} else
{
//is move better then last identified?
if(nextstep.getCost() > movesToProcess.get(i).getCost())
{
nextstep = movesToProcess.get(i);
}
}
}
//movesToProcess is empty. There is no connection from start to destination
if(nextstep == null)
{
//no way found
break;
}
//try to add identified step. If not possible it is already in the graph
if(graph.addVertex(nextstep))
{
//Add an edge from identified step's predecessor to identified step
graph.addEdge(nextstep.getPredecessorMove(), nextstep,edgecount++);
//now continue with identified step
currentState = nextstep;
//add all successorMoves to movesToProcess
movesToProcess.addAll(currentState.successorMoves());
}
//remove the identified step from movesToProcess
movesToProcess.remove(nextstep);
}
//save end time
endPuzzleTime = System.currentTimeMillis();
}
/**
* This method prints a summary of the solution
*
* @param state The final puzzle state (Destination)
*/
public void printSolutionSummary(PuzzleMove state) {
System.out.println("Time needed to find Destination (ms): " + (this.endPuzzleTime-this.startPuzzleTime));
System.out.println("Current cost at final state (Destination): " + state.getCost());
System.out.println("States processed so far: " + numberOfProcessedStates());
System.out.println("States identified for processing (not being processed): " + numberOfStatesToProcess());
}
/**
* This method prints the path to the solution
*
* Make sure you called findDestination() first.
* This method only works if the A* Algorithm was
* calculated before.
*
* Uses currentState & destinationState
*
* @param graph
*/
public void printPathToSolution(DirectedGraph<PuzzleMove, Integer> graph) {
System.out.println("\nThe steps/path needed to reach the destination:\n");
//Check if A* was successful
if(!currentState.equals(destinationState)){
System.out.println("No Path to Solution found");
return;
}
//Add String representation of destinationState
String result = currentState.toString();
PuzzleMove curMove = destinationState;
//Move from destination to start
while(!curMove.equals(startState))
{
//get incoming edges
Set<Integer> s = graph.incomingEdgesOf(curMove);
//No or more then one edge found - something is wrong
if(s.size() != 1)
{
System.out.println("An Error occured: Graph destination has no or to many connections to start");
return;
}
//only look at first edge
Iterator<Integer> it = s.iterator();
curMove = graph.getEdgeSource(it.next());
//Add String representation before last steps
result = curMove.toString() + result;
}
//print the result
System.out.println(result);
}
/**
* The number of states identified for processing but not processed yet
* @return the number of moves not taken yet
*/
int numberOfStatesToProcess() {
return this.movesToProcess.size();
}
/**
* The number of states/puzzle moves processed so far
* @return the number of edges
*/
int numberOfProcessedStates() {
return this.graph.vertexSet().size();
}
/**
* @return the graph
*/
public DirectedGraph<PuzzleMove, Integer> getGraph() {
return this.graph;
}
/**
* @return the currentState
*/
public PuzzleMove getCurrentState() {
return this.currentState;
}
/**
* @param destinationState the destinationState to set
*/
public void setDestinationState(PuzzleMove destinationState) {
this.destinationState = destinationState;
}
/**
* @param startState the startState to set
*/
public void setStartState(PuzzleMove startState) {
this.startState = startState;
}
/**
* @return the startState
*/
public PuzzleMove getStartState() {
return this.startState;
}
/**
* @return the destinationState
*/
public PuzzleMove getDestinationState() {
return this.destinationState;
}
/**
* @return the movesToProcess
*/
public List<PuzzleMove> getMovesToProcess() {
return this.movesToProcess;
}
}