Subversion Repositories sokoban

Rev

Blame | Last modification | View Log | RSS feed

  1. package gdi1sokoban.game;
  2.  
  3. import gdi1sokoban.exceptions.InternalFailureException;
  4. import gdi1sokoban.exceptions.LevelHistoryEntryNotFoundException;
  5. import gdi1sokoban.exceptions.ParameterOutOfRangeException;
  6. import gdi1sokoban.exceptions.ParseException;
  7. import gdi1sokoban.globals.Point;
  8. import gdi1sokoban.gui.SokobanWindow;
  9. import gdi1sokoban.highscores.Highscores;
  10.  
  11. import java.awt.Dimension;
  12. import java.awt.Toolkit;
  13. import java.io.BufferedReader;
  14. import java.io.File;
  15. import java.io.FileNotFoundException;
  16. import java.io.FileReader;
  17. import java.io.FileWriter;
  18. import java.io.IOException;
  19. import java.net.URI;
  20. import java.net.URISyntaxException;
  21. import java.util.ArrayList;
  22. import java.util.LinkedList;
  23. import java.util.regex.Matcher;
  24. import java.util.regex.Pattern;
  25.  
  26. import javax.swing.JOptionPane;
  27.  
  28. /**
  29.  * GameEngine class
  30.  *
  31.  * main class for controlling the Sokoban game
  32.  * contains game logic and supplies GUI functions
  33.  */
  34. public class GameEngine {
  35.  
  36.         private static final long serialVersionUID = 8702781401668955536L;
  37.         private GameLevel gameLevel; // current loaded level
  38.         private SokobanWindow gameGui; // GUI interface
  39.         private int currentLevelNr = 0; // current level no.
  40.         private String currentCheatInput=""; // cheat input
  41.         private Highscores highscores; // highscore database
  42.         private String leveldir; // current level directory
  43.         private String playerName = ""; // player name
  44.         private long startTime = 0; // start time of the current level
  45.         private boolean deadLock = false; // deadlock situation?
  46.         /**
  47.          * gets the handle of the highscore engine
  48.          * @return highscores
  49.          */
  50.         public Highscores getHighscores() {
  51.                 return highscores;
  52.         }
  53.  
  54.         /**
  55.          * @return gameLevel
  56.          */
  57.         public GameLevel getGameLevel() {
  58.                 return gameLevel;
  59.         }
  60.        
  61.         /**
  62.          * returns the level number of the played level
  63.          * @return levelNumber
  64.          */
  65.         public int getCurrentLevelNr(){
  66.                 if(currentLevelNr < 0)
  67.                         currentLevelNr = 0;
  68.                 return currentLevelNr;
  69.         }
  70.        
  71.         /**
  72.          * set playerName to specified name
  73.          * @param playerName the name of the player
  74.          */
  75.         public void setPlayerName(final String playerName){
  76.                 this.playerName = playerName;
  77.         }
  78.         /**
  79.          * gets playerName
  80.          * @return current player name
  81.          */
  82.         public String getPlayerName(){
  83.                 return playerName;
  84.         }
  85.         /**
  86.          *
  87.          * @param windowTitle
  88.          * @throws InternalFailureException
  89.          */
  90.         public GameEngine(final SokobanWindow gameGui) throws InternalFailureException {
  91.                 try {
  92.                         if(gameGui != null)
  93.                                 gameGui.setOwner(this);
  94.                         this.gameGui = gameGui;
  95.                         final File levelDir = new File(ClassLoader.getSystemClassLoader().getResource("levels").toURI());
  96.                         setLevelDir(levelDir);
  97.                 } catch (final URISyntaxException e) {
  98.                         System.err.println("Fehlerhafter Dateiname");
  99.                 }
  100.         }
  101.        
  102.         /**
  103.          * checks if the user has typed a cheat
  104.          * @param input the currently read char
  105.          * @throws ParameterOutOfRangeException
  106.          */
  107.         public void checkCheat(final char input) throws ParameterOutOfRangeException{
  108.                 final Pattern beamCheat = Pattern.compile("osj([0-9]+),([0-9]+)#"); // define regular expression
  109.                 final Pattern solveCheat = Pattern.compile("helpmeplease"); // define regular expression
  110.                 currentCheatInput += input; // add input character to current cheat Code
  111.                 final Matcher beam = beamCheat.matcher(currentCheatInput); // match against input
  112.                 final Matcher solve = solveCheat.matcher(currentCheatInput); // match against input
  113.                 if(beam.find()){ // beam cheat found
  114.                         if (gameGui != null)
  115.                                 gameGui.playCheatSound();
  116.                         final Point playerPos = gameLevel.getPlayerPos(); // get Player Position
  117.                         // move player to given position
  118.                         final int destTop = Integer.valueOf(beam.group(2)).intValue();
  119.                         final int destLeft = Integer.valueOf(beam.group(1)).intValue();
  120.                         if(!(destTop == playerPos.top && destLeft == playerPos.left)){
  121.                                 gameLevel.setPosition(playerPos.top, playerPos.left, destTop, destLeft);
  122.                                 gameLevel.setNewHistoryStart(); // cheat code cannot be undone
  123.                         }
  124.                         currentCheatInput = ""; // reset cheat input
  125.                         // redraw etc
  126.                         roundEnd(true);
  127.                 }
  128.                 if(solve.find()){ // solve cheat found
  129.                         // call level solver
  130.                         if (gameGui != null)
  131.                                 gameGui.playCheatSound();
  132.                         int solveTime = 20;
  133.                         if(gameGui != null)
  134.                                 solveTime = gameGui.showSolveTimeDialog();
  135.                         if(solveTime < 0)
  136.                                 solveTime = 0;
  137.  
  138.                         final String moves = solve(solveTime);
  139.                         currentCheatInput = ""; // reset cheat input
  140.                         //System.out.println(moves);
  141.                         // execute moves
  142.                         new Thread() {
  143.                                 @Override
  144.                                 public void run() {
  145.                                         for(final char m : moves.toCharArray()){
  146.                                                 try {
  147.                                                         roundEnd(movePlayer(m));
  148.                                                 } catch (final ParameterOutOfRangeException e1) {
  149.                                                         System.err.println("Fehler: Ungltige Levelkoordinaten!");
  150.                                                 }
  151.                                                 try {
  152.                                                         Thread.sleep(125);
  153.                                                 } catch (final InterruptedException e) {
  154.                                                         System.err.println("Interner Fehler: Thread wurde unterbrochen.");
  155.                                                 }
  156.                                         }
  157.                                 }
  158.                         }.start();
  159.                        
  160.                 }
  161.         }
  162.  
  163.         /**
  164.          * sets the level directory
  165.          * @param leveldir level directory
  166.          * @throws InternalFailureException
  167.          */
  168.         public void setLevelDir(final File leveldir, final int maxHighscores) throws InternalFailureException {
  169.                 this.leveldir = leveldir.toURI().toString();
  170.                 highscores = new Highscores(this.leveldir + "/highscore.txt", maxHighscores);
  171.                 // reset level no.
  172.                 currentLevelNr = 0;
  173.         }
  174.        
  175.         /**
  176.          * returns the level directory
  177.          * @return level directory
  178.          */
  179.         public String getLevelDir(){
  180.                 return leveldir;
  181.         }
  182.         public void setLevelDir(final File leveldir) throws InternalFailureException {
  183.                 setLevelDir(leveldir, 10);
  184.         }
  185.        
  186.         /**
  187.          * Parses the level no. from the filename of a given file handle
  188.          * @author Victor
  189.          * @param level level file handle
  190.          * @return level no., -1 if error
  191.          */
  192.         private int parseLevelNr(final File level) {
  193.                 final String fileName = level.toString();
  194.                 final Pattern p = Pattern.compile("(level\\_)([0-9]+)(\\.txt)"); // define regular expression
  195.                 final Matcher m = p.matcher(fileName); // apply regexp
  196.                 if (m.find() && (m.groupCount() >= 3))
  197.                         return Integer.valueOf(m.group(2)).intValue(); // return level no.
  198.                 else
  199.                         return -1;
  200.         }
  201.        
  202.         /**
  203.          * Startet das Level neu bzw. startet einen neuen Level
  204.          * @throws IOException
  205.          * @throws InternalFailureException
  206.          * @throws ParameterOutOfRangeException
  207.          * @throws URISyntaxException
  208.          * @throws ParseException
  209.          */
  210.         public void newGame (final File level) throws IOException, ParameterOutOfRangeException, InternalFailureException, URISyntaxException, ParseException {
  211.                 deadLock = false;
  212.                 startTime = System.currentTimeMillis();
  213.                 try {
  214.                         gameLevel = new GameLevel(level);
  215.                         currentLevelNr = parseLevelNr(level);
  216.                         if(gameGui != null) {
  217.                                 gameGui.notifyLevelLoaded(gameLevel.getWidth(), gameLevel.getHeight());
  218.                                 // set new window position
  219.                                 final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
  220.                                 gameGui.setLocation((int) ((screenSize.width - gameGui.getWidth()) / 2), (int) ((screenSize.height - gameGui.getHeight()) / 2));
  221.                         }
  222.                 } catch (ParseException e) {
  223.                         if (gameGui != null)
  224.                                 gameGui.showParseError();
  225.                         newGame();
  226.                         throw new ParseException("Leveldatei fehlerhaft.");
  227.                 }
  228.         }
  229.  
  230.         /**
  231.          * Startet das Standard-Level
  232.          * @throws URISyntaxException
  233.          * @throws InternalFailureException
  234.          * @throws ParameterOutOfRangeException  
  235.          * @throws IOException
  236.          * @throws ParseException
  237.          */
  238.         public void newGame () throws IOException, ParameterOutOfRangeException, InternalFailureException, URISyntaxException, ParseException {
  239.                 newGame(1);
  240.         }
  241.        
  242.         /**
  243.          * Starts a specified level
  244.          * @param level Das zu ladende Level
  245.          * @throws URISyntaxException
  246.          * @throws InternalFailureException
  247.          * @throws ParameterOutOfRangeException  
  248.          * @throws IOException
  249.          * @throws ParseException
  250.          */
  251.         public void newGame (final int level) throws IOException, ParameterOutOfRangeException, InternalFailureException, URISyntaxException, ParseException {
  252.                 String levelURI = String.valueOf(level);
  253.                 currentLevelNr = level;
  254.                 if (level < 10)
  255.                         levelURI = "0" + levelURI;
  256.                 newGame(new File(new URI(leveldir + "/level_" + levelURI +  ".txt")));
  257.         }
  258.        
  259.        
  260.         public void roundEnd(final boolean hasMoved) throws ParameterOutOfRangeException {
  261.                 roundEnd(hasMoved, playerName);
  262.         }
  263.  
  264.         public int getPlayingTime(long endTime) {
  265.                 endTime = System.currentTimeMillis();
  266.                 return (int) ((endTime - startTime)/1000);
  267.         }
  268.        
  269.         /**
  270.          * a step was made, redraw, check if level is complete and if it is a new highscore
  271.          * Start new level if level is complete
  272.          * @param hasMoved was the move succesful?
  273.          * @param playerName name of player
  274.          * @throws ParameterOutOfRangeException
  275.          */
  276.         public void roundEnd(boolean hasMoved, final String playerName) throws ParameterOutOfRangeException {
  277.                 if (! hasMoved) return; // break if nothing has moved
  278.                 gameLevel.incSteps(); // increment done steps
  279.                 if(gameGui != null)
  280.                         gameGui.roundEnd(hasMoved, playerName);
  281.                 if (gameLevel.isSolved()) {
  282.                         if(gameGui != null)
  283.                                 gameGui.setStatusBarInfo("Level kmpl.");
  284.                         this.playerName =  playerName;
  285.                         final int passedTime = getPlayingTime(0);
  286.                         final int place = highscores.getPlace(currentLevelNr, gameLevel.getSteps(), passedTime);
  287.                         if (highscores.isHighscore(currentLevelNr, gameLevel.getSteps(), passedTime)) {
  288.                                 if(gameGui != null)
  289.                                         gameGui.newHighscore(place);
  290.                                 highscores.addHighscore(currentLevelNr, this.playerName, String.valueOf(gameLevel.getSteps()), Integer.valueOf(passedTime).toString());
  291.                                 try {
  292.                                         highscores.saveHighscores(); // save the highscore list
  293.                                 } catch (final InternalFailureException e) {
  294.                                         System.err.println("Fehler: Highscores konnten nicht gespeichert werden.");
  295.                                 }
  296.                                 if(gameGui != null)
  297.                                         gameGui.showHighscores();
  298.                         }
  299.                         try {
  300.                                 newGame(currentLevelNr+1);
  301.                         } catch (final IOException e) {
  302.                                 System.err.println("Level-Datei konnte nicht gefunden werden");
  303.                         } catch (final ParameterOutOfRangeException e) {
  304.                                 e.printStackTrace();
  305.                         } catch (final InternalFailureException e) {
  306.                                 System.err.println("Ein interner Fehler ist aufgetreten");
  307.                                 e.printStackTrace();
  308.                         } catch (final URISyntaxException e) {
  309.                                 System.err.println("Fehlerhafter Dateiname");
  310.                         } catch (ParseException e) {
  311.                                 System.err.println("Leveldatei fehlerhaft");
  312.                         }
  313.                 }
  314.                 // notify player if level contains deadlock
  315.                 if (gameLevel.hasDeadlock()) {
  316.                         if (! deadLock) {
  317.                                 if (gameGui != null) {
  318.                                         gameGui.playDeadlockSound();
  319.                                         gameGui.showDeadlockMessage();
  320.                                 }
  321.                                 deadLock = true;
  322.                         }
  323.                 } else if (deadLock) {
  324.                         deadLock = false;
  325.                         if (gameGui != null)
  326.                                 gameGui.playBackgroundSound();
  327.                 }
  328.         }
  329.  
  330.         /**
  331.          * method to make the player walk to the given coordinates
  332.          * (steps are visible for the player)
  333.          * @param top
  334.          * @param left
  335.          * @throws ParameterOutOfRangeException
  336.          */
  337.         public void playerWalk(final int top, final int left) throws ParameterOutOfRangeException{
  338.                 final Point playerPos = gameLevel.getPlayerPos();
  339.                 // if the player only has to walk one step, he can move boxes
  340.                 // and the normal MovePlayer method is called
  341.                 final int diffTop = playerPos.top - top;
  342.                 final int diffLeft = playerPos.left - left;
  343.                 if((diffTop == 1) && (diffLeft == 0)) // Up
  344.                         roundEnd(movePlayer('U'));
  345.                 else if((diffTop == -1) && (diffLeft == 0)) // Down
  346.                         roundEnd(movePlayer('D'));
  347.                 else if((diffTop == 0) && (diffLeft == -1)) // Right
  348.                         roundEnd(movePlayer('R'));
  349.                 else if((diffTop == 0) && (diffLeft == 1)) // Left
  350.                         roundEnd(movePlayer('L'));
  351.                 else
  352.                         new Thread() {
  353.                                 @Override
  354.                                 public void run() {
  355.                                         // The method returns a LinkedList of chars (U, R, D, L)
  356.                                         // that have to be executed so that the player reaches his
  357.                                         // goal with the fewest possible moves
  358.                                         LinkedList<Character> lod;
  359.                                         try {
  360.                                                 lod = gameLevel.getShortestPath(playerPos.top, playerPos.left, top, left);
  361.                                         } catch (final ParameterOutOfRangeException e1) {
  362.                                                 System.err.println("Fehler: Ungültige Levelkoordinaten!");
  363.                                                 return;
  364.                                         }
  365.                                         // for every Direction in the List of directions
  366.                                         // the player has to execute the move and then wait
  367.                                         // for a while
  368.                                         for(final char dir : lod)
  369.                                                 try {
  370.                                                         // move player in given direction
  371.                                                         roundEnd(movePlayer(dir));
  372.                                                         // wait 0.1 seconds before executing the next move
  373.                                                         Thread.sleep(100);
  374.                                                 } catch (final InterruptedException e) {
  375.                                                         System.err.println("Interner Thread Fehler");
  376.                                                         e.printStackTrace();
  377.                                                 } catch (final ParameterOutOfRangeException e) {
  378.                                                         System.err.println("Fehler: Ungültige Levelkoordinaten!");
  379.                                                         return;
  380.                                                 }
  381.                                 }
  382.                         }.start();
  383.         }
  384.        
  385.         /**
  386.          * Checks if the move is allowed,
  387.          * moves player in the given direction,
  388.          * updates game level and returns if the level is solved
  389.          *
  390.          * @param dir Direction ('R', 'U', 'D', 'L')
  391.          * @return true if move was successful
  392.          * @throws ParameterOutOfRangeException
  393.          */
  394.         public boolean movePlayer (final char dir) throws ParameterOutOfRangeException {
  395.                 final Point playerPos = gameLevel.getPlayerPos();
  396.                 final Point newPos = playerPos.moveDirection(dir);
  397.                 final Point newCratePos = newPos.moveDirection(dir);
  398.                 final int top = playerPos.top;
  399.                 final int left = playerPos.left;
  400.                 // if crate is in front of player try to move it first
  401.                 boolean isCrate = false;
  402.                 try {
  403.                         isCrate = gameLevel.isCrate(newPos.top, newPos.left);
  404.                 } catch (final ParameterOutOfRangeException e) {
  405.                         System.err.println("Fehler: Koordinaten liegen ausserhalb des Spielfelds!");
  406.                         return false;
  407.                 }
  408.                 if(isCrate)
  409.                         gameLevel.setPosition(newPos.top, newPos.left , newCratePos.top, newCratePos.left);
  410.                 if (gameLevel.setPosition(top, left, newPos.top, newPos.left)) { // move successful?
  411.                         gameLevel.addMove(dir); // Add move to history
  412.                         return true;
  413.                 }
  414.                 return false; // move unsuccessful
  415.         }
  416.        
  417.         /**
  418.          * undo the last move
  419.          * @throws ParameterOutOfRangeException
  420.          */
  421.         public void undo() throws LevelHistoryEntryNotFoundException, ParameterOutOfRangeException{
  422.                 final LinkedList<Character> history = gameLevel.getMoveHistory();
  423.                 final int stepCount = gameLevel.getHistorySteps(); // current position in history
  424.                 if(stepCount == 0)
  425.                         throw new LevelHistoryEntryNotFoundException("Undo not possible! No moves made yet.");
  426.                 gameLevel.reset(); // resets level to start
  427.                 // execute all steps made except the last one
  428.                 for(int i=0; i< stepCount-1; i++)
  429.                                 movePlayer(history.get(i));
  430.                 // history may not change
  431.                 gameLevel.setHistory(history);
  432.         }
  433.        
  434.         /**
  435.          * redo the last undo
  436.          * @throws ParameterOutOfRangeException
  437.          */
  438.         public void redo() throws LevelHistoryEntryNotFoundException, ParameterOutOfRangeException{
  439.                 final LinkedList<Character> history = gameLevel.getMoveHistory();
  440.                 final int stepCount = gameLevel.getHistorySteps(); // current position in history
  441.                 if(stepCount == history.size())
  442.                         throw new LevelHistoryEntryNotFoundException("Redo not possible! No undos made yet.");
  443.                 movePlayer(history.get(stepCount)); // execute undone move
  444.                 gameLevel.setHistory(history); // history may not change
  445.         }
  446.  
  447.         /**
  448.          * load saved game from the given File
  449.          * @param GamesSaveFile saved game file
  450.          */
  451.         public void loadGame(final File GamesSaveFile) {
  452.                         try {
  453.                                 String steps = "";
  454.                                 String historyStart = "";
  455.                                 int historySteps=0;
  456.                                 int stepCount = 0;
  457.                                 String[] saveData = new String[0];
  458.                                 final LinkedList<Character> stepsSequence = new LinkedList<Character>();
  459.                                
  460.                             if(GamesSaveFile != null){
  461.                                 final BufferedReader in = new BufferedReader(new FileReader(GamesSaveFile));
  462.                                 String line = null;
  463.                                 int lineNum = 0;
  464.                                 while ((line = in.readLine()) != null) { // read SavedGames file line by line
  465.                                         lineNum++;
  466.                                         if(lineNum > 1)
  467.                                                         historyStart += line+"\n";
  468.                                                 else
  469.                                                         saveData = line.split("\t"); // split SavedGames line
  470.                                 }
  471.                                 currentLevelNr = Integer.valueOf(saveData[1]);//Level
  472.                                 if(saveData.length >= 3)
  473.                                                 try {
  474.                                                 stepCount = Integer.valueOf(saveData[2]).intValue();
  475.                                         } catch (final NumberFormatException e) {
  476.                                                 System.err.println("Fehler: Savegame fehlerhaft.");
  477.                                                 if (gameGui != null)
  478.                                                         JOptionPane.showMessageDialog(null, "Der Spielstand konnte nicht geladen werden.\nDie Datei ist fehlerhaft.", "Savegame fehlerhaft", JOptionPane.ERROR_MESSAGE);
  479.                                                 return;
  480.                                         }
  481.                                 newGame(currentLevelNr);
  482.                                 if(saveData.length >= 4)
  483.                                                 steps = saveData[3]; // Schritte in richtiger Reihenfolge
  484.                                 if(saveData.length >= 5)
  485.                                         startTime = System.currentTimeMillis() - Integer.parseInt(saveData[4])*1000; // Playing Time
  486.                                 if(saveData.length >= 6)
  487.                                                 historySteps = Integer.valueOf(saveData[5]).intValue(); // History-Schritte
  488.                                 try {
  489.                                                 gameLevel.parseString(historyStart);
  490.                                         } catch (ParseException e) {
  491.                                                 if (gameGui != null)
  492.                                                         gameGui.showParseError();      
  493.                                                 in.close();
  494.                                                 return;
  495.                                         }
  496.                                 gameLevel.setNewHistoryStart();
  497.                                 for(final char step : steps.toCharArray())
  498.                                                 stepsSequence.add(step);
  499.                                 gameLevel.setHistory(stepsSequence);
  500.                                 for(int i = 0;i<historySteps; i++)
  501.                                                 redo();
  502.                                 roundEnd(true);                
  503.                                 gameLevel.setSteps(stepCount);
  504.                                 in.close();
  505.                             }
  506.                         } catch (final URISyntaxException e) {
  507.                         System.err.println("Ungltiger Dateiname");
  508.                         } catch (final FileNotFoundException e) {
  509.                                 System.err.println("Datei nicht gefunden!");
  510.                         } catch (final NumberFormatException e) {
  511.                                 e.printStackTrace();
  512.                         } catch (final IOException e) {
  513.                                 e.printStackTrace();
  514.                         } catch (final ParameterOutOfRangeException e) {
  515.                                 e.printStackTrace();
  516.                         } catch (final InternalFailureException e) {
  517.                                 e.printStackTrace();
  518.                         } catch (final LevelHistoryEntryNotFoundException e) {
  519.                                 System.err.println("Fehler beim Einlesen der Schrittfolge");
  520.                         } catch (ParseException e) {
  521.                                 System.err.println("Leveldatei fehlerhaft");
  522.                         }
  523.                 }
  524.        
  525.         /**
  526.          * save game to given filepath
  527.          * @param GamesSaveFile File to save gamestatus to
  528.          * @return
  529.          */
  530.                 public boolean saveGame(final File GamesSaveFile) {
  531.                        
  532.                         String stepsSequence = "";
  533.                         for(int i=0;i<getGameLevel().getMoveHistory().size();i++)
  534.                                 stepsSequence += getGameLevel().getMoveHistory().get(i);
  535.                         FileWriter out;
  536.                         try {
  537.                         out = new FileWriter(GamesSaveFile);
  538.                         out.write(playerName + "\t" + getCurrentLevelNr() + "\t" + getGameLevel().getSteps() + "\t"
  539.                                         + stepsSequence + "\t" + getPlayingTime(System.currentTimeMillis())
  540.                                         +  "\t" + getGameLevel().getHistorySteps() + "\n" + gameLevel.getHistoryStart());
  541.                         out.close();
  542.                         } catch (final IOException e) {
  543.                                 e.printStackTrace();
  544.                         }
  545.                         return true;   
  546.                 }      
  547.         /**
  548.          * tries to solve the level in a given amount of time
  549.          * @param solutionTime maximum time the solver may run
  550.          * @return moves that have to be executed to clear the level or an empty String when no solution could be found
  551.          * @throws ParameterOutOfRangeException
  552.          */    
  553.         private String solveWithQueue(final int solutionTime) throws ParameterOutOfRangeException {
  554.                 try {
  555.                         final LinkedList<String> queue = new LinkedList<String>();
  556.                         final ArrayList<String> levelHistory = new ArrayList<String>();
  557.                         final char[] directions = new char[] { 'U', 'L', 'R', 'D' };
  558.                         // passed seconds since start of solver
  559.                         final long startTime = System.currentTimeMillis();
  560.                         int passedTime = 0;
  561.                         do{
  562.                                 passedTime = (int) (System.currentTimeMillis() - startTime) / 1000;
  563.                                 String currMoves = "";
  564.                                 if(!queue.isEmpty())
  565.                                         currMoves = queue.pop();
  566.                                 // set level to state
  567.                                 for (final char m : currMoves.toCharArray())
  568.                                         movePlayer(m);
  569.                                 String solvedString = "";
  570.                                 // Try if next move completes game
  571.                                 for (final char d : directions)
  572.                                         // if move is valid and level contains no deadlocks and
  573.                                         // field has not been visited yet
  574.                                         if (!gameLevel.hasDeadlock() && movePlayer(d)) {
  575.                                                 if (gameLevel.isSolved())
  576.                                                         // return made moves
  577.                                                         solvedString = currMoves + d;
  578.                                                 // do not restore a state of the level in which
  579.                                                 // it has been before
  580.                                                 if (!levelHistory.contains(gameLevel.toString())) {
  581.                                                         queue.add(currMoves + d); // add moves to queue
  582.                                                         levelHistory.add(gameLevel.toString());
  583.                                                 }
  584.                                                 undo(); // undo move
  585.                                         }
  586.                                 // reset level to beginning state
  587.                                 for (int i = 0; i < currMoves.length(); i++)
  588.                                         undo();
  589.                                 if(solvedString != "")
  590.                                         return solvedString;
  591.                         } while (!queue.isEmpty() && (passedTime < solutionTime));
  592.                 } catch (final LevelHistoryEntryNotFoundException e) {
  593.                         System.err.println("Interner Fehler: Levelsolver-Fehler");
  594.                 }
  595.                 return "";
  596.         }
  597.         /**
  598.          * tries to solve the level
  599.          * @param solutionTime max time for searching for a solution (in seconds)
  600.          * @return the steps that have to be executed to solve the level in {R,L,U,D}-format
  601.          * @throws ParameterOutOfRangeException
  602.          */
  603.         public String solve(final int solutionTime) throws ParameterOutOfRangeException{
  604.                 final long startTime = System.currentTimeMillis();
  605.                 // the solver tries to find the optimal solution
  606.                 // (i.e. the solution with the smallest number of moves)
  607.                 long timePassed = 0;
  608.                         final String solution = solveWithQueue(solutionTime);
  609.                         if(solution != ""){ // solution has be found
  610.                                 timePassed = (System.currentTimeMillis() - startTime)/1000;
  611.                                 System.out.println("Found solution in "+timePassed+" seconds.");
  612.                                 if(gameGui != null)
  613.                                         gameGui.setStatusBarInfo("Lsung ("+timePassed+"s)");
  614.                                 return solution;
  615.                 }
  616.                 // return empty string if no solution could be found
  617.                 if(gameGui != null)
  618.                         gameGui.setStatusBarInfo("Keine Ls.");
  619.                 return "";
  620.         }
  621.        
  622.        
  623. }
  624.