Subversion Repositories sokoban

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 daniel-mar 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
}