getLevelsetpaths() {
+
+ return levelpaths;
+ }
+
+ public void setCurrentLevel(Level level) {
+ currentLevel = level;
+
+ }
+
+ public void setLevelNumber(int i) {
+ this.levelnumber = i;
+
+ }
+
+ public void setLevelSetPath(String levelsetpath) {
+ this.levelsetpath = levelsetpath;
+ }
+
+ public void setHighscore(Highscore highscore) {
+ this.highscore = highscore;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public String getName()
+ {
+ return this.name;
+ }
+}
diff --git a/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/tests/adapters/PlumberTestAdapterExtended1.java b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/tests/adapters/PlumberTestAdapterExtended1.java
new file mode 100644
index 00000000..7fc72ac6
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/tests/adapters/PlumberTestAdapterExtended1.java
@@ -0,0 +1,81 @@
+package de.tu_darmstadt.gdi1.plumber.tests.adapters;
+
+/**
+ * This is the test adapter for the first extended stage of completion.
+ * Implement all method stubs in order for the tests to work.
+ *
+ * Note: This test adapter inherits from the minimal test adapter.
+ *
+ * @see PlumberTestAdapterMinimal
+ *
+ * @author Jonas Marczona
+ * @author Christian Merfels
+ * @author Fabian Vogt
+ */
+ public class PlumberTestAdapterExtended1 extends PlumberTestAdapterMinimal {
+
+ /**
+ * Add a highscore entry to the highscore with the given playername and
+ * time.
+ *
+ * @param playername the name which shall appear in the highscore
+ * @param time the time which was needed
+ */
+ public void addHighscoreEntry(String playername, int reached_level, double time) {
+ controller.logic.levelset.getHighscore().addHighscoreEntry(time,playername,reached_level);
+ }
+
+ /**
+ * Return the number of highscore entries in your highscore store.
+ *
+ * @return the number of highscore entries
+ */
+ public int getHighscoreCount() {
+ return controller.logic.levelset.getHighscore().count();
+ }
+
+ /**
+ * Clear the highscore store and delete all entries.
+ */
+ public void resetHighscore() {
+ controller.logic.levelset.getHighscore().reset();
+ }
+
+ /**
+ * Get the playername of a highscore entry at a given position.
+ * Note: The position counting starts at zero. The first entry should contain the best result.
+ *
+ * See the specification in the task assignment for a definition of 'best' in the highscore.
+ *
+ * @param position the position of the highscore entry in the highscore
+ * store
+ * @return the playername of the highscore entry at the specified position
+ * or null if the position is invalid
+ */
+ public String getPlayernameAtHighscorePosition(int position) {
+ if(controller.logic.levelset.getHighscore().getAt(position) != null)
+ {
+ return controller.logic.levelset.getHighscore().getAt(position).getPlayername();
+ }
+ return null;
+ }
+
+ /**
+ * Get the needed time of a highscore entry at a given position.
+ * Note: The position counting starts at zero. The first entry should contain the best result.
+ *
+ * See the specification in the task assignment for a definition of 'best' in the highscore.
+ *
+ * @param position the position of the highscore entry in the highscore
+ * store
+ * @return the time of the highscore entry at the specified position
+ * or -1 if the position is invalid
+ */
+ public double getTimeAtHighscorePosition(int position) {
+ if(controller.logic.levelset.getHighscore().getAt(position) != null)
+ {
+ return controller.logic.levelset.getHighscore().getAt(position).getTime();
+ }
+ return -1;
+ }
+}
diff --git a/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/tests/adapters/PlumberTestAdapterExtended2.java b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/tests/adapters/PlumberTestAdapterExtended2.java
new file mode 100644
index 00000000..b3b3c1ca
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/tests/adapters/PlumberTestAdapterExtended2.java
@@ -0,0 +1,86 @@
+package de.tu_darmstadt.gdi1.plumber.tests.adapters;
+
+import de.tu_darmstadt.gdi1.plumber.view.tudframework.GameWindow;
+
+/**
+ * This is the test adapter for the second extended stage of completion.
+ * Implement all method stubs in order for the tests to work.
+ *
+ * Note: This test adapter inherits from the first extended test adapter
+ *
+ * @see PlumberTestAdapterMinimal
+ * @see PlumberTestAdapterExtended1
+ *
+ * @author Jonas Marczona
+ * @author Christian Merfels
+ * @author Fabian Vogt
+ */
+public class PlumberTestAdapterExtended2 extends PlumberTestAdapterExtended1 {
+
+ /**
+ * Undo the last action. The state of the game shall be the same as before
+ * the last action. Action is here defined as "rotating game elements".
+ * Do nothing if there is no action to undo.
+ */
+ public void undo() {
+ controller.logic.level.UnDo();
+ }
+
+ /**
+ * Redo the last action. The state of the game shall be the same as before
+ * the last "undo".
+ * Do nothing if there is no action to redo.
+ */
+ public void redo() {
+ controller.logic.level.ReDo();
+ }
+
+ /**
+ * Like {@link GameWindow#keySpacePressed()}
+ */
+ public void handleKeyPressedSpace() {
+ controller.logic.level.rotateSelected();
+ }
+
+ /**
+ * Like {@link GameWindow#keyUndoPressed()}
+ */
+ public void handleKeyPressedUndo() {
+ controller.logic.level.UnDo();
+ }
+
+ /**
+ * Like {@link GameWindow#keyRedoPressed()}
+ */
+ public void handleKeyPressedRedo() {
+ controller.logic.level.ReDo();
+ }
+
+ /**
+ * Like {@link GameWindow#keyUpPressed()}
+ */
+ public void handleKeyPressedUp() {
+ controller.logic.level.moveSelectionUp();
+ }
+
+ /**
+ * Like {@link GameWindow#keyDownPressed()}
+ */
+ public void handleKeyPressedDown() {
+ controller.logic.level.moveSelectionDown();
+ }
+
+ /**
+ * Like {@link GameWindow#keyLeftPressed()}
+ */
+ public void handleKeyPressedLeft() {
+ controller.logic.level.moveSelectionLeft();
+ }
+
+ /**
+ * Like {@link GameWindow#keyRightPressed()}
+ */
+ public void handleKeyPressedRight() {
+ controller.logic.level.moveSelectionRight();
+ }
+}
\ No newline at end of file
diff --git a/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/tests/adapters/PlumberTestAdapterExtended3.java b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/tests/adapters/PlumberTestAdapterExtended3.java
new file mode 100644
index 00000000..6201b6db
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/tests/adapters/PlumberTestAdapterExtended3.java
@@ -0,0 +1,45 @@
+package de.tu_darmstadt.gdi1.plumber.tests.adapters;
+
+/**
+ * This is the test adapter for the third extended stage of completion.
+ * Implement all method stubs in order for the tests to work.
+ *
+ * Note: This test adapter inherits from the second extended test
+ * adapter.
+ *
+ * @see PlumberTestAdapterMinimal
+ * @see PlumberTestAdapterExtended1
+ * @see PlumberTestAdapterExtended2
+ *
+ * @author Jonas Marczona
+ * @author Christian Merfels
+ * @author Fabian Vogt
+ */
+public class PlumberTestAdapterExtended3 extends PlumberTestAdapterExtended2 {
+
+ /**
+ * Generate a level with the given width and height.
+ * The generated level has to be solvable. It should be returned as
+ * string representation of a valid level as described in the
+ * documentation.
+ *
+ *
Counting starts at 1, that means a 3x3 board has a width and
+ * height of three.
+ *
+ * @param x the width of the generated level
+ * @param y the height of the generated level
+ */
+ public String generateLevel(int width, int height) {
+ // TODO: fill stub.
+ return "";
+ }
+
+ /**
+ * Automatically solve the current level. There shall be a connection
+ * between the source and the sink in the level, but the water shall
+ * not start to flow automatically.
+ */
+ public void solveLevel() {
+ // TODO: fill stub.
+ }
+}
\ No newline at end of file
diff --git a/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/tests/adapters/PlumberTestAdapterMinimal.java b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/tests/adapters/PlumberTestAdapterMinimal.java
new file mode 100644
index 00000000..c25b2f70
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/tests/adapters/PlumberTestAdapterMinimal.java
@@ -0,0 +1,194 @@
+package de.tu_darmstadt.gdi1.plumber.tests.adapters;
+
+import java.awt.Point;
+
+import de.tu_darmstadt.gdi1.plumber.controller.Controller;
+import de.tu_darmstadt.gdi1.plumber.model.exceptions.PlumberError;
+
+
+/**
+ * This is the test adapter for the minimal stage of completion. You
+ * must implement the method stubs and match them to your concrete
+ * implementation.
+ *
Important: This class should not contain any real game
+ * logic, you should rather only match the method stubs to your game.
+ *
Example: in {@link #isCorrectLevel()} you may return the value
+ * myGame.isCorrectlevel(), if you have a variable myGame and a
+ * level has before been loaded via {@link #loadLevelFromString(String)}.
+ *
You should not implement the actual logic of the method in this class.
+ *
+ * If you have implemented the minimal stage of completion, you should be able
+ * to implement all method stubs. The public and private JUnit tests for the
+ * minimal stage of completion will be run on this test adapter. The other test
+ * adapters will inherit from this class, because they need the basic methods
+ * (like loading a level), too.
+ *
+ * The methods of all test adapters need to function without any kind of user
+ * interaction.
+ *
+ * @author Jonas Marczona
+ * @author Christian Merfels
+ * @author Fabian Vogt
+ */
+public class PlumberTestAdapterMinimal {
+ protected Controller controller;
+
+ public PlumberTestAdapterMinimal() {
+ controller = new Controller();
+ }
+
+
+ /**
+ * Construct a level from a string. You will be given a string
+ * representation of a level and you need to load this into your game.
+ * Line breaks will be delimited by \n. Your game should hold the level
+ * until a new one is loaded; the other methods will assume that this very
+ * level is the current one and that the actions (like rotating elements)
+ * will run on the specified level.
+ * @param levelstring a string representation of the level to load
+ * @see #isCorrectLevel()
+ */
+ public void loadLevelFromString(String levelstring) {
+ controller.logic.level.fromString(levelstring);
+ }
+
+ /**
+ * Return the string representation of the current level.
+ * A level loaded with the method {@link #loadLevelFromString()}
+ * should be the same as the result of
+ * {@link #getStringRepresentationOfLevel()}
+ * as long as no actions has been performed in the meantime.
+ * But if there were (valid) actions in the meantime this have to be visible in the level representation.
+ * The level format is the same
+ * as the one specified for loading levels.
+ *
+ * @return string representation of the current level
+ * or null if no valid level was loaded
+ *
+ * @see #loadLevelFromString(String)
+ * @see #isCorrectLevel()
+ */
+ public String getStringRepresentationOfLevel() {
+ return controller.logic.level.toString();
+ }
+
+ /**
+ * Is the loaded level a syntactically correct level?
+ * See the specification in the task assignment for a definition of
+ * 'syntactical correct'.
+ * You don't need to implement a solvability evaluation here.
+ *
+ * @return if the currently loaded level is syntactically correct return true,
+ * otherwise return false
+ *
+ * @see #loadLevelFromString(String)
+ * @see #getStringRepresentationOfLevel()
+ */
+ public boolean isCorrectLevel() {
+ return controller.logic.level.isCorrect();
+ }
+
+ /**
+ * Has the current level been won? If a level has been loaded, this should
+ * return false. Even if a source and a sink are connected, but the water
+ * hasn't flown yet, this should return false. If a level has been loaded
+ * and the necessary actions have been made (or the source and sink were
+ * connected from the beginning), and the method {@link #playGame()} was
+ * called and the level has been won, the return value has to be 'true'.
+ *
+ * @return if the current level has been won return true, otherwise return
+ * false*/
+ public boolean isWon() {
+ return controller.logic.level.getLevel().isSolved();
+ }
+
+ /**
+ * Has the current level been lost? In accordance to {@link #isWon()},
+ * you should return 'true' if and only if a level was loaded,
+ * {@link #playGame()} was called and the source and sink were not
+ * connected in the end. Before or while a game is running, 'false' shall
+ * be returned. {@link #isWon()} and {@link #isLost()} may be 'false',
+ * but never both be 'true' at the same time.
+ *
+ * @return if the level has been lost after the water has flown return true,
+ * otherwise return false
+ */
+ public boolean isLost() {
+ return controller.logic.level.getLevel().isLost();
+ }
+
+ /**
+ * Rotate an element at a specified position (clockwise).
+ *
+ * Notice:
+ * [0,0] is the upper left point on the board.
+ * if a and b were the maximal coordinates:
+ * [a,b] is the lower right point on the board,
+ * [0,b] is the lower left point on the board
+ * [a,0] is the upper right point on the board
+ *
+ * @param x the x coordinate of the element to rotate
+ * @param y the y coordinate of the element to rotate
+ */
+ public void rotateClockwiseAtPosition(int x, int y) {
+ controller.logic.level.rotateRight(new Point(y,x));
+ }
+
+ /**
+ * Is the element at a specified position filled with water?
+ *
+ *
+ * Notice:
+ * [0,0] is the upper left point on the board.
+ * if a and b were the maximal coordinates:
+ * [a,b] is the lower right point on the board,
+ * [0,b] is the lower left point on the board
+ * [a,0] is the upper right point on the board
+ *
+ *
+ * @param x the x coordinate of the element
+ * @param y the y coordinate of the element
+ * @return
+ */
+ public boolean isFilledWithWater(int x, int y) {
+
+ try {
+ return controller.logic.level.getElement(new Point(y,x)).isWatered();
+ } catch (PlumberError e) {
+ return false;
+ }
+ }
+
+ /**
+ * Rotate an element at a specified position (counter-clockwise).
+ *
+ * @see #isFilledWithWater(int, int)
+ * @see #rotateClockwiseAtPosition(int, int
+ *
+ * @param x the x coordinate of the element to rotate
+ * @param y the y coordinate of the element to rotate
+ */
+ public void rotateCounterClockwiseAtPosition(int x, int y) {
+ controller.logic.level.rotateLeft(new Point(y,x));
+ }
+
+ /**
+ * Like {@link GameWindow#keyNewGamePressed()}.
+ */
+ public void handleKeyPressedNew() {
+ controller.logic.level.restart();
+ }
+
+ /**
+ * Start and play the game: the water shall start to flow. The flow has to
+ * be ended at the end of this method, either because it reached the sink
+ * or a wall.
+ */
+ public void playGame() {
+ // TODO: fill stub.
+ controller.logic.level.start();
+ controller.logic.level.startWater();
+
+ while(!this.isLost() && !this.isWon()){}
+ }
+}
diff --git a/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/ViewLogicListener.java b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/ViewLogicListener.java
new file mode 100644
index 00000000..8f73bb73
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/ViewLogicListener.java
@@ -0,0 +1,139 @@
+package de.tu_darmstadt.gdi1.plumber.view;
+
+import java.awt.Color;
+
+import de.tu_darmstadt.gdi1.plumber.model.events.EventListener;
+import de.tu_darmstadt.gdi1.plumber.model.events.level.NewLevel;
+import de.tu_darmstadt.gdi1.plumber.model.events.level.SelectionChange;
+import de.tu_darmstadt.gdi1.plumber.model.events.level.Timer;
+import de.tu_darmstadt.gdi1.plumber.model.events.level.WaterOut;
+import de.tu_darmstadt.gdi1.plumber.model.events.level.WaterStart;
+import de.tu_darmstadt.gdi1.plumber.model.events.level.WaterWin;
+import de.tu_darmstadt.gdi1.plumber.model.events.levelelement.LevelElementEvent_abstract;
+import de.tu_darmstadt.gdi1.plumber.view.game.Panel;
+import de.tu_darmstadt.gdi1.plumber.view.game.Window;
+
+//UNUSED
+//import plumber.model.events.levelset.LevelSetEvent_abstract;
+
+public class ViewLogicListener extends EventListener {
+
+ private Window plumberWindow;
+
+ private boolean water_started = false;
+
+ public ViewLogicListener(Window plumberWindow) {
+ this.plumberWindow = plumberWindow;
+ }
+
+ //UNUSED
+ /*public void levelset(LevelSetEvent_abstract e)
+ {
+ System.out.println("New LevelSet");
+
+ }; //reports a Levelsetchange*/
+
+ @Override
+ public void _level(NewLevel e) //new level loaded
+ {
+ Panel p = (Panel) plumberWindow.getGamePanel(); //create GamePanel
+ p.OnLevelChange(e.currentLevel);
+ water_started = false; //water isn't started at beginning ;)
+ plumberWindow.timeleft.setForeground(Color.BLACK);
+ plumberWindow.levelnumber(plumberWindow.controller.logic.level.getLevel().getLevelnumber());//level nummer im levelset
+ plumberWindow.levelsetname(plumberWindow.controller.logic.levelset.getLevelSet().getName()); //levelset ordner name
+ }
+
+ @Override
+ /**
+ * Wenn Selektion �ber Pfeiltasten ge�ndert wird
+ */
+ public void _level(SelectionChange e)
+ {
+ Panel p = (Panel) plumberWindow.getGamePanel();
+ p.OnLevelChange(e.currentLevel);
+ }
+
+ @Override
+ /**
+ * Wenn Timer tickt (alle 750 ms)
+ */
+ public void _level(Timer e)
+ {
+ plumberWindow.settime(plumberWindow.controller.logic.level.getLevel().getTimeLeft()); //set remaining time in gamewindow
+ if(water_started)
+ {
+ Panel p = (Panel) plumberWindow.getGamePanel();
+ p.OnLevelChange(plumberWindow.controller.logic.level.getLevel());
+ }
+ }
+
+ @Override
+ /**
+ * Wasser kommt nicht in Senke an -> GameOver
+ */
+ public void _level(WaterOut e) //when water goes out
+ {
+ plumberWindow.gameoverdialog(); //you lose dialog
+ }
+
+ @Override
+ /**
+ * Wasser erreicht Senke -> Level gewonnen
+ */
+ public void _level(WaterWin e) //water comes to sink
+ {
+ plumberWindow.gamewindialog(); //you win dialog
+ plumberWindow.controller.logic.stopGame(); //stop the game
+ water_started = false;
+ if(plumberWindow.controller.logic.levelset.nextLevel()) //next level if existent
+ {
+ plumberWindow.controller.logic.startGame(); //new level start
+ }else
+ {
+ plumberWindow.levelsetenddialog(); //level set ending dialog
+ }
+ }
+
+ @Override
+ /**
+ * Wasserfluss startet
+ */
+ public void _level(WaterStart e) //water start trigger
+ {
+ water_started = true; //water start true
+ }
+
+ /**
+ * restart Level
+ */
+ public void restart(){
+ plumberWindow.controller.logic.level.restart(); //call restart
+ }
+
+ /**
+ * UnDo aufruf
+ */
+ public void UnDo(){
+ plumberWindow.controller.logic.level.UnDo();
+ }
+
+
+ /**
+ * ReDo aufruf
+ */
+ public void ReDo(){
+ plumberWindow.controller.logic.level.ReDo();
+ }
+
+
+ /**
+ * Wenn Levelelement ge�ndert wird
+ * rotiert oder mit Wasser gef�llt
+ */
+ public void levelelement(LevelElementEvent_abstract e){
+ //Update gamewindow according to info in e
+ Panel p = (Panel) plumberWindow.getGamePanel();
+ p.OnLevelChange(plumberWindow.controller.logic.level.getLevel());
+ };
+}
diff --git a/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/game/Panel.java b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/game/Panel.java
new file mode 100644
index 00000000..07302dcb
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/game/Panel.java
@@ -0,0 +1,157 @@
+package de.tu_darmstadt.gdi1.plumber.view.game;
+
+import java.awt.*;
+import java.util.Vector;
+
+import javax.swing.JButton;
+import javax.swing.border.LineBorder;
+
+import de.tu_darmstadt.gdi1.plumber.model.exceptions.PlumberError;
+import de.tu_darmstadt.gdi1.plumber.model.level.Level;
+import de.tu_darmstadt.gdi1.plumber.model.levelelements.Element_abstract;
+import de.tu_darmstadt.gdi1.plumber.model.levelelements.Pipe_Bent;
+import de.tu_darmstadt.gdi1.plumber.model.levelelements.Pipe_Straight;
+import de.tu_darmstadt.gdi1.plumber.model.levelelements.Sink;
+import de.tu_darmstadt.gdi1.plumber.model.levelelements.Well;
+import de.tu_darmstadt.gdi1.plumber.view.tudframework.GamePanel;
+import de.tu_darmstadt.gdi1.plumber.view.tudframework.GameWindow;
+import de.tu_darmstadt.gdi1.plumber.view.tudframework.ParameterOutOfRangeException;
+
+
+/**
+ * Plumber GamePanel
+ */
+public class Panel extends GamePanel{
+
+ private static final long serialVersionUID = -6952107268488601098L;
+
+ private Window gamewindow;
+
+ public Panel(GameWindow theParentWindow) {
+ super(theParentWindow);
+
+ this.gamewindow = (Window) theParentWindow;
+
+ setVisible(true);
+ }
+
+ /**
+ * Bei Button benutzung rotiere Element rechtsrum.
+ */
+ @Override
+ protected void entityClicked(int positionX, int positionY) {
+ gamewindow.controller.logic.level.rotateRight(new Point(positionY,positionX));
+ }
+
+ @Override
+ protected void panelResized() {
+ //Auto-generated method stub -> not used
+ }
+
+ /**
+ * Bei Level�nderung (Rotieren, Roter Kasten wandert, Felder sind bew�ssert)
+ * wird der Frame geleert und das Level wird neu gemalt.
+ * @param level das aktuelle Level
+ */
+ public void OnLevelChange(Level level)
+ {
+ clearFrame(); //macht Panel leer
+ Vector> elements = level.getElements();
+
+ Point selectedElement = gamewindow.controller.logic.level.getSelection(); //ausgew�hltes Element (Roter Kasten)
+
+ Point levelsize; //Levelgr��e
+ try {
+ levelsize = level.getLevelSize();
+ } catch (PlumberError exp) {
+ //Auto-generated catch block
+ return;
+ }
+ setLayout(new GridLayout(levelsize.x,levelsize.y)); //Feldgr��e als GridLayout setzen
+
+ //geschachtelte For-Schleife um alle Levelelemente durch zu gehen und Bilder zu finden
+ for(int i = 0; i < elements.size(); i++)
+ {
+ for(int j= 0; j < elements.get(i).size(); j++)
+ {
+ Element_abstract e = elements.get(i).get(j);
+ String ident = "";
+
+ try {
+ if(e instanceof Well) //Quelle
+ {
+ ident += "WELL_"; //identifier f�r Bild hinzuf�gen/anbauen
+ } else
+ if(e instanceof Sink) //Senke
+ {
+ ident += "SINK_"; //identifier f�r Bild hinzuf�gen/anbauen
+ } else
+ if(e instanceof Pipe_Bent) //gebogen
+ {
+ ident += "BENT_"; //identifier f�r Bild hinzuf�gen/anbauen
+ }else
+ if(e instanceof Pipe_Straight) //gerade
+ {
+ ident += "STRAIGHT_"; //identifier f�r Bild hinzuf�gen/anbauen
+ } else
+ {
+ return;
+ }
+
+ if(e.getCon(Element_abstract.CON_LEFT)) //Element hat Verbindung links
+ {
+ ident += "LEFT_"; //identifier f�r Bild hinzuf�gen/anbauen
+ }
+ if(e.getCon(Element_abstract.CON_RIGHT)) //Element hat Verbindung rechts
+ {
+ ident += "RIGHT_"; //identifier f�r Bild hinzuf�gen/anbauen
+ }
+ if(e.getCon(Element_abstract.CON_TOP)) //Element hat Verbindung oben
+ {
+ ident += "UP_"; //identifier f�r Bild hinzuf�gen/anbauen
+ }
+ if(e.getCon(Element_abstract.CON_BOTTOM)) //Element hat Verbindung unten
+ {
+ ident += "DOWN_"; //identifier f�r Bild hinzuf�gen/anbauen
+ }
+
+ if(e.isWatered()) //Felder mit Wassergef�llt
+ {
+ ident += "FILLED"; //identifier f�r Bild hinzuf�gen/anbauen
+ } else
+ {
+ ident += "UNFILLED"; //identifier f�r Bild hinzuf�gen/anbauen
+ }
+
+ JButton b = placeEntity(ident); //Button an Stelle plazieren
+ b.setBorder(new LineBorder(Color.LIGHT_GRAY,2)); //grauer Rand am Button
+ //b.setMargin(new Insets(-50,-50,-50,-50));
+ if( selectedElement.x == i &&
+ selectedElement.y == j)
+ {
+ b.setBorder(new LineBorder(Color.RED,2)); //wenn der Button selektiert ist Rand Rot
+ }
+
+ } catch (ParameterOutOfRangeException e1) {
+ e1.printStackTrace();
+ }
+ }
+ }
+
+ //Gr��e des Fensters anpassen
+ gamewindow.pack();
+
+ //Frame Position
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ int top = (screenSize.height - gamewindow.getSize().height) / 2 ;
+ int left = (screenSize.width - gamewindow.getSize().width) / 2 ;
+ gamewindow.setLocation(left , top);
+
+ }
+
+ @Override
+ protected void setGamePanelContents() {
+ //Auto-generated method stub -> not used
+ }
+
+}
diff --git a/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/game/Window.java b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/game/Window.java
new file mode 100644
index 00000000..de717744
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/game/Window.java
@@ -0,0 +1,340 @@
+package de.tu_darmstadt.gdi1.plumber.view.game;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+import javax.swing.AbstractButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+
+import de.tu_darmstadt.gdi1.plumber.controller.Controller;
+import de.tu_darmstadt.gdi1.plumber.controller.logic.LogicController;
+import de.tu_darmstadt.gdi1.plumber.view.ViewLogicListener;
+
+import translator.TranslatableGUIElement;
+/**
+ * Plumber Window, in dem das Panel(Spielfeld) eingefügt wird.
+ */
+public class Window extends de.tu_darmstadt.gdi1.plumber.view.tudframework.GameWindow
+{
+ public final static String WINDOW_NAME = "Plumber - Game";
+
+ private static final long serialVersionUID = -5796601737808769009L;
+
+ public Controller controller;
+ private ViewLogicListener logiclistener;
+ public JLabel timeleft;
+ public JLabel level;
+ public JLabel levelset;
+ private JDialog gameover;
+
+
+ /**
+ * zur Optischen darstellung der Levelnummer im Set
+ * @param levelnumber Nummer des Levels
+ */
+ public void levelnumber (int levelnumber){
+ level.setText(" Level: " + String.valueOf(levelnumber)); //aktuelles Level anzeigen
+ }
+
+ /**
+ * zur Optischen darstellung des Levelsetnamens (Ordner)
+ * @param levelset name des Levelsets
+ */
+ public void levelsetname(String levelset){
+ this.levelset.setText(levelset); //levelset Name
+ }
+
+ /** zum optischen runterzählen der Zeit
+ * @param time
+ */
+ public void settime (int time){
+
+ timeleft.setText(String.valueOf(time/1000));
+
+ if(time <= 9999) //weniger als 10sec
+ {
+ timeleft.setForeground(Color.RED); //rote Schrift
+ }
+
+ }
+
+ /**
+ * Dialog:
+ * wird angezeigt, wenn das Level verloren wurde
+ */
+ public void gameoverdialog (){ //bei game over
+ JLabel game = controller.view.getTranslator().getGenerator().generateJLabel("gameover");
+
+ JOptionPane.showMessageDialog(gameover, game); //zeige gameoverText in eigenem Fenster an
+ timeleft.setForeground(Color.BLACK);
+ }
+
+ /**
+ * Dialog
+ * Wird angezeigt, wenn das Level gewonnen wurde.
+ */
+ public void gamewindialog (){ //bei gewinn des Levels
+ JLabel game = controller.view.getTranslator().getGenerator().generateJLabel("mastered");
+
+ JOptionPane.showMessageDialog(gameover, game); //zeige masteredText in eigenem Fenster an
+ timeleft.setForeground(Color.BLACK);
+ }
+
+ /**
+ * Dialog
+ * Wird angezeigt, wenn das Levelset zu ende ist.
+ */
+ public void levelsetenddialog() {
+ JLabel game = controller.view.getTranslator().getGenerator().generateJLabel("ended");
+
+ JOptionPane.showMessageDialog(gameover, game);
+ controller.view.showMainMenuWindow();
+ }
+
+ /**
+ * Wenn "W" gedrückt wird, startet der Wasserfluss sofort
+ */
+ protected void keyWaterPressed(){
+ controller.logic.level.startWater();
+ }
+
+ /**
+ * Wenn "Q" gedrückt wird, wird das Programm vom Spielfeld aus beendet.
+ */
+ protected void keyQuitPressed(){
+ controller.exit();
+ }
+
+ /**
+ * Wenn "T" gedrückt wird, dann wird das Theme im Spiel geändert.
+ */
+ protected void keyThemePressed(){
+ if(!controller.view.nextTheme())
+ {
+ controller.view.loadTheme(0);
+ }
+ ((Panel)gamePanel).OnLevelChange(controller.logic.level.getLevel());
+ }
+
+ /**
+ * Wenn "N" gedrückt wird, wird das aktuelle Level neu gestartet.
+ */
+ protected void keyNewGamePressed() {
+ controller.logic.level.restart();
+ }
+
+ /**
+ * Wenn "Backspace" gedrückt wird, dann wird der vorherige
+ * Schritt Rückgänig gemacht.
+ */
+ protected void keyUndoPressed() {
+ controller.logic.level.UnDo();
+ }
+
+ /**
+ * Wenn "Enter" gedrückt wird, dann werden die Schritte die
+ * Rückgängig gemacht wurden wiedergeholt
+ */
+ protected void keyRedoPressed() {
+ controller.logic.level.ReDo();
+ }
+
+ /**
+ * Wenn "Leertaste" gedrückt, dann wird das selektierte
+ * Feld rotiert.
+ */
+ protected void keySpacePressed() {
+ controller.logic.level.rotateSelected();
+ }
+
+ /**
+ * "Linke Pfeiltaste" das Feld links vom selektierten
+ * Feld wird nun selektiert. Wenn möglich.
+ */
+ protected void keyLeftPressed() {
+ controller.logic.level.moveSelectionLeft();
+ }
+
+ /**
+ * "Rechte Pfeiltaste" das Feld rechts vom selektierten
+ * Feld wird nun selektiert. Wenn möglich.
+ */
+ protected void keyRightPressed() {
+ controller.logic.level.moveSelectionRight();
+ }
+
+ /**
+ * "Pfeiltaste Hoch" das Feld über dem selektierten
+ * Feld wird nun selektiert. Wenn möglich.
+ */
+ protected void keyUpPressed() {
+ controller.logic.level.moveSelectionUp();
+ }
+
+ /**
+ * "Pfeiltaste Runter" das Feld unter dem selektierten
+ * Feld wird nun selektiert. Wenn möglich.
+ */
+ protected void keyDownPressed() {
+ controller.logic.level.moveSelectionDown();
+ }
+
+ protected void keyOtherPressed (KeyEvent key) {
+ switch(key.getKeyCode())
+ {
+ case KeyEvent.VK_W: //"W" Taste definierne
+ {
+ keyWaterPressed();
+ break;
+ }
+
+ case KeyEvent.VK_T://"T" Taste definieren
+ {
+ keyThemePressed();
+ break;
+ }
+
+ }
+ }
+
+ /**
+ * Listener deregistrieren.
+ */
+ public void finalize()
+ {
+ LogicController.deregisterListener(logiclistener);
+ }
+
+ public Window(final Controller controller) {
+ super(WINDOW_NAME, controller);
+
+ logiclistener = new ViewLogicListener(this);
+ LogicController.registerListener(logiclistener);
+
+ this.controller = controller;
+
+ addWindowListener(new WindowAdapter(){
+ @Override
+ public void windowClosing(WindowEvent arg0) {
+ controller.view.showMainMenuWindow();
+ }
+
+ });
+
+ //Frame Position
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ int top = (screenSize.height - getSize().height) / 2 ;
+ int left = (screenSize.width - getSize().width) / 2 ;
+ setLocation(left , top);
+
+ //setSize(400,400);
+
+ }
+ protected @Override de.tu_darmstadt.gdi1.plumber.view.tudframework.GamePanel createGamePanel(Controller controller)
+ {
+ // retrieve the GUI element builder
+ TranslatableGUIElement guiBuilder = controller.view.getTranslator().getGenerator();
+
+ //set panel
+ //Layout in Window
+ setLayout(new BorderLayout());
+
+ //Levelinfo -> North
+ JPanel levelinfo = new JPanel();
+ levelinfo.setLayout(new GridLayout(1,2));
+
+ //Label für Level und Levelset
+ level = new JLabel();
+ levelset = new JLabel();
+
+ //Labels hinzufügen
+ levelinfo.add(levelset);
+ levelinfo.add(level);
+ add(levelinfo, BorderLayout.NORTH);
+
+ //Label für Timeleft
+ timeleft = new JLabel();
+
+ //ButtonPanel -> South
+ JPanel buttonpanel = new JPanel();
+ buttonpanel.setLayout(new GridLayout(4,2));
+
+ //create translatable labels and buttons
+ JLabel timetext = guiBuilder.generateJLabel("timeLeft");
+ AbstractButton restart = guiBuilder.generateJButton("restart");
+ restart.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event) {
+ keyNewGamePressed();
+ }});
+
+ //Undo Button - translatable
+ AbstractButton undo = guiBuilder.generateJButton("undo");
+ undo.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event) {
+ keyUndoPressed();
+ }});
+
+ //Redo Button - translatable
+ AbstractButton redo = guiBuilder.generateJButton("redo");
+ redo.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event) {
+ keyRedoPressed();
+ }});
+
+
+ //Exit Button - translatable
+ AbstractButton exit = guiBuilder.generateJButton("exit");
+ exit.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event) {
+ keyQuitPressed();
+ }});
+
+ //Theme Button - translatable
+ AbstractButton theme = guiBuilder.generateJButton("theme");
+ theme.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event) {
+ keyThemePressed();
+ }});
+
+ //Water Button - translatable
+ AbstractButton water = guiBuilder.generateJButton("Wasser");
+ water.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event) {
+ keyWaterPressed();
+ }});
+
+ //add buttons to panel
+ buttonpanel.add(timetext);
+ buttonpanel.add(timeleft);
+ buttonpanel.add(undo);
+ buttonpanel.add(redo);
+ buttonpanel.add(water);
+ buttonpanel.add(theme);
+ buttonpanel.add(restart);
+ buttonpanel.add(exit);
+ add(buttonpanel, BorderLayout.SOUTH);
+
+ //GamePanel
+ gamePanel = new Panel(this);
+ add(gamePanel, BorderLayout.CENTER);
+
+ return gamePanel;
+ }
+
+ public void showWindow()
+ {
+ //window visibility
+ setVisible(true);
+ }
+}
\ No newline at end of file
diff --git a/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/tudframework/GamePanel.java b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/tudframework/GamePanel.java
new file mode 100644
index 00000000..74b7d1d9
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/tudframework/GamePanel.java
@@ -0,0 +1,552 @@
+/*============================================================================*/
+
+package de.tu_darmstadt.gdi1.plumber.view.tudframework;
+
+/*============================================================================*/
+
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Vector;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+
+
+/*============================================================================*/
+
+/**
+ * Class representing a basic Plumber game field display that you can extend for
+ * your own solution by deriving from it.
+ *
+ * @author Steven Arzt, Oren Avni
+ * @version 1.2
+ */
+public abstract class GamePanel extends JPanel implements MouseListener {
+
+ /* ======================================================================== */
+
+ private static final long serialVersionUID = -1037100806444236904L;
+
+ /* ======================================================================== */
+
+ // the list of entities
+ private Vector entities = null;
+
+ // the loaded images, accessed by name
+ private HashMap images = null;
+
+ // the parent window
+ private GameWindow parentWindow = null;
+
+ // The current layout width and height based on the level
+ private int layoutWidth = 0, layoutHeight = 0;
+
+ // switch for enabling or disabling automatic sizing
+ private boolean autosize = false;
+
+ /* ======================================================================== */
+
+ /**
+ * Creates a new instance of the GamePanel class
+ *
+ * @param theParentWindow
+ * The parent window on which this panel is placed
+ */
+ public GamePanel(GameWindow theParentWindow) {
+ super();
+
+ // Set the reference
+ parentWindow = theParentWindow;
+
+ // Create the internal objects
+ entities = new Vector();
+ images = new HashMap();
+ }
+
+ /* ======================================================================== */
+
+
+ /**
+ * Enables or disables automatic sizing
+ * @param Autosize True if automatic sizing shall be enabled, otherwise
+ * false
+ */
+ public void setAutosize
+ (boolean Autosize)
+ {
+ autosize = Autosize;
+ resizePanel ();
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Resizes the game panel to match the current contents
+ */
+ private void resizePanel ()
+ {
+ int oldWidth = getWidth (), oldHeight = getHeight ();
+ int width = 0, height = 0;
+ for (int i = 0; i < entities.size (); i++)
+ {
+ JButton btn = entities.get (i);
+ int icoWidth = btn.getIcon ().getIconWidth () + 2;
+ int icoHeight = btn.getIcon ().getIconHeight () + 2;
+
+ width = Math.max (width, icoWidth);
+ height = Math.max (height, icoHeight);
+
+ // +2px border size (one pixel per side)
+ if (autosize)
+ btn.setPreferredSize (new Dimension (icoWidth, icoHeight));
+ else
+ btn.setSize (icoWidth, icoHeight);
+ }
+
+ width = layoutWidth * width;
+ height = layoutHeight * height;
+ setSize (width, height);
+
+ if (oldWidth != width || oldHeight != height)
+ {
+ if (autosize)
+ parentWindow.pack ();
+ panelResized ();
+ }
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Draws the game field once again and updates its graphical representation
+ * @throws InternalFailureException
+ * Thrown if an uncorrectable internal error occurs
+ */
+ public void redraw() throws InternalFailureException {
+ // The following code contains a few tricks concerning Swing and
+ // threading. I do not require anyone to understand it - mainly
+ // workarounds for the mess Sun has done...
+
+ if (Thread.currentThread ().getName ().contains ("AWT-EventQueue"))
+ {
+ clearFrame();
+ setGamePanelContents();
+ resizePanel ();
+ }
+ else
+ try
+ {
+ SwingUtilities.invokeAndWait (new Runnable ()
+ {
+ //@Override
+ public void run ()
+ {
+ clearFrame();
+ setGamePanelContents();
+ resizePanel ();
+ }
+ });
+ }
+ catch (Exception ex)
+ {
+ throw new InternalFailureException (ex);
+ }
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Method for setting the game panel's contents. Override this method to
+ * place your game entities like walls, crates etc. on the game field.
+ */
+ protected abstract void setGamePanelContents();
+
+ /* ======================================================================== */
+
+ /**
+ * Clears the game frame by removing all entity buttons and recreating the
+ * corresponding internal data structures. This method can also be used for
+ * initialization purposes.
+ */
+ protected void clearFrame() {
+ for (int i = 0; i < entities.size();) {
+ JButton btn = entities.get(i);
+ btn.setVisible(false);
+ remove(btn);
+ synchronized (entities)
+ {
+ entities.remove(btn);
+ }
+ clearFrame();
+ return;
+ }
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Notifies the game panel that a new level has been loaded
+ *
+ * @param width
+ * The width of the level just loaded
+ * @param height
+ * The height if the level just loaded
+ * @throws ParameterOutOfRangeException
+ * Thrown if one of the parameters falls out of the range of
+ * acceptable values
+ * @throws InternalFailureException
+ * Thrown if an uncorrectable internal error occurs
+ */
+ void notifyLevelLoaded(int width, int height)
+ throws ParameterOutOfRangeException, InternalFailureException {
+ // Check the parameters
+ if (width <= 0)
+ throw new ParameterOutOfRangeException("Game Panel width negative");
+ if (height <= 0)
+ throw new ParameterOutOfRangeException("Game Panel height negative");
+
+ // Initialize the layout
+ layoutWidth = width;
+ layoutHeight = height;
+ setLayout(new GridLayout(height, width));
+ redraw();
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Returns whether there are already entities on this game panel
+ *
+ * @return True if there are already entities on this game panel, otherwise
+ * false
+ */
+ protected boolean hasEntities() {
+ return entities.size() > 0;
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Checks whether a specific image has already been registered with the game
+ * panel
+ *
+ * @param identifier
+ * The unique image identifier
+ * @throws ParameterOutOfRangeException
+ * Thrown if one of the parameters falls out of the range of
+ * acceptable values
+ */
+ protected boolean isImageRegistered(String identifier)
+ throws ParameterOutOfRangeException {
+ // Check the parameter
+ if (identifier == null || identifier.equals(""))
+ throw new ParameterOutOfRangeException("Identifier invalid");
+ return images.containsKey(identifier);
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Registers a new image in this game panel. Please note that the identifier
+ * must be unique, so the operation will fail if an image with the specified
+ * identifier has already been registered.
+ *
+ * @param identifier
+ * The new image's unique identifier
+ * @param fileName
+ * The file name from which to load the image file
+ * @throws ParameterOutOfRangeException
+ * Thrown if one of the parameters falls out of the range of
+ * acceptable values
+ * @throws InvalidOperationException
+ * Thrown if this operation is not permitted due to the object's
+ * current state
+ * @throws InternalFailureException
+ * Thrown if an uncorrectable internal error occurs
+ */
+ public void registerImage(String identifier, String fileName)
+ throws ParameterOutOfRangeException,
+ InvalidOperationException,
+ InternalFailureException {
+ try
+ {
+ // Check for file existence
+ File f = new File (fileName);
+ if (!f.exists ())
+ throw new InvalidOperationException
+ ("File " + fileName + " not found");
+
+ StringBuilder builder = new StringBuilder ();
+ builder.append ("file:");
+ //builder.append (File.separator);
+ builder.append (f.getCanonicalPath ());
+ registerImage(identifier, new URL (builder.toString ()));
+ }
+ catch (MalformedURLException ex)
+ {
+ throw new ParameterOutOfRangeException ("fileName", ex);
+ }
+ catch (IOException ex)
+ {
+ throw new InternalFailureException (ex);
+ }
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Registers a new image in this game panel. Please note that the identifier
+ * must be unique, so the operation will fail if an image with the specified
+ * identifier has already been registered.
+ *
+ * @param identifier
+ * The new image's unique identifier
+ * @param fileName
+ * The URL from which to load the image file
+ * @throws ParameterOutOfRangeException
+ * Thrown if one of the parameters falls out of the range of
+ * acceptable values
+ * @throws InvalidOperationException
+ * Thrown if this operation is not permitted due to the object's
+ * current state
+ */
+ protected void registerImage(String identifier, URL fileName)
+ throws ParameterOutOfRangeException, InvalidOperationException {
+ // Check the parameters
+ if (identifier == null || identifier.equals(""))
+ throw new ParameterOutOfRangeException("Identifier invalid");
+ if (fileName == null || fileName.equals(""))
+ throw new ParameterOutOfRangeException("FileName invalid");
+
+ if (isImageRegistered(identifier))
+ throw new InvalidOperationException(
+ "An image with this identifier "
+ + "has already been registered");
+
+ images.put(identifier, new ImageIcon(fileName));
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Unregisters a previously registered image from this game panel. If the
+ * specified identifier does not exist, an exception is thrown.
+ * @param identifier
+ * The image's unique identifier
+ * @throws ParameterOutOfRangeException
+ * Thrown if one of the parameters falls out of the range of
+ * acceptable values
+ * @throws InvalidOperationException
+ * Thrown if this operation is not permitted due to the object's
+ * current state
+ */
+ protected void unregisterImage(String identifier)
+ throws ParameterOutOfRangeException, InvalidOperationException {
+ // Check the parameters
+ if (identifier == null || identifier.equals(""))
+ throw new ParameterOutOfRangeException("Identifier invalid");
+
+ if (!isImageRegistered(identifier))
+ throw new InvalidOperationException(
+ "An image with this identifier "
+ + "has not been registered");
+ images.remove (identifier);
+ }
+
+ public void clearImages()
+ {
+ images.clear();
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Places a graphical entity on the game panel.
+ *
+ * @param imageIdentifier
+ * The identifier of a previously registered image that will be
+ * used for rendering the entity
+ * @throws ParameterOutOfRangeException
+ * Thrown if one of the parameters falls out of the range of
+ * acceptable values
+ * @return The placed entity (JButton).
+ */
+ protected JButton placeEntity(String imageIdentifier)
+ throws ParameterOutOfRangeException {
+
+ // Check the parameters
+ if (imageIdentifier == null || imageIdentifier.equals(""))
+ throw new ParameterOutOfRangeException("ImageIdentifier invalid");
+
+ // Get the image icon
+ ImageIcon img = images.get(imageIdentifier);
+ if (img == null)
+ throw new RuntimeException("An image with the identifier "
+ + imageIdentifier + " could not be found");
+
+ return(
+ placeEntity(
+ img
+ )
+ );
+ }
+
+ /**
+ * Places a graphical entity on the game panel.
+ *
+ * @param image
+ * An image which will be used for the entity.
+ * @return The placed entity (JButton).
+ */
+ protected JButton placeEntity(Image image){
+ return(
+ placeEntity(
+ new ImageIcon(
+ image
+ )
+ )
+ );
+ }
+
+ /**
+ * Places a graphical entity on the game panel.
+ *
+ * @param icon
+ * An icon which will be used for the entity.
+ * @return The placed entity (JButton).
+ */
+ protected JButton placeEntity(Icon icon){
+ // Create the visual entity
+ JButton btn = new JButton();
+
+ btn.setMargin(
+ new Insets(
+ 0 , 0 , 0 , 0
+ )
+ );
+
+ synchronized(entities){
+ entities.add(btn);
+ }
+
+ btn.addKeyListener(parentWindow);
+ btn.addMouseListener(this);
+ btn.setIcon(icon);
+
+ // add it
+ add(btn);
+ btn.requestFocus();
+
+ return( btn );
+ }
+
+
+ /* ======================================================================== */
+
+ /**
+ * This method is called whenever an entity on the game field is clicked
+ *
+ * @param positionX
+ * The x coordinate of the entity that was clicked
+ * @param positionY
+ * The y coordinate of the entity that was clicked
+ */
+ protected abstract void entityClicked(int positionX, int positionY);
+
+ /* ======================================================================== */
+
+ /**
+ * This method is called whenever the game panel is resized
+ */
+ protected abstract void panelResized ();
+
+ /* ======================================================================== */
+
+ // @Override
+ /**
+ * This method handles the "mouse clicked" mouse event by converting the
+ * event into a call to entityClicked(int, int).
+ *
+ * @param evt the mouse event caused by clicking "somewhere" on the screen
+ * @see #entityClicked(int, int)
+ */
+ public void mouseClicked(MouseEvent evt) {
+ if (!hasEntities())
+ return;
+ // retrieve first button
+ JButton refBtn = entities.get(0);
+
+ // iterate buttons until right one was found
+ for (int i = 0; i < entities.size(); i++) {
+ JButton btn = entities.get(i);
+ if (evt.getSource() == btn) {
+ // determine x and y position
+ int posX = evt.getXOnScreen();
+ posX = posX - (int) this.getLocationOnScreen().getX();
+
+ int posY = evt.getYOnScreen();
+ posY = posY - (int) this.getLocationOnScreen().getY();
+
+ // pass message along
+ entityClicked(posX / refBtn.getWidth(), posY
+ / refBtn.getHeight());
+
+ // done!
+ evt.consume();
+ break;
+ }
+ }
+ }
+
+ /* ======================================================================== */
+
+ public void mousePressed(MouseEvent arg0) {
+ // nothing to be done here
+ }
+
+ /* ======================================================================== */
+
+ public void mouseReleased(MouseEvent arg0) {
+ // nothing to be done here
+ }
+
+ /* ======================================================================== */
+
+ public void mouseEntered(MouseEvent arg0) {
+ // nothing to be done here
+ }
+
+ /* ======================================================================== */
+
+ public void mouseExited(MouseEvent arg0) {
+ // nothing to be done here
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Gets the parent window for this game field
+ *
+ * @return This game field's parent window
+ */
+ public GameWindow getParentWindow() {
+ return parentWindow;
+ }
+
+ /* ======================================================================== */
+
+}
+
+/* ============================================================================ */
diff --git a/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/tudframework/GameWindow.java b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/tudframework/GameWindow.java
new file mode 100644
index 00000000..965ea59b
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/tudframework/GameWindow.java
@@ -0,0 +1,271 @@
+/*============================================================================*/
+
+package de.tu_darmstadt.gdi1.plumber.view.tudframework;
+
+/*============================================================================*/
+
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+
+import de.tu_darmstadt.gdi1.plumber.controller.Controller;
+
+
+/*============================================================================*/
+
+/**
+ * Base class for the main game window. Derive from this class for implementing
+ * your custom solution.
+ *
+ * @author Steven Arzt, Oren Avni, Jonas Marczona
+ * @version 1.1
+ */
+public abstract class GameWindow extends de.tu_darmstadt.gdi1.plumber.view.windows.Translatable implements KeyListener {
+
+ /* ======================================================================== */
+
+ private static final long serialVersionUID = -2646785578035515024L;
+
+ /* ======================================================================== */
+
+ protected GamePanel gamePanel = null;
+
+ /* ======================================================================== */
+
+ /**
+ * Creates a new instance of the GameWindow class
+ *
+ * @param windowTitle The title of the game window
+ * @throws InternalFailureException
+ * Thrown if an uncorrectable internal error occurs
+ */
+ public GameWindow(String windowTitle, Controller controller) {
+ super(windowTitle,controller);
+
+ // We may need to correct the window title
+ if (windowTitle == null || windowTitle.equals(""))
+ setTitle("Plumber Student Implementation");
+
+ // Create the game panel
+ gamePanel = createGamePanel(controller);
+ if (gamePanel == null)
+ throw new RuntimeException("The game panel may not be null");
+
+ // Configure the frame
+ addKeyListener( this );
+ //setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ setResizable(false);
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Override this method to create your own custom game panel.
+ *
+ * @return An instance of the GamePanel you want to use
+ */
+ protected abstract GamePanel createGamePanel (Controller controller);
+
+ /* ======================================================================== */
+
+ /**
+ * Method that is invoked whenever the left arrow key is pressed. Override
+ * this method to implement your custom solution
+ */
+ protected void keyLeftPressed() {
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Method that is invoked whenever the right arrow key is pressed. Override
+ * this method to implement your custom solution
+ */
+ protected void keyRightPressed() {
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Method that is invoked whenever the up arrow key is pressed. Override
+ * this method to implement your custom solution
+ */
+ protected void keyUpPressed() {
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Method that is invoked whenever the down arrow key is pressed. Override
+ * this method to implement your custom solution
+ */
+ protected void keyDownPressed() {
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Method that is invoked whenever the "q" key is pressed. Override this
+ * method to implement your custom solution
+ */
+ protected void keyQuitPressed(){
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Method that is invoked whenever the "n" key is pressed. Override this
+ * method to implement your custom solution
+ */
+ protected void keyNewGamePressed() {
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Method that is invoked whenever the backspace key is pressed. Override
+ * this method to implement your custom solution
+ */
+ protected void keyUndoPressed() {
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Method that is invoked whenever the return key is pressed. Override this
+ * method to implement your custom solution
+ */
+ protected void keyRedoPressed(){
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Method that is invoked whenever the space key is pressed. Override this
+ * method to implement your custom solution
+ */
+ protected void keySpacePressed() {
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Method that is invoked whenever a key that is not explicitly handled has
+ * been pressed. Override this method to implement your custom solution.
+ */
+ protected void keyOtherPressed (KeyEvent key){
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * This method consumes a KeyEvent caused by the user pressing a key. If the
+ * key is "known", the appropriate method key*Pressed will be called.
+ *
+ * @see #keyUpPressed()
+ * @see #keyLeftPressed()
+ * @see #keyRightPressed()
+ * @see #keyDownPressed()
+ * @see #keyNewGamePressed()
+ * @see #keyRedoPressed()
+ * @see #keyUndoPressed()
+ */
+ public void keyPressed(KeyEvent key) {
+ // retrieve the key code and call the appropriate method, if any
+ switch (key.getKeyCode()) {
+ case KeyEvent.VK_LEFT:
+ keyLeftPressed();
+ break;
+
+ case KeyEvent.VK_RIGHT:
+ keyRightPressed();
+ break;
+
+ case KeyEvent.VK_UP:
+ keyUpPressed();
+ break;
+
+ case KeyEvent.VK_DOWN:
+ keyDownPressed();
+ break;
+
+ case KeyEvent.VK_Q:
+ keyQuitPressed();
+ break;
+
+ case KeyEvent.VK_N:
+ keyNewGamePressed();
+ break;
+
+ case KeyEvent.VK_BACK_SPACE:
+ keyUndoPressed();
+ break;
+
+ case KeyEvent.VK_ENTER:
+ keyRedoPressed();
+ break;
+
+ case KeyEvent.VK_SPACE:
+ keySpacePressed();
+ break;
+
+ default:
+ keyOtherPressed(key);
+ break;
+ }
+ }
+
+ /* ======================================================================== */
+
+ public void keyReleased(KeyEvent key) {
+ // nothing to be done here
+ }
+
+ /* ======================================================================== */
+
+ public void keyTyped(KeyEvent key) {
+ // nothing to be done here
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Returns the game panel used by this game window
+ *
+ * @return The game panel used by this game window
+ */
+ public GamePanel getGamePanel() {
+ return gamePanel;
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Notifies the game window that a new level has been loaded
+ *
+ * @param width
+ * The width of the level just loaded
+ * @param height
+ * The height of the level just loaded
+ * @throws ParameterOutOfRangeException
+ * Thrown if one of the parameters falls out of the range of
+ * acceptable values
+ * @throws InternalFailureException
+ * Thrown if an uncorrectable internal error occurs
+ */
+ public void notifyLevelLoaded(int width, int height)
+ throws ParameterOutOfRangeException, InternalFailureException {
+ // Check the parameters
+ if (width <= 0)
+ throw new ParameterOutOfRangeException("Game Window width invalid");
+ if (height <= 0)
+ throw new ParameterOutOfRangeException("Game Window height invalid");
+
+ // Notify the panel
+ gamePanel.notifyLevelLoaded(width, height);
+ }
+
+ /* ======================================================================== */
+
+}
+
+/* ============================================================================ */
diff --git a/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/tudframework/InternalFailureException.java b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/tudframework/InternalFailureException.java
new file mode 100644
index 00000000..ca759a2d
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/tudframework/InternalFailureException.java
@@ -0,0 +1,52 @@
+/*============================================================================*/
+
+package de.tu_darmstadt.gdi1.plumber.view.tudframework;
+
+/*============================================================================*/
+
+/**
+ * Exception that occurs in the case of internal errors. If a method throws this
+ * exception, this normally indicates a bug and there is nothing that the caller
+ * could do.
+ *
+ * @author Steven Arzt, Oren Avni, Guido Roessling
+ * @version 1.0
+ */
+public class InternalFailureException extends Exception {
+
+ /* ======================================================================== */
+
+ private static final long serialVersionUID = 0L;
+
+ /* ======================================================================== */
+
+ /**
+ * Creates a new instance of the InternalFailureException class based upon
+ * the reason for creation (treated as an inner exception).
+ *
+ * @param cause
+ * The cause why the internal error has occurred. Pass the
+ * original exception or a more detailed internal one here.
+ */
+ public InternalFailureException(Throwable cause) {
+ super(cause);
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Creates a new instance of the InternalFailureException class based upon a
+ * textual reason
+ *
+ * @param errorMessage
+ * The reason why this error has occurred
+ */
+ public InternalFailureException(String errorMessage) {
+ super(errorMessage);
+ }
+
+ /* ======================================================================== */
+
+}
+
+/* ============================================================================ */
diff --git a/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/tudframework/InvalidOperationException.java b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/tudframework/InvalidOperationException.java
new file mode 100644
index 00000000..0a697025
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/tudframework/InvalidOperationException.java
@@ -0,0 +1,49 @@
+package de.tu_darmstadt.gdi1.plumber.view.tudframework;
+
+/*============================================================================*/
+
+/**
+ * Exception that is thrown whenever a method's parameter falls out of the scope
+ * of allowed values
+ *
+ * @author Steven Arzt, Oren Avni, Guido Roessling
+ * @version 1.1
+ */
+public class InvalidOperationException extends Exception {
+
+ /* ======================================================================== */
+
+ private static final long serialVersionUID = 1L;
+
+ /* ======================================================================== */
+
+ /**
+ * Creates a new instance of the InvalidOperationException class
+ *
+ * @param errorMessage
+ * A string description of the reason why this operation is
+ * invalid
+ */
+
+ public InvalidOperationException (String errorMessage) {
+ super(errorMessage);
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Creates a new instance of the InvalidOperationException class
+ *
+ * @param cause
+ * The original exception that has lead to the error
+ */
+
+ public InvalidOperationException (Throwable cause) {
+ super (cause);
+ }
+
+ /* ======================================================================== */
+
+}
+
+/* ============================================================================ */
diff --git a/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/tudframework/ParameterOutOfRangeException.java b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/tudframework/ParameterOutOfRangeException.java
new file mode 100644
index 00000000..e73c606d
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/tudframework/ParameterOutOfRangeException.java
@@ -0,0 +1,98 @@
+package de.tu_darmstadt.gdi1.plumber.view.tudframework;
+
+/*============================================================================*/
+
+/**
+ * Exception that is thrown whenever a method's parameter falls out of the scope
+ * of allowed values
+ *
+ * @author Steven Arzt, Oren Avni, Guido Roessling
+ * @version 1.0
+ */
+public class ParameterOutOfRangeException extends Exception {
+
+ /* ======================================================================== */
+
+ private static final long serialVersionUID = 1L;
+
+ private String parameterName = "";
+ private Object value = null;
+
+ /* ======================================================================== */
+
+ /**
+ * Creates a new instance of the ParameterOutOfRangeException class
+ *
+ * @param paramName
+ * The name of the parameter that has failed the validity check
+ */
+
+ public ParameterOutOfRangeException(String paramName) {
+ this(paramName, null);
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Creates a new instance of the ParameterOutOfRangeException class with the
+ * value that has caused the error
+ *
+ * @param paramName
+ * The name of the parameter that has failed the validity check
+ * @param aValue
+ * The value that has caused the error
+ */
+
+ public ParameterOutOfRangeException(String paramName, Object aValue) {
+ super ("The " + paramName + " parameter got an invalid value");
+ parameterName = paramName;
+ value = aValue;
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Creates a new instance of the ParameterOutOfRangeException class with an
+ * inner exception for exception chaining
+ *
+ * @param paramName
+ * The name of the parameter that has failed the validity check
+ * @param innerException
+ * The inner exception that has led to this one
+ */
+
+ public ParameterOutOfRangeException(String paramName,
+ Throwable innerException) {
+ super(innerException);
+ parameterName = paramName;
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Gets the name of the parameter that has failed the validity check
+ *
+ * @return The name of the parameter that has failed the validity check
+ */
+
+ public String getParameterName() {
+ return parameterName;
+ }
+
+ /* ======================================================================== */
+
+ /**
+ * Gets the value that has caused the error
+ *
+ * @return The value that has caused the error
+ */
+
+ public Object getValue() {
+ return value;
+ }
+
+ /* ======================================================================== */
+
+}
+
+/* ============================================================================ */
diff --git a/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/windows/AboutWindow.java b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/windows/AboutWindow.java
new file mode 100644
index 00000000..21cf18e0
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/windows/AboutWindow.java
@@ -0,0 +1,92 @@
+package de.tu_darmstadt.gdi1.plumber.view.windows;
+import javax.swing.*;
+
+import de.tu_darmstadt.gdi1.plumber.controller.Controller;
+
+import java.awt.*;
+import java.awt.event.*;
+
+/**
+ * Fenster für die credits
+ *
+ */
+public class AboutWindow extends Translatable{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 647745719966414188L;
+
+ /**
+ * Controller-Referenz
+ */
+ @SuppressWarnings("unused")
+ private Controller controller;
+
+ /** generiert ein Fenster mit den credits
+ * @param controller
+ */
+ public AboutWindow (final Controller controller){
+ super("Plumber - About", controller);
+
+ this.controller = controller;
+ addWindowListener(new WindowAdapter(){
+ @Override
+ public void windowClosing(WindowEvent arg0) { //wenn Fenster geschlossen wird
+ controller.view.showMainMenuWindow(); //MainMenuWindow anzeigen
+ }
+
+ });
+
+ setLayout(new BorderLayout());
+
+ //translatable lable
+ JLabel creditText = controller.view.getTranslator().getGenerator().generateJLabel("credits");
+ add(creditText, BorderLayout.PAGE_START); //fügt credits Text hinzu
+
+ JLabel aboutText = controller.view.getTranslator().getGenerator().generateJLabel ("about");
+ add(aboutText, BorderLayout.CENTER); //fügt about Text hinzu
+
+ //translatable lable
+ JLabel nameText = controller.view.getTranslator().getGenerator().generateJLabel("names");
+ add(nameText, BorderLayout.PAGE_END); //fügt Namen hinzu
+
+ AbstractButton aboutToMenu = controller.view.getTranslator().getGenerator().generateJButton("backButton",null,false);
+ aboutToMenu.addActionListener(new ActionListener(){
+ public void actionPerformed(ActionEvent e){
+ controller.view.showMainMenuWindow();
+ }
+ });
+ add(aboutToMenu, BorderLayout.SOUTH);
+
+ //Frame Size
+ Dimension frameSize = new Dimension (250, 200);
+ setSize(frameSize);
+
+ //Frame Position - middle of screen
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ int top = (screenSize.height - frameSize.height) / 2 ;
+ int left = (screenSize.width - frameSize.width) / 2 ;
+ setLocation(left , top);
+ }
+
+ /**
+ * Zeigt Fenster
+ */
+ public void showWindow() {
+ // Open the window
+ setVisible(true);
+
+ }
+
+ /**
+ * Versteckt Fenster
+ */
+ public void hideWindow() {
+ setVisible(false);
+
+ }
+
+}
+
+
diff --git a/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/windows/DirectionsWindow.java b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/windows/DirectionsWindow.java
new file mode 100644
index 00000000..f5e62705
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/windows/DirectionsWindow.java
@@ -0,0 +1,89 @@
+package de.tu_darmstadt.gdi1.plumber.view.windows;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.awt.Toolkit;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+import javax.swing.JLabel;
+
+import de.tu_darmstadt.gdi1.plumber.controller.Controller;
+
+
+/**
+ * Fenster für Spielanleitung
+ *
+ */
+public class DirectionsWindow extends Translatable
+{
+ /**
+ *
+ */
+ private static final long serialVersionUID = 8507153576958050668L;
+
+ /**
+ * Controller-Refferenz
+ */
+ @SuppressWarnings("unused")
+ private Controller controller;
+
+ /** generiert ein Fenster mit der Spielanleitung
+ * @param controller
+ */
+ public DirectionsWindow(final Controller controller)
+ {
+ super("Plumber",controller);
+ this.controller = controller;
+ addWindowListener(new WindowAdapter(){
+ @Override
+ public void windowClosing(WindowEvent arg0) { //wenn Fenster geschlossen wird
+ controller.view.showMainMenuWindow(); //MainMenuWindow anzeigen
+ }
+
+ });
+
+ //translatable lable
+ JLabel controlText = controller.view.getTranslator().getGenerator().generateJLabel("control");
+ add(controlText, BorderLayout.PAGE_START); //fügt controll Text hinzu
+
+ setLayout(new GridLayout(3,1)); // GridLayout mit 3 Texten
+ //translatable lable
+ JLabel shortcutsText = controller.view.getTranslator().getGenerator().generateJLabel("shortcuts");
+ add(shortcutsText); //fügt shortcut Text hinzu
+
+ //translatable lable
+ JLabel aimText = controller.view.getTranslator().getGenerator().generateJLabel("aim");
+ add(aimText); //fügt goal Text hinzu
+
+ //translatable lable
+ JLabel rulesText = controller.view.getTranslator().getGenerator().generateJLabel("rules");
+ add(rulesText); //fügt rule Text hinzu
+
+
+ //Frame Size
+ Dimension frameSize = new Dimension (600, 500);
+ setSize(frameSize);
+
+ //Frame Position - middle of screen
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ int top = (screenSize.height - frameSize.height) / 2 ;
+ int left = (screenSize.width - frameSize.width) / 2 ;
+ setLocation(left , top);
+ }
+
+ /**
+ * Zeigt Fenster
+ */
+ public void showWindow() {
+ setVisible(true);
+ }
+
+ /**
+ * Versteckt Fenster
+ */
+ public void hideWindow() {
+ setVisible(false);
+ }
+}
diff --git a/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/windows/HighscoreWindow.java b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/windows/HighscoreWindow.java
new file mode 100644
index 00000000..7d759815
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/windows/HighscoreWindow.java
@@ -0,0 +1,112 @@
+package de.tu_darmstadt.gdi1.plumber.view.windows;
+
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.awt.Toolkit;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import de.tu_darmstadt.gdi1.plumber.controller.Controller;
+import de.tu_darmstadt.gdi1.plumber.model.highscores.Highscore;
+
+
+/**
+ * Fenster für den Highscore
+ *
+ */
+public class HighscoreWindow extends Translatable
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1065886056990842168L;
+
+ /**
+ * Controller-Refferenz
+ */
+ @SuppressWarnings("unused")
+ private Controller controller;
+
+ /**
+ * Konstruktor für das HighscoreWindow,
+ *
+ * zeigt Highscore für das aktuelle Levelset an
+ * @param controller
+ */
+ public HighscoreWindow(final Controller controller){
+ super("Highscore",controller);
+ this.controller = controller;
+
+ addWindowListener(new WindowAdapter(){
+ @Override
+ public void windowClosing(WindowEvent arg0) {
+ controller.view.showMainMenuWindow();
+ }
+
+ });
+
+
+ //Layout des kompletten Fensters
+ setLayout(new BorderLayout());
+
+
+ //Layout für Highscore
+ JPanel highscore = new JPanel();
+ highscore.setLayout(new GridLayout(11,4));
+
+ //frameName translatable lable
+ JLabel highscoreText = controller.view.getTranslator().getGenerator().generateJLabel ("highscore");
+ add(highscoreText, BorderLayout.NORTH);
+
+ highscore.add(new JLabel("Name")); //muss nicht übersetzt werden
+ //translatable lable
+ JLabel timeText = controller.view.getTranslator().getGenerator().generateJLabel ("time");
+ highscore.add(timeText);
+ highscore.add(new JLabel("Level")); //muss nicht übersetzt werden
+ //translatable lable
+ JLabel pointsText = controller.view.getTranslator().getGenerator().generateJLabel ("points");
+ highscore.add(pointsText);
+
+ for (int i = 0 ; i < 10 ; i++){
+ if (controller.logic.levelset.getHighscore().getAt(i) == null){ //für leere Highscoreliste
+ highscore.add(new JLabel("-"));
+ highscore.add(new JLabel("-"));
+ highscore.add(new JLabel("-"));
+ highscore.add(new JLabel("-"));
+
+ }else //Highscoreeintrag machen
+ {
+ highscore.add(new JLabel(controller.logic.levelset.getHighscore().getAt(i).getPlayername()));
+ highscore.add(new JLabel(String.valueOf(controller.logic.levelset.getHighscore().getAt(i).getTime()/1000)));
+ highscore.add(new JLabel(String.valueOf(controller.logic.levelset.getHighscore().getAt(i).getReachedlevel())));
+ highscore.add(new JLabel(String.valueOf(Highscore.calculatePoints(controller.logic.levelset.getHighscore().getAt(i)))));
+ }
+ }
+
+ add(highscore);
+
+ //Frame Size
+ Dimension frameSize = new Dimension (300, 500);
+ setSize(frameSize);
+
+ //Frame Position - middle of screen
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ int top = (screenSize.height - frameSize.height) / 2 ;
+ int left = (screenSize.width - frameSize.width) / 2 ;
+ setLocation(left , top);
+
+ }
+
+ /**
+ * Versteckt Fenster
+ */
+ public void showWindow() {
+ setVisible(true);
+ }
+}
\ No newline at end of file
diff --git a/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/windows/MainMenuWindow.java b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/windows/MainMenuWindow.java
new file mode 100644
index 00000000..29ce4705
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/windows/MainMenuWindow.java
@@ -0,0 +1,213 @@
+package de.tu_darmstadt.gdi1.plumber.view.windows;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.AbstractButton;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+import de.tu_darmstadt.gdi1.plumber.controller.Controller;
+import de.tu_darmstadt.gdi1.plumber.controller.options.Option;
+import de.tu_darmstadt.gdi1.plumber.controller.options.Options;
+
+import translator.TranslatableGUIElement;
+
+/**
+ * Hauptmenü
+ */
+public class MainMenuWindow extends Translatable{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 3575290148137411381L;
+ @SuppressWarnings("unused")
+ /**
+ * Controller-Refferenz
+ */
+ private Controller controller;
+
+ /**
+ * Playername-Eingabe-Feld
+ */
+ private JTextField playername;
+
+ /**
+ * Levelset-Text-Feld
+ */
+ private JLabel lvlset;
+
+
+ /**
+ * Constructs a new window with a given title
+ * Includes buttons which will be displayed in the selected language
+ */
+ public MainMenuWindow(final Controller controller) {
+ super("Plumber",controller);
+
+ // retrieve the GUI element builder
+ TranslatableGUIElement guiBuilder = controller.view.getTranslator().getGenerator();
+
+
+ this.controller = controller;
+ //Main Menu -> 8 Buttons
+ setLayout(new GridLayout (7,1));
+
+ addWindowListener(new WindowAdapter(){
+ @Override
+ public void windowClosing(WindowEvent arg0) {
+ controller.exit();
+ }
+
+ });
+
+ //PlayerName
+ JPanel player = new JPanel();
+ player.setLayout(new GridLayout());
+
+ //Textfield and Button for PlayerName
+ playername = new JTextField("Player");
+
+ Option o = Options.getOption("playername");
+
+ if(o != null)
+ {
+ playername.setText(o.getValue());
+ }
+
+ playername.getDocument().addDocumentListener(new DocumentListener() {
+ public void changedUpdate(DocumentEvent e)
+ {
+ Options.setOption(new Option("playername", playername.getText()));
+ }
+ public void removeUpdate(DocumentEvent e){
+ changedUpdate(e);
+ }
+ public void insertUpdate(DocumentEvent e){
+ changedUpdate(e);
+ }
+ });
+ /*playername.addFocusListener(new FocusAdapter() {
+ public void focusLost(FocusEvent evt) {
+
+ }}
+ );*/
+
+ player.add(playername);
+
+ add(player);
+
+ //Levelset
+ JPanel levelset = new JPanel();
+ levelset.setLayout(new BorderLayout());
+ JButton last = new JButton("<");
+ last.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event) {
+ if(controller.logic.previousLevelSet())
+ {
+ lvlset.setText(controller.logic.levelset.getLevelSet().getName());
+ }
+ }
+ });
+ lvlset = new JLabel(controller.logic.levelset.getLevelSet().getName());
+ lvlset.setHorizontalAlignment(JLabel.CENTER);
+ JButton next = new JButton(">");
+ next.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event) {
+ if(controller.logic.nextLevelSet())
+ {
+ lvlset.setText(controller.logic.levelset.getLevelSet().getName());
+ }
+ }
+ });
+
+ levelset.add(last, BorderLayout.LINE_START);
+ levelset.add(lvlset, BorderLayout.CENTER);
+ levelset.add(next, BorderLayout.LINE_END);
+
+
+ add(levelset);
+ //Game Start Button
+ AbstractButton game_start= guiBuilder.generateJButton("startButton");
+ game_start.addActionListener(new ActionListener(){
+ public void actionPerformed(ActionEvent e)
+ {
+ controller.view.showGameWindow();
+ }
+
+ });
+ add(game_start);
+
+
+ //Highscore Button
+ AbstractButton highscore_button = guiBuilder.generateJButton("highscoreButton");
+ highscore_button.addActionListener(new ActionListener(){
+ public void actionPerformed(ActionEvent e)
+ {
+ System.out.println("Here you can see the Highscore");
+ controller.view.showHighscoreWindow();
+
+ }
+ });
+ add(highscore_button);
+
+ //Directions Button
+ AbstractButton options_button = guiBuilder.generateJButton("directionsButton");
+ options_button.addActionListener(new ActionListener(){
+ public void actionPerformed(ActionEvent e)
+ {
+ controller.view.showDirectionsWindow();
+ }
+ });
+ add(options_button);
+
+ //About Button
+ AbstractButton about_button = guiBuilder.generateJButton("aboutButton");
+ about_button.addActionListener(new ActionListener(){
+ public void actionPerformed(ActionEvent e)
+ {
+ controller.view.showAboutWindow();
+ }
+ });
+ add(about_button);
+
+ //Exit Button
+ AbstractButton exit_button = guiBuilder.generateJButton("exit");
+ exit_button.addActionListener(new ActionListener(){
+ public void actionPerformed(ActionEvent e)
+ {
+ controller.exit();
+ }
+ });
+ add(exit_button);
+
+ //Window Size
+ Dimension frameSize = new Dimension (250, 250);
+ setSize(frameSize);
+
+ //window Location
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ int top = (screenSize.height - frameSize.height) / 2 ;
+ int left = (screenSize.width - frameSize.width) / 2 ;
+ setLocation(left , top);
+ }
+
+ /**
+ * Zeigt Fenster
+ */
+ public void showWindow() {
+ setVisible(true);
+ }
+
+ /**
+ * Versteckt Fenster
+ */
+ public void hideWindow() {
+ setVisible(false);
+ }
+
+ }
\ No newline at end of file
diff --git a/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/windows/Translatable.java b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/windows/Translatable.java
new file mode 100644
index 00000000..39f4a196
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Plumber/src/de/tu_darmstadt/gdi1/plumber/view/windows/Translatable.java
@@ -0,0 +1,82 @@
+package de.tu_darmstadt.gdi1.plumber.view.windows;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Locale;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+
+import de.tu_darmstadt.gdi1.plumber.controller.Controller;
+
+import translator.TranslatableGUIElement; // for GUI elements
+
+public class Translatable extends JFrame{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1874366379191280678L;
+
+ /**
+ * Controller-Referenz
+ */
+ @SuppressWarnings("unused")
+ private Controller controller;
+
+ /**
+ * builds a menu with language options
+ * when language is chosen all of the translatable objects are displayed in the chosen language
+ *
+ * @param windowName window "name"
+ * @param controller
+ */
+ public Translatable(String windowName, final Controller controller){
+
+ // windowName is given to JFrame to create a window with the given title
+ super(windowName);
+ this.controller = controller;
+
+
+ // retrieve the GUI element builder
+ TranslatableGUIElement guiBuilder = controller.view.getTranslator().getGenerator();
+
+ // create a JMenuBar
+ JMenuBar menuBar = new JMenuBar();
+ // generate the JMenu for this
+ JMenu menu = guiBuilder.generateJMenu("languageMenu");
+
+ // add the menu to the menu bar and add this to the JFrame
+ menuBar.add(menu);
+ super.setJMenuBar(menuBar);
+
+ // generate a menu item with parameters (key, useIconIfExists)
+ //deutsch button
+ JMenuItem deutschItem = guiBuilder.generateJMenuItem("deutschItem");
+
+ //set the language to German
+ deutschItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ controller.view.getTranslator().setTranslatorLocale(Locale.GERMANY);
+ }
+ });
+ // add the item to the JMenu
+ menu.add(deutschItem);
+
+ // generate a menu item with parameters (key, useIconIfExists)
+ //english button
+ JMenuItem englishItem = guiBuilder.generateJMenuItem("englishItem");
+
+ // set the language to English
+ englishItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ controller.view.getTranslator().setTranslatorLocale(Locale.US);
+ }
+ });
+ // add the item to the JMenu
+ menu.add(englishItem);
+ }
+
+}
diff --git a/ws2009/gdi I/exercise/src/StockTicker/.classpath b/ws2009/gdi I/exercise/src/StockTicker/.classpath
new file mode 100644
index 00000000..06c7b695
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/StockTicker/.classpath
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/ws2009/gdi I/exercise/src/StockTicker/.project b/ws2009/gdi I/exercise/src/StockTicker/.project
new file mode 100644
index 00000000..43603c02
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/StockTicker/.project
@@ -0,0 +1,17 @@
+
+
+ StockTicker
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/ws2009/gdi I/exercise/src/StockTicker/.settings/org.eclipse.jdt.core.prefs b/ws2009/gdi I/exercise/src/StockTicker/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..e74acee6
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/StockTicker/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Tue Jan 26 10:12:01 CET 2010
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/ws2009/gdi I/exercise/src/StockTicker/Stock Ticker.ump b/ws2009/gdi I/exercise/src/StockTicker/Stock Ticker.ump
new file mode 100644
index 00000000..8ae79181
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/StockTicker/Stock Ticker.ump
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ws2009/gdi I/exercise/src/StockTicker/src/StockTicker.java b/ws2009/gdi I/exercise/src/StockTicker/src/StockTicker.java
new file mode 100644
index 00000000..b387037e
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/StockTicker/src/StockTicker.java
@@ -0,0 +1,261 @@
+import java.awt.Color;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.swing.Timer;
+
+import acm.graphics.GLabel;
+import acm.graphics.GLine;
+import acm.graphics.GPoint;
+import acm.graphics.GRect;
+import acm.program.GraphicsProgram;
+
+public class StockTicker extends GraphicsProgram {
+
+ /**
+ * Solves a warning; not realy needed
+ */
+ private static final long serialVersionUID = 1L;
+
+ // maximum delay for timers to call updateTicker
+ private static final int MAX_DURATION = 5000;
+
+ // the maximum value to expect
+ private static final int MAX_VALUE = 1000;
+
+ // the number of calls to updateTicker
+ private static final int NR_TIMERS = 3000;
+
+ // the maximum difference of old and new value
+ private static final int MAX_FLUCTUATION = 15;
+
+ // the ticker symbols traded
+ private static final String[] SYMBOLS = new String[] { "SNC", "EKDD",
+ "ATD", "AGN", "HEDM" };
+
+ private Map oldPos;
+
+ // we keep the timers in this collection to start them after init()
+ private Vector timers;
+
+ // the appr. time when the timers were startes
+ private long startedAt;
+
+ // the mapping of ticker symbols to colors
+ protected Map colors;
+
+ /**
+ * Create a new StockTicker.
+ *
+ * This will instantiate all timers with their calls to updateTicker and put
+ * them into the timers collection.
+ */
+ public StockTicker()
+ {
+ timers = new Vector(NR_TIMERS);
+
+ final Map oldWorth = new HashMap();
+ for (String symbol : SYMBOLS)
+ {
+ // start somewhere near MAX_VALUE/2
+ oldWorth.put(symbol, MAX_VALUE * Math.random() / 2 + (MAX_VALUE / 4));
+ }
+ for (int i = 0; i < NR_TIMERS; i++)
+ {
+ // instantiate a timer with a random delay within 0..MAX_DURATION
+ Timer timer = new Timer((int) (Math.random() * MAX_DURATION),
+ new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ // get a random ticker symbol
+ String symbol = SYMBOLS[(int) (Math.random() * SYMBOLS.length)];
+
+ // calculate the new worth
+ double newWorth = oldWorth.get(symbol)
+ + MAX_FLUCTUATION * 2
+ * (Math.random() - 0.5);
+
+ // do not increase beyond MAX_VALUE
+ if (newWorth > MAX_VALUE) {
+ newWorth -= MAX_FLUCTUATION;
+ }
+ // save the new value for next time
+ oldWorth.put(symbol, newWorth);
+
+ updateTicker(symbol, newWorth);
+ }
+ });
+ // only fire once
+ timer.setRepeats(false);
+ timers.add(timer);
+ }
+
+ // pre-allocate the color mappings
+ colors = new HashMap();
+ colors.put("SNC", Color.BLUE);
+ colors.put("EKDD", Color.ORANGE);
+ colors.put("ATD", Color.MAGENTA);
+ colors.put("AGN", Color.GRAY);
+ colors.put("HEDM", Color.RED);
+
+ //initialize oldPos HashMap
+ oldPos = new HashMap();
+ }
+
+ /**
+ * Start the timers and set the startTime.
+ */
+ public void startTicking() {
+ startedAt = System.currentTimeMillis();
+ for (Timer timer : timers) {
+ timer.start();
+ }
+ }
+
+ /**
+ * Correct Height
+ * Delete this when acm is fixed
+ */
+ @Override
+ public int getHeight()
+ {
+ return super.getHeight() - 30;
+ }
+
+ /**
+ * Draw Interface: - Y-Axis
+ * - X-Lines every 50 pixel
+ * - Value of every line
+ * - White Rect
+ * - Names of TickerSymbols in right Color
+ */
+ @Override
+ public void init()
+ {
+ { //draw horizontal line
+ GLine hline = new GLine(0,0,0,getHeight());
+ add(hline); //draw it
+ }
+
+ final int distance = 50; //50px distance between vlines
+
+ { //draw vertical lines
+ for(int i=0; i <= (getHeight()/distance);i++) //lines
+ {
+ for(int j=0; j < (getWidth()/10);j++) //small lines every 10px with leght 5
+ {
+ //many small lines per "line"
+ GLine vline = new GLine( j*10+1, //+1 to not override the x-achsis
+ getHeight()-i*distance,
+ j*10+5+1,
+ getHeight()-i*distance);
+ vline.setColor(Color.LIGHT_GRAY); //light-gray!!!
+ add(vline); //draw it
+ }
+
+ //once per line
+ GLabel label = new GLabel( String.valueOf((int)(((double)MAX_VALUE/(double)getHeight())*i*distance)),
+ 3,
+ getHeight()-i*distance-2);
+ add(label); //draw it
+ }
+ }
+
+ { //Draw white Rect
+ GRect rect = new GRect(getWidth()-120,0,120,120);
+ rect.setColor(Color.WHITE); //color
+ rect.setFilled(true); //do fill
+ add(rect); //draw it
+ }
+
+ { //Draw Labels in Rect
+ for(int i=0;i < SYMBOLS.length; i++)
+ {
+ //new label with symbol
+ GLabel label = new GLabel(SYMBOLS[i],getWidth()-100,i*20+20);
+ //set the right color
+ label.setColor(colors.get(SYMBOLS[i])); //load color here
+ //draw it
+ add(label);
+ }
+ }
+
+ // uncomment this line when you have implemented 6.3 - i have
+ startTicking();
+ }
+
+ /**
+ * Converts a X-Value relative to startedAt to an Pixel-Value
+ * relative to MAX_DURATION and Window-Width
+ *
+ * @param x X-Value relative to startedAT
+ * @return Pixel-Value which represents given X-Value
+ */
+ public double XVal2XPix(double x)
+ {
+ //pixel_per_timepassed
+ return ((double)getWidth()/(double)MAX_DURATION)*x;
+ }
+
+ /**
+ * Converts a Y-Value(worth) to an Pixel-Value
+ * relative to MAX_VALUE and Window-Height
+ *
+ * @param y Y-Value(worth)
+ * @return Pixel-Value which represents given Y-Value
+ */
+ public double YVal2YPix(double y)
+ {
+ //pixel_per_valuepoint
+ return ((double)getHeight()/(double)MAX_VALUE)*y;
+ }
+
+ /**
+ * Update the graph of a single ticker symbol.
+ *
+ * @param symbol A textual representation of the ticker symbol.
+ * @param worth The new worth of the company.
+ */
+ public void updateTicker(String symbol, double worth)
+ {
+ //Calculate new Coordinates with time passed since start(x) and worth(y)
+ double x_val = XVal2XPix(System.currentTimeMillis() - startedAt);
+ double y_val = YVal2YPix(worth);
+
+ //Get last Value of given ticker-symbol
+ GPoint oldgp = oldPos.get(symbol);
+
+ //No old value stored at first call for every ticker-symbol
+ if(oldgp == null)
+ {
+ //create new Point with actual values instead
+ oldgp = new GPoint(x_val/*1*/,y_val);//x_val,y_val);
+ }
+
+ //line from oldpos to newpos
+ GLine line = new GLine( oldgp.getX(), //oldpos
+ oldgp.getY(),
+ x_val, //newpos
+ y_val);
+
+ //set the right color for every ticker-symbol
+ line.setColor(colors.get(symbol));
+
+ //paint it
+ add(line);
+
+ //store new pos as oldpos for next call.
+ oldPos.put(symbol, new GPoint(x_val,y_val));
+ }
+
+ /**
+ * Instantiate a new StockTicker and start it.
+ */
+ public static void main(String[] args) {
+ new StockTicker().start(args);
+ }
+
+}
diff --git a/ws2009/gdi I/exercise/src/StockTicker/src/StockTicker_Solution.java b/ws2009/gdi I/exercise/src/StockTicker/src/StockTicker_Solution.java
new file mode 100644
index 00000000..4bc57789
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/StockTicker/src/StockTicker_Solution.java
@@ -0,0 +1,206 @@
+import java.awt.Color;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.swing.Timer;
+
+import acm.graphics.GLabel;
+import acm.graphics.GLine;
+import acm.graphics.GPoint;
+import acm.graphics.GRect;
+import acm.program.GraphicsProgram;
+
+public class StockTicker_Solution extends GraphicsProgram {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1866080068453559421L;
+
+ // maximum delay for timers to call updateTicker
+ private static final int MAX_DURATION = 5000;
+
+ // the maximum value to expect
+ private static final int MAX_VALUE = 1000;
+
+ // the number of calls to updateTicker
+ private static final int NR_TIMERS = 3000;
+
+ // the maximum difference of old and new value
+ private static final int MAX_FLUCTUATION = 15;
+
+ // the ticker symbols traded
+ private static final String[] SYMBOLS = new String[] { "SNC", "EKDD",
+ "ATD", "AGN", "HEDM" };
+
+ // we keep the timers in this collection to start them after init()
+ private Vector timers;
+
+ // the appr. time when the timers were startes
+ private long startedAt;
+
+ // the mapping of ticker symbols to colors
+ protected Map colors;
+
+ //
+ protected Map oldPos;
+
+ /**
+ * Create a new StockTicker.
+ *
+ * This will instantiate all timers with their calls to updateTicker and put
+ * them into the timers collection.
+ */
+ public StockTicker_Solution() {
+ timers = new Vector(NR_TIMERS);
+
+ final Map oldWorth = new HashMap();
+ for (String symbol : SYMBOLS) {
+ // start somewhere near MAX_VALUE/2
+ oldWorth.put(symbol, MAX_VALUE * Math.random() / 2 + (MAX_VALUE / 4));
+ }
+ for (int i = 0; i < NR_TIMERS; i++) {
+ // instantiate a timer with a random delay within 0..MAX_DURATION
+ Timer timer = new Timer((int) (Math.random() * MAX_DURATION),
+ new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ // get a random ticker symbol
+ String symbol = SYMBOLS[(int) (Math.random() * SYMBOLS.length)];
+
+ // calculate the new worth
+ double newWorth = oldWorth.get(symbol)
+ + MAX_FLUCTUATION * 2
+ * (Math.random() - 0.5);
+
+ // do not increase beyond MAX_VALUE
+ if (newWorth > MAX_VALUE) {
+ newWorth -= MAX_FLUCTUATION;
+ }
+ // save the new value for next time
+ oldWorth.put(symbol, newWorth);
+
+ updateTicker(symbol, newWorth);
+ }
+ });
+ // only fire once
+ timer.setRepeats(false);
+ timers.add(timer);
+ }
+
+ // pre-allocate the color mappings
+ colors = new HashMap();
+ colors.put("SNC", Color.BLUE);
+ colors.put("EKDD", Color.ORANGE);
+ colors.put("ATD", Color.MAGENTA);
+ colors.put("AGN", Color.GRAY);
+ colors.put("HEDM", Color.RED);
+
+ oldPos = new HashMap();
+
+ }
+
+
+ /**
+ * Start the timers and set the startTime.
+ */
+ public void startTicking() {
+ startedAt = System.currentTimeMillis();
+ for (Timer timer : timers) {
+ timer.start();
+ }
+ }
+
+ @Override
+ public void init() {
+ // add your call to the methods from 6.2 here
+ GLine line_y = new GLine (0 , 0 , 0 , getHeight() );
+ line_y.setColor(Color.black);
+ add(line_y);
+
+ for (int i = 0; i < (getHeight() / 50) ; i++)
+ {
+ GLabel label = new GLabel (Integer.toString(MAX_VALUE - 100*(10-i)), 5 , getHeight() - (50*i + 5) ) ;
+ add(label);
+ for (int j = 0; j < (getWidth() / 8) ; j++)
+ {
+ GLine line_x = new GLine ( j * 8, getHeight() - (50 * i), j * 8 + 5, getHeight() - (50 * i));
+ line_x.setColor(Color.gray);
+ add(line_x);
+ }
+ }
+
+ GRect names = new GRect(getWidth()- 70,0,70,80);
+ names.setFillColor(Color.white);
+ names.setColor(Color.white);
+ names.setFilled(true);
+ add(names);
+
+
+ for (int i = 0 ; i < SYMBOLS.length ; i++)
+ {
+ GLabel symbols = new GLabel (SYMBOLS[i], getWidth() - 50 , 5 + ((i+1) * 10));
+ symbols.setColor(colors.get(SYMBOLS[i]));
+ add(symbols);
+ }
+
+ // uncomment this line when you have implemented 6.3
+ startTicking();
+ }
+
+ /**
+ * Update the graph of a single ticker symbol.
+ *
+ * @param symbol A textual representation of the ticker symbol.
+ * @param worth The new worth of the company.
+ */
+ public void updateTicker(String symbol, double worth) {
+
+
+
+
+ if (oldPos.containsKey(symbol)) {
+
+ GLine stock = new GLine (
+ oldPos.get(symbol).getX(), //old x
+ oldPos.get(symbol).getY(), //old y
+ (System.currentTimeMillis() - startedAt) * getWidth() / MAX_DURATION, //new x
+ getHeight () - (worth / 2));//new y
+ stock.setColor(colors.get(symbol));
+ add(stock);
+
+ oldPos.put(symbol, new GPoint (
+ (System.currentTimeMillis() - startedAt) * getWidth()/ MAX_DURATION ,
+ getHeight() - (worth / 2)));
+ } else
+
+ {
+ GLine stock = new GLine(0,
+ getHeight() - (worth / 2),
+ (System.currentTimeMillis() - startedAt) * getWidth() / MAX_DURATION,
+ getHeight() - (worth / 2));
+ stock.setColor(colors.get(symbol));
+ add(stock);
+
+ oldPos.put(symbol, new GPoint (
+ (System.currentTimeMillis() - startedAt) * getWidth() / MAX_DURATION,
+ getHeight()- (worth / 2)));
+ }
+
+
+ }
+
+
+
+ /**
+ * Instantiate a new StockTicker and start it.
+ * @param args
+ */
+ public static void main(String[] args) {
+ new StockTicker_Solution().start(args);
+ }
+
+}
diff --git a/ws2009/gdi I/exercise/src/StockTicker/tests/SudokuTest.java b/ws2009/gdi I/exercise/src/StockTicker/tests/SudokuTest.java
new file mode 100644
index 00000000..3f8d974b
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/StockTicker/tests/SudokuTest.java
@@ -0,0 +1,228 @@
+import java.util.Arrays;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class SudokuTest {
+
+ /**
+ * Test cases for the solver. Public, because you can also use them to use
+ * them for game initialization!
+ */
+ public final static int[][] testCase1 = new int[][] {
+ { 5, 3, 0, 0, 7, 0, 0, 0, 0 }, { 6, 0, 0, 1, 9, 5, 0, 0, 0 },
+ { 0, 9, 8, 0, 0, 0, 0, 6, 0 }, { 8, 0, 0, 0, 6, 0, 0, 0, 3 },
+ { 4, 0, 0, 8, 0, 3, 0, 0, 1 }, { 7, 0, 0, 0, 2, 0, 0, 0, 6 },
+ { 0, 6, 0, 0, 0, 0, 2, 8, 0 }, { 0, 0, 0, 4, 1, 9, 0, 0, 5 },
+ { 0, 0, 0, 0, 8, 0, 0, 7, 9 } };
+
+ public final static int[][] testCase1Result = new int[][] {
+ { 5, 3, 4, 6, 7, 8, 9, 1, 2 }, { 6, 7, 2, 1, 9, 5, 3, 4, 8 },
+ { 1, 9, 8, 3, 4, 2, 5, 6, 7 }, { 8, 5, 9, 7, 6, 1, 4, 2, 3 },
+ { 4, 2, 6, 8, 5, 3, 7, 9, 1 }, { 7, 1, 3, 9, 2, 4, 8, 5, 6 },
+ { 9, 6, 1, 5, 3, 7, 2, 8, 4 }, { 2, 8, 7, 4, 1, 9, 6, 3, 5 },
+ { 3, 4, 5, 2, 8, 6, 1, 7, 9 } };
+
+ public final static int[][] testCase2 = new int[][] {
+ { 1, 0, 2, 0, 0, 0, 0, 0, 0 }, { 0, 0, 3, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 4 }, { 0, 4, 0, 0, 5, 0, 0, 0, 0 },
+ { 0, 6, 0, 0, 7, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 2, 0 },
+ { 0, 8, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 8, 0, 0 } };
+
+ public final static int[][] testCase2Result = new int[][] {
+ { 1, 5, 2, 3, 4, 6, 7, 8, 9 }, { 4, 7, 3, 1, 8, 9, 2, 5, 6 },
+ { 6, 9, 8, 5, 2, 7, 1, 3, 4 }, { 2, 4, 1, 6, 5, 3, 9, 7, 8 },
+ { 5, 6, 9, 2, 7, 8, 3, 4, 1 }, { 8, 3, 7, 4, 9, 1, 6, 2, 5 },
+ { 3, 8, 4, 9, 1, 2, 5, 6, 7 }, { 7, 1, 6, 8, 3, 5, 4, 9, 2 },
+ { 9, 2, 5, 7, 6, 4, 8, 1, 3 } };
+
+ final int[][] testField3 = new int[][] { { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 2, 0, 4, 5, 6, 7 },
+ { 0, 0, 2, 0, 0, 0, 4, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 4, 0, 0, 0, 2, 0, 0 }, { 0, 0, 5, 4, 0, 2, 1, 0, 0 },
+ { 0, 0, 6, 0, 0, 0, 0, 0, 0 }, { 0, 0, 7, 0, 0, 0, 0, 0, 0 } };
+
+ //From template
+ public final int[][] fullField = new int[][] { { 5, 3, 4, 6, 7, 8, 9, 1, 2 },
+ { 6, 7, 2, 1, 9, 5, 3, 4, 8 }, { 1, 9, 8, 3, 4, 2, 5, 6, 7 },
+ { 8, 5, 9, 7, 6, 1, 4, 2, 3 }, { 4, 2, 6, 8, 5, 3, 7, 9, 1 },
+ { 7, 1, 3, 9, 2, 4, 8, 5, 6 }, { 9, 6, 1, 5, 3, 7, 2, 8, 4 },
+ { 2, 8, 7, 4, 1, 9, 6, 3, 5 }, { 3, 4, 5, 2, 8, 6, 1, 7, 9 } };
+
+ final int[][] sudoku17_1 = new int[][] {
+ {0, 0, 0, 0, 0, 0, 0, 1, 0}, { 0, 6, 0, 3, 0, 0, 0, 0, 0},
+ {9, 0, 0, 0, 0, 0, 0, 7, 0}, { 1, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 4, 0, 0, 6, 0, 0}, { 0, 0, 6, 0, 0, 0, 5, 0, 3},
+ {0, 0, 0, 0, 9, 0, 0, 0, 0}, { 0, 2, 0, 0, 0, 0, 4, 0, 0},
+ {0, 0, 8, 0, 1, 7, 0, 0, 0}
+ };
+
+ /**
+ * The test instance.
+ */
+ private Sudoku sudoku;
+
+ /**
+ * Sets up the test environment.
+ */
+ @Before
+ public void setUp() {
+ sudoku = new Sudoku();
+ }
+
+ /**
+ * Timing check
+ */
+ /*
+ //This one is quite nasty
+ @Test
+ public void testTimingField17()
+ {
+ Assert.assertNull(sudoku.solve(sudoku17_1));
+ }*/
+
+ /**
+ * Timing check2
+ */
+ @Test
+ public void testTimingField3()
+ {
+ Assert.assertNull(sudoku.solve(testField3));
+ }
+
+ /**
+ * Test if predefined fullfield is ok.
+ */
+ @Test
+ public void testFullField()
+ {
+ //Question was raised - so i do the test
+ Assert.assertFalse(sudoku.reject(fullField));
+ }
+
+ /**
+ * Tests the {@link Sudoku#reject(int[][])} method.
+ */
+ @Test
+ public void testReject() {
+ int[][] config = new int[9][9];
+
+ // Empty field is always valid!
+ Assert.assertFalse("reject false negative: rejected empty field!",
+ sudoku.reject(config));
+
+ // Check rows
+ config = new int[9][9];
+ config[5][1] = 9;
+ config[5][7] = 9;
+ Assert.assertTrue("reject false negative: row check failed!", sudoku
+ .reject(config));
+
+ config[5][7] = 6;
+ Assert.assertFalse("reject false positive: row check failed!", sudoku
+ .reject(config));
+
+ // Check columns
+ config = new int[9][9];
+ config[5][1] = 9;
+ config[8][1] = 9;
+ Assert.assertTrue("reject false negative: column check failed!", sudoku
+ .reject(config));
+
+ config[8][1] = 3;
+ Assert.assertFalse("reject false positive: column check failed!",
+ sudoku.reject(config));
+
+ // Check 3x3 fields
+ config = new int[9][9];
+ config[0][0] = 7;
+ config[2][2] = 7;
+ Assert.assertTrue("reject false negative: 3x3 field check failed!",
+ sudoku.reject(config));
+
+ config[2][2] = 4;
+ Assert.assertFalse("reject false positive: 3x3 field check failed!",
+ sudoku.reject(config));
+
+ config[2][3] = 7; // out of top-left field
+ Assert.assertFalse("reject false positive: 3x3 field check failed!",
+ sudoku.reject(config));
+
+ // Check with real-world example
+ Assert.assertFalse("reject false positive: real world example", sudoku
+ .reject(testCase1Result));
+ }
+
+ /**
+ * Tests the {@link Sudoku#getNextFreeField(int[][])} method.
+ */
+ @Test
+ public void testNextFreeField() {
+ int[][] config = new int[9][9];
+
+ // Full & empty field
+ Assert.assertEquals(
+ "getNextFreeField failed: should return 0 if field is empty!",
+ 0, sudoku.getNextFreeField(config));
+ Assert.assertEquals(
+ "getNextFreeField failed: should return -1 if field is full!",
+ -1, sudoku.getNextFreeField(testCase1Result));
+
+ // Normal fields
+ config[0][0] = 5;
+ Assert.assertEquals("getNextFreeField failed!", 1, sudoku
+ .getNextFreeField(config));
+ config[0][1] = 5;
+ Assert.assertEquals("getNextFreeField failed!", 2, sudoku
+ .getNextFreeField(config));
+ config[0] = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ Assert.assertEquals("getNextFreeField failed for second row!", 9,
+ sudoku.getNextFreeField(config));
+ }
+
+ /**
+ * Tests the {@link Sudoku#getNextExtension(int[][], int)} method.
+ */
+ @Test
+ public void testNextExtension() {
+ int[][] config = new int[9][9];
+ config[4][6] = 8; // Field 42
+
+ int[][] newConfig = sudoku.getNextExtension(config, 42);
+ Assert.assertEquals(
+ "getNextExtension failed: did not increment (correct) field!",
+ 9, newConfig[4][6]);
+ Assert.assertNotSame(
+ "getNextExtension failed: did not create a new array!", config,
+ newConfig);
+ Assert.assertNotSame(
+ "getNextExtension failed: did not clone sub-arrays!",
+ config[0], newConfig[0]);
+
+ newConfig = sudoku.getNextExtension(newConfig, 42);
+ Assert
+ .assertEquals(
+ "getNextExtension failed: did not return null if field already is 9",
+ null, newConfig);
+ }
+
+ /**
+ * Tests the {@link Sudoku#solve(int[][])} method.
+ */
+ @Test
+ public void testSolve() {
+ // Test cases
+ Assert.assertTrue("solve failed for test case 1", Arrays.deepEquals(
+ sudoku.solve(testCase1), testCase1Result));
+
+ Assert.assertTrue("solve failed for test case 2", Arrays.deepEquals(
+ sudoku.solve(testCase2), testCase2Result));
+
+ // Finished field should not be modified
+ Assert.assertTrue("solve failed for finished field", Arrays.deepEquals(
+ sudoku.solve(testCase1Result), testCase1Result));
+ }
+}
diff --git a/ws2009/gdi I/exercise/src/Sudoku/.classpath b/ws2009/gdi I/exercise/src/Sudoku/.classpath
new file mode 100644
index 00000000..06c7b695
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Sudoku/.classpath
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/ws2009/gdi I/exercise/src/Sudoku/.project b/ws2009/gdi I/exercise/src/Sudoku/.project
new file mode 100644
index 00000000..b273577a
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Sudoku/.project
@@ -0,0 +1,17 @@
+
+
+ Sudoku
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/ws2009/gdi I/exercise/src/Sudoku/.settings/org.eclipse.jdt.core.prefs b/ws2009/gdi I/exercise/src/Sudoku/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..8d015390
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Sudoku/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Tue Jan 19 13:27:34 CET 2010
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/ws2009/gdi I/exercise/src/Sudoku/src/Sudoku.java b/ws2009/gdi I/exercise/src/Sudoku/src/Sudoku.java
new file mode 100644
index 00000000..c9a59b5f
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/Sudoku/src/Sudoku.java
@@ -0,0 +1,467 @@
+import java.awt.Color;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+
+import java.util.Arrays;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+
+import acm.gui.IntField;
+import acm.gui.TableLayout;
+import acm.gui.TablePanel;
+import acm.program.Program;
+
+public class Sudoku extends Program {
+
+ /**
+ * Fixed boardsize - alter this if you want to make smaller/bigger boards
+ * Not tested! (is this possible?^^)
+ */
+ public static int boardsize = 9;
+
+ /**
+ * Simple avoiding some warnings
+ */
+ private static final long serialVersionUID = 1L;
+
+
+ // the model of the game board
+ IntField[][] board;
+
+ /**
+ * Construct a new game of Sudoku.
+ *
+ * Initializes the game board with all zeroes.
+ */
+ public Sudoku() {
+ super();
+ board = new IntField[9][9];
+ for (int i = 0; i < 9; i++) {
+ for (int j = 0; j < 9; j++) {
+ board[i][j] = new IntField(0);
+ }
+ }
+ }
+
+ /**
+ * Initialize a new game of Sudoku with a given configuration.
+ *
+ * @param values
+ * The configuration of the game board.
+ */
+ public Sudoku(int[][] values) {
+ this();
+ setConfiguration(values);
+ }
+
+ /**
+ * Initialize the view component.
+ */
+ @Override
+ public void init() {
+ setTitle("Sudoku");
+ setLayout(new TableLayout(4, 3));
+ for (int i = 0; i < 9; i++) {
+ add(assembleInnerTable(i));
+ }
+ add(new JButton("Solve"));
+ addActionListeners();
+ }
+
+ /**
+ * Assemble a single 3x3 field.
+ *
+ * @param n
+ * The number of the 3x3 field to assemble a table component for.
+ * @return The TablePanel containing a 3x3 field.
+ */
+ private TablePanel assembleInnerTable(int n) {
+ TablePanel tp = new TablePanel(3, 3);
+ for (int i = 0; i < 9; i++) {
+ // we assemble 3x3 field-wise and have to adjust array indices
+ // accordingly
+ int row = 3 * (n / 3) + i / 3;
+ int col = 3 * (n % 3) + i % 3;
+
+ // The constructor made sure these are instantiated IntFields
+ IntField intField = board[row][col];
+
+ // Register a KeyListener to suppress non-digit entries
+ intField.addKeyListener(new KeyListener() {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ // don't care
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ // don't care
+ }
+
+ @Override
+ public void keyTyped(KeyEvent e) {
+ try {
+ // try to parse the pressed keys value into an Integer
+ Integer.parseInt(String.valueOf(e.getKeyChar()));
+ } catch (NumberFormatException nfe) {
+ // consume the event and stop it from propagating
+ e.consume();
+ }
+ }
+ });
+ tp.add(intField);
+ }
+ // draw a solid black border around every 3x3 field
+ tp.setBorder(BorderFactory.createLineBorder(Color.black));
+ return tp;
+ }
+
+ /**
+ * Initialize the game board with the given arrays of ints.
+ *
+ * @param init The 9x9 two-dimensional array with int values from 0..9
+ */
+ public void setConfiguration(int[][] init) {
+ for (int i = 0; i < 9; i++) {
+ for (int j = 0; j < 9; j++) {
+ if (init[i][j] > 0 && init[i][j] <= 9) {
+ board[i][j].setValue(init[i][j]);
+ } else {
+ board[i][j].setValue(0);
+ }
+ }
+ }
+ }
+
+ /**
+ * Return the current configuration of the game board.
+ *
+ * @return The current configuration.
+ */
+ public int[][] getConfiguration() {
+ int[][] tmp = new int[9][9];
+ for (int i = 0; i < 9; i++) {
+ for (int j = 0; j < 9; j++) {
+ tmp[i][j] = board[i][j].getValue();
+ }
+ }
+ return tmp;
+ }
+
+ // if no solution was found, color every field red
+ public void colorForFailure() {
+ for (int i = 0; i < 9; i++) {
+ for (int j = 0; j < 9; j++) {
+ board[i][j].setBackground(new Color(255, 0, 0));
+ }
+ }
+ }
+
+ // if there was a solution, color the new values fields green
+ public void colorForSuccess(int[][] solution) {
+ int[][] actual = getConfiguration();
+ for (int i = 0; i < 9; i++) {
+ for (int j = 0; j < 9; j++) {
+ if (solution[i][j] != actual[i][j]) {
+ board[i][j].setBackground(new Color(0, 255, 0));
+ board[i][j].setValue(solution[i][j]);
+ } else {
+ board[i][j].setBackground(new Color(255, 255, 255));
+ }
+ }
+ }
+ }
+
+ /**
+ * The ActionListeners method to process pressed buttons.
+ *
+ * @param e ActionEvent
+ */
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (e.getActionCommand().equals("Solve")) {
+ // The solve button was pressed, find a solution
+ int[][] solution = solve(getConfiguration());
+ if (solution != null) {
+ colorForSuccess(solution);
+ } else {
+ colorForFailure();
+ }
+ }
+ }
+
+ /**
+ * Checks if board is valid. Returns false if it is valid, else true.
+ *
+ * public because requested
+ *
+ * @param board Sudoku Configuration
+ * @return false if valid, true if not.
+ */
+ public boolean reject(int[][] board)
+ {
+ //Check input
+ if(board == null)
+ {
+ return true;
+ }
+
+ { //Check if 1-9 is max 1x in every row & line
+
+ //Helper-Vars - Start with false
+ boolean[] row = new boolean[boardsize];
+ boolean[] line = new boolean[boardsize];
+
+ for(int i=0; i < boardsize;i++) //rows
+ {
+ for(int j=0; j < boardsize; j++) //lines
+ {
+ { //row
+ int t = board[i][j]; //value @ act pos //row
+
+ if( t > 0 && //skip 0 and wrong input!
+ t <= boardsize)
+ {
+ if(row[t-1]) //already seen?
+ {
+ //Number already found in row
+ return true;
+ } else
+ {
+ //Set to true - do not accept this number a second time.
+ row[t-1] = true;
+ }
+ }
+ } //row
+
+ { //line
+ int t = board[j][i]; //value @ act pos //line
+
+ if( t > 0 && //skip 0 and wrong input!
+ t <= boardsize)
+ {
+ if(line[t-1]) //already seen?
+ {
+ //Number already found in line
+ return true;
+ } else
+ {
+ //Set to true - do not accept this number a second time.
+ line[t-1] = true;
+ }
+ }
+ } //line
+ }
+
+ //Reset helper-vars, new line/row
+ Arrays.fill(row, false);
+ Arrays.fill(line, false);
+ }
+ } //Check if 1-9 is max 1x in every row&line
+
+ { //Check board-3x3-blocks
+
+ //Helper-Var - Starts with false
+ boolean[] block = new boolean[boardsize];
+
+ for(int n=0; n < 3; n++) //Count block-lines
+ {
+ for(int m=0; m < 3; m++) //Count block-rows
+ {
+ for(int i=0; i < (boardsize/3); i++) //Count line within block
+ {
+ for(int j=0; j < (boardsize/3); j++) //Count row within block
+ {
+ int t = board[n*3+i][m*3+j]; //Value @ act pos
+
+ if( t > 0 && //skip 0 and wrong input!
+ t <= boardsize)
+ {
+ if(block[t-1]) //Number already seen?
+ {
+ //Number already found in Block
+ return true;
+ } else
+ {
+ //Set to true - do not accept this number a second time.
+ block[t-1] = true;
+ }
+ }
+ }
+ }
+
+ //Reset - new block
+ Arrays.fill(block, false);
+ }
+ }
+ } //Check board-3x3-blocks
+
+
+ //All Checked & OK
+ return false;
+ }
+
+ /**
+ * Returns position of the next field which is 0 (free field).
+ *
+ * Position-Encoding: row*boardsize + line
+ * row and line starting by 0.
+ * first item is 0,
+ * last item is boardsize*boardsize -1
+ *
+ * public because assumed it is requested
+ *
+ * @param board
+ * @return Position of next free field or -1 if no free field was found.
+ */
+ public int getNextFreeField(int[][] board)
+ {
+ //Just Checking - should never happen, but method is public... you know...
+ if(board == null)
+ {
+ return -1;
+ }
+
+ //Search
+ for(int i=0; i < boardsize; i++) //row
+ {
+ for(int j=0; j < boardsize; j++) //line
+ {
+ if(board[i][j] == 0) //Is act pos 0 ?
+ {
+ return i*boardsize + j; //Position Calculation
+ }
+ }
+ }
+
+ //Field has no empty fields
+ return -1;
+ }
+
+ /**
+ * Returns new Sudoku configuration with altered (incremented by 1)
+ * value at given position pos.
+ *
+ * public because assumed it is requested
+ *
+ * @param board Given Sudoku configuration
+ * @param pos position to be altered
+ * @return Sudoku configuration or null
+ */
+ public int[][] getNextExtension(int[][] board, int pos)
+ {
+ //Decrypt 1-dim-pos to 2-dim-pos
+ int i = pos/boardsize;
+ int j = pos-i*boardsize;
+
+ if( board != null && //Board ok?
+ i < boardsize && //row ok?
+ j < boardsize && //line ok?
+ board[i][j] < boardsize) //value @ pos < boardsize?
+ {
+ int[][] newboard = new int[boardsize][boardsize];
+
+ { //clone board -> newboard
+ for(int k = 0; k < boardsize; k++)
+ {
+ System.arraycopy(board[k], 0, newboard[k], 0, board[k].length);
+ }
+ } //clone board -> newboard
+
+ newboard[i][j] += 1; // inc value @ pos -> +1
+ return newboard; //return the new board
+ }
+
+ return null; //Something was wrong - see if clause
+ }
+
+ /**
+ * Solve the given Sudoku configuration and return the result.
+ *
+ * @param configuration A 9x9 two-dimensional array, columns first.
+ * @return The solution for this game of Sudoku or null if not solvable.
+ */
+ public int[][] solve(int[][] configuration)
+ {
+ return solve(configuration,getNextFreeField(configuration));
+ }
+ /**
+ * Solve the given Sudoku configuration and return the result.
+ *
+ * @param configuration A 9x9 two-dimensional array, columns first.
+ * @param pos position to be altered (start with getNextFreeField(configuration))
+ * @return The solution for this game of Sudoku or null if not solvable.
+ */
+ public int[][] solve(int[][] configuration, int pos)
+ {
+ //Recursion-anchor
+ if(pos == -1) //all fields are done, or startcall was wrong
+ {
+ return configuration;
+ }
+
+ //Recursion
+ while(true) //Always do^^
+ {
+ configuration = getNextExtension(configuration,pos); //getNextExt checks if pos/config is valid!
+
+ if(configuration == null)
+ {
+ return null; //Could not alter act pos any further, not solvable, try alter fields before filled in
+ }
+
+ if(!reject(configuration)) //is generated config ok?
+ {
+ int[][] tboard = solve(configuration,getNextFreeField(configuration)); //Fill in empty fields recursivly.
+
+ if(tboard != null) // was solvable
+ {
+ return tboard;
+ } //else config was not solvable - alter fields filled in before.
+ }
+ }
+ }
+
+ /**
+ * Main-Method
+ *
+ * some start-soduko-defs
+ *
+ * @param args
+ */
+ public static void main(final String[] args) {
+ @SuppressWarnings("unused")
+ final int[][] emptyField = new int[][] { { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
+
+ @SuppressWarnings("unused")
+ final int[][] fullField = new int[][] { { 5, 3, 4, 6, 7, 8, 9, 1, 2 },
+ { 6, 7, 2, 1, 9, 5, 3, 4, 8 }, { 1, 9, 8, 3, 4, 2, 5, 6, 7 },
+ { 8, 5, 9, 7, 6, 1, 4, 2, 3 }, { 4, 2, 6, 8, 5, 3, 7, 9, 1 },
+ { 7, 1, 3, 9, 2, 4, 8, 5, 6 }, { 9, 6, 1, 5, 3, 7, 2, 8, 4 },
+ { 2, 8, 7, 4, 1, 9, 6, 3, 5 }, { 3, 4, 5, 2, 8, 6, 1, 7, 9 } };
+
+ final int[][] actualField1 = new int[][] {
+ { 5, 3, 0, 0, 7, 0, 0, 0, 0 }, { 6, 0, 0, 1, 9, 5, 0, 0, 0 },
+ { 0, 9, 8, 0, 0, 0, 0, 6, 0 }, { 8, 0, 0, 0, 6, 0, 0, 0, 3 },
+ { 4, 0, 0, 8, 0, 3, 0, 0, 1 }, { 7, 0, 0, 0, 2, 0, 0, 0, 6 },
+ { 0, 6, 0, 0, 0, 0, 2, 8, 0 }, { 0, 0, 0, 4, 1, 9, 0, 0, 5 },
+ { 0, 0, 0, 0, 8, 0, 0, 7, 9 } };
+
+ @SuppressWarnings("unused")
+ final int[][] actualField2 = new int[][] {
+ { 1, 0, 2, 0, 0, 0, 0, 0, 0 }, { 0, 0, 3, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 4 }, { 0, 4, 0, 0, 5, 0, 0, 0, 0 },
+ { 0, 6, 0, 0, 7, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 2, 0 },
+ { 0, 8, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 8, 0, 0 } };
+
+ new Sudoku(actualField1).start();
+ }
+
+}
diff --git a/ws2009/gdi I/exercise/src/TrainSimulation/.classpath b/ws2009/gdi I/exercise/src/TrainSimulation/.classpath
new file mode 100644
index 00000000..923609ae
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/TrainSimulation/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/ws2009/gdi I/exercise/src/TrainSimulation/.project b/ws2009/gdi I/exercise/src/TrainSimulation/.project
new file mode 100644
index 00000000..9bcdda19
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/TrainSimulation/.project
@@ -0,0 +1,19 @@
+
+
+ TrainSimulation
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jem.workbench.JavaEMFNature
+ org.eclipse.jdt.core.javanature
+ org.eclipse.jem.beaninfo.BeanInfoNature
+
+
diff --git a/ws2009/gdi I/exercise/src/TrainSimulation/src/TrainSimulation/IntChar.java b/ws2009/gdi I/exercise/src/TrainSimulation/src/TrainSimulation/IntChar.java
new file mode 100644
index 00000000..ba8fef8d
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/TrainSimulation/src/TrainSimulation/IntChar.java
@@ -0,0 +1,72 @@
+package TrainSimulation;
+
+/**
+ * Class to store Int or Char in one variable.
+ */
+public class IntChar {
+
+ private int i = -1; //intvar
+ private char c = 0; //charvar
+ /**
+ * Char or int switch
+ *
+ * false = char
+ * true = int
+ */
+ private boolean ci = false; //false = char; true = int
+
+ public int getInt() {
+ return i;
+ }
+
+ /**
+ * Sets ci to true.
+ */
+ public void setInt(int i) {
+ this.i = i;
+ setToInt();
+ }
+ public char getChar() {
+ return c;
+ }
+
+ /**
+ * Sets ci to false.
+ */
+ public void setChar(char c) {
+ this.c = c;
+ setToChar();
+ }
+
+ /**
+ * Returns true if ci is set to false!
+ */
+ public boolean isChar()
+ {
+ return !ci;
+ }
+
+ /**
+ * Returns true if ci is true
+ * @return
+ */
+ public boolean isInt()
+ {
+ return ci;
+ }
+
+ /**
+ * Sets ci to false
+ */
+ public void setToChar() {
+ this.ci = false;
+ }
+
+ /**
+ * Sets ci to true
+ */
+ public void setToInt() {
+ this.ci = true;
+ }
+
+}
diff --git a/ws2009/gdi I/exercise/src/TrainSimulation/src/TrainSimulation/TrainDialog.java b/ws2009/gdi I/exercise/src/TrainSimulation/src/TrainSimulation/TrainDialog.java
new file mode 100644
index 00000000..3099ce73
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/TrainSimulation/src/TrainSimulation/TrainDialog.java
@@ -0,0 +1,122 @@
+package TrainSimulation;
+
+import exceptions.InvalidAreaException;
+import exceptions.InvalidCoordinatesException;
+import acm.program.DialogProgram;
+
+public class TrainDialog extends DialogProgram{
+
+ /**
+ * serialVersionUID
+ */
+ private static final long serialVersionUID = -2064310234134016114L;
+
+ /**
+ * Instance of the Train-Simulation
+ */
+ private TrainSimulation sim;
+
+ private static String terminate = new String("Program will terminate now");
+
+ /**
+ * Loads a map and interacts with the user
+ */
+ public void run() {
+ //Example-Array
+ //Attention: This is columnwise
+ char arr[][] = { { '0', '0', '#', '0' }, { '0', '~', '0', '^' }, { '0', '~', '0', '#' },
+ { '0', '^', '0', '0' }, { '0', '0', '#', '~' } };
+
+ //initiate new TrainSimulation object with the given area
+ //catch correct exceptions
+ try
+ {
+ sim = new TrainSimulation(arr);
+ }catch(InvalidAreaException e)
+ {
+ //show-errortype and terminate
+ println(e.getMessage());
+ println(terminate);
+ return;
+ }
+
+ //print Area as String to help user to decide which coordinate is correct
+ println(sim.toString());
+
+ //ask the user for x- and y-coordinates, calculate reachable areas and show the result
+ while(true)
+ {
+ //ask for x-Coordinate -> -1 = exit
+ int x = this.readInt("X-Coordinate of a City");
+ if(x == -1)
+ {
+ println(terminate);
+ return;
+ }
+
+ //ask for y-Coordinate -> -1 = exit
+ int y = this.readInt("Y-Coordinate of a City");
+ if(y == -1)
+ {
+ println(terminate);
+ return;
+ }
+
+ boolean exit = true;
+
+ try
+ {
+ //Test Costs -> Not needed
+ /*int[][] costs = sim.analyzeCosts(x, y);
+
+ String result = "";
+
+ if(costs.length > 0)
+ {
+ for(int i=0; i overview for the user if coordinates were wrong,
+ //else show result of reachable-calculation
+ println(sim.toString());
+
+ if(exit)
+ {
+ //exit if calculation was successfull
+ println(terminate);
+ return;
+ }
+ }
+
+ }
+
+ /**
+ * Main method. This is automatically called by the environment when your
+ * program starts.
+ *
+ * @param args
+ */
+ public static void main(String[] args) {
+ new TrainDialog().start();
+ }
+}
diff --git a/ws2009/gdi I/exercise/src/TrainSimulation/src/TrainSimulation/TrainSimulation.java b/ws2009/gdi I/exercise/src/TrainSimulation/src/TrainSimulation/TrainSimulation.java
new file mode 100644
index 00000000..d3d7345b
--- /dev/null
+++ b/ws2009/gdi I/exercise/src/TrainSimulation/src/TrainSimulation/TrainSimulation.java
@@ -0,0 +1,400 @@
+package TrainSimulation;
+
+import exceptions.InvalidAreaException;
+import exceptions.InvalidCoordinatesException;
+import exceptions.NoObstacleException;
+import exceptions.NoPlainsException;
+import exceptions.NotACityException;
+import exceptions.NotEnoughCitiesException;
+
+public class TrainSimulation {
+
+ //Constants for the Map
+ public final char map_city = '#';
+ public final char map_plain = '0';
+ public final char map_swamp = '~';
+ public final char map_mountain = '^';
+ public final char map_train = '=';
+
+ /**
+ * Variable to store Map-Char-Representation
+ */
+ private char[][] area;
+
+ /**
+ * Constructor sets Map-Char-Representation and throws Exceptions
+ * if its not valid.
+ *
+ * @param area Map-Char-Representation
+ * @throws InvalidAreaException
+ */
+ public TrainSimulation(char[][] area) throws InvalidAreaException
+ {
+ setArea(area); //use setter-method to check given area
+ }
+
+ /**
+ * Flood-Algorithm to replace all Positions which are reachable
+ * from pos (x/y) with map_train.
+ *
+ * A Position is reachable when (x/y) == map_plain || (x/y) == map_city.
+ *
+ * Cities are not replaced.
+ *
+ * Modifies this.area
+ *
+ * @param x X-Coordinate
+ * @param y >-Coordinate
+ */
+ private void floodArrayWithTrain(int x, int y)
+ {
+ //check if position is valid
+ if(areCoordinatesValid(x, y))
+ {
+ //skip/anchor -> area not reachable
+ if(area[x][y] != map_plain && area[x][y] != map_city)
+ {
+ return;
+ }
+
+ //replace only map_plain not map_city
+ if(area[x][y] == map_plain)
+ {
+ area[x][y] = map_train;
+ }
+
+ //flood-algorithm-recursive call
+ floodArrayWithTrain(x,y+1);
+ floodArrayWithTrain(x,y-1);
+ floodArrayWithTrain(x+1,y);
+ floodArrayWithTrain(x-1,y);
+ }
+ }
+
+ private boolean areCoordinatesValid(IntChar[][] array, int x, int y)
+ {
+ if( x < 0 ||
+ y < 0 ||
+ array.length <= x ||
+ array[x].length <= y)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean areCoordinatesValid(char[][] array, int x, int y)
+ {
+ if( x < 0 ||
+ y < 0 ||
+ array.length <= x ||
+ array[x].length <= y)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean areCoordinatesValid(int x, int y)
+ {
+ return areCoordinatesValid(area, x, y);
+ }
+
+ /**
+ * Replaces all map_plain in this.area
+ * if field is reachable
+ *
+ * Coordinate have to point to a city.
+ *
+ * @param x X-Coordinate
+ * @param y Y-Coordinate
+ * @throws InvalidCoordinatesException
+ */
+ public void reachable(int x, int y) throws InvalidCoordinatesException
+ {
+ //check if coordinates are valid
+ if(!areCoordinatesValid(x, y))
+ {
+ throw new InvalidCoordinatesException("Error: Coordinates are not valid");
+ }
+
+ //check if position is a city
+ if(area[x][y] != map_city)
+ {
+ throw new NotACityException();
+ }
+
+ //flood-algorithm
+ floodArrayWithTrain(x,y);
+ }
+
+ /**
+ * Floods given are with Costs-parameters; only replaces
+ * reachable fields.
+ *
+ * @param array Array with chars/costs-values
+ * @param x X-Coordinate
+ * @param y Y-Coordinate
+ * @param value Current costs for the field, if its reachable
+ * @return new Array
+ */
+ private IntChar[][] floodArrayWithCosts(IntChar[][] array, int x, int y, int value)
+ {
+ //check Coordinates are valid
+ if(areCoordinatesValid(array,x, y)) //recursion-anchor
+ {
+ //is Coordinate an integer and value of the field is > current costs
+ // -> replace with current costs
+ if(array[x][y].isInt() && array[x][y].getInt() > value)
+ {
+ array[x][y].setInt(value);
+ } else
+ {
+ //is Coordinate a char and value of the field is map_plain or map_city
+ // -> set current costs @ current field
+ if( array[x][y].isChar() &&
+ (array[x][y].getChar() == map_plain ||
+ array[x][y].getChar() == map_city)
+ )
+ {
+ array[x][y].setInt(value);
+ } else
+ {
+ return array; //recursion-anchor
+ }
+ }
+
+ //Flood-Algorithm
+ array = floodArrayWithCosts(array,x,y+1,value+1);
+ array = floodArrayWithCosts(array,x,y-1,value+1);
+ array = floodArrayWithCosts(array,x+1,y,value+1);
+ array = floodArrayWithCosts(array,x-1,y,value+1);
+ }
+
+ return array;
+ }
+
+ /**
+ * Returns a integer-field(2-dim) with "costs" of the
+ * all reachable fields from pos (x/y)
+ *
+ * @param x X-Coordinate
+ * @param y Y-Coordinate
+ * @return integer-field(2-dim)
+ * @throws InvalidCoordinatesException
+ */
+ public int[][] analyzeCosts(int x, int y) throws InvalidCoordinatesException
+ {
+ //Check if array is ok
+ if(!isAreaSizeOk())
+ {
+ //should not happen, but to be sure
+ throw new InvalidCoordinatesException("Error: Area-Array was not ok");
+ }
+
+ //Check Coordinates
+ if(!areCoordinatesValid(x, y))
+ {
+ throw new InvalidCoordinatesException("Error: Coordinates are not valid");
+ }
+
+ //check if position is a city
+ if(area[x][y] != map_city)
+ {
+ throw new NotACityException();
+ }
+
+ //New array to operate on
+ IntChar[][] tarea = new IntChar[area.length][area[0].length];
+ for(int i=0; i created object locally
+ int[][] result = new int[tarea.length][tarea[0].length];
+
+ //Convert IntChar[][] -> int[][]
+ for(int i=0;i set to -1
+ result[i][j] = -1;
+ }
+ }
+ }
+
+ //return int[][]
+ return result;
+ }
+
+ /**
+ * @return String Returns a String-Representation of the current this.area property.
+ */
+ public String toString()
+ {
+ //result variable
+ String result = "";
+
+ //check if area has a length
+ if(area.length > 0)
+ {
+ for(int i=0; i add return
+ result += "\n";
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns true if element is at least count-times present in this.area. else false
+ *
+ * @param element Element to look for
+ * @param count How many times should the Element appear before returning true
+ * @return All required Elements found ? true : false
+ */
+ private boolean hasElement(char element, int count)
+ {
+ for(int i=0; i true
+ }
+ }
+ }
+ }
+
+ return false; //not all found -> false
+ }
+
+ /**
+ * @return returns true if this.area has two or more cities else false
+ */
+ private boolean hasTwoCities()
+ {
+ return hasElement(map_city,2);
+ }
+
+ /**
+ * @return returns true if this.area has one or more plains else false
+ */
+ private boolean hasPlainsElement()
+ {
+ return hasElement(map_plain,1);
+ }
+
+ /**
+ * @return returns true if this.area has one or more terrainObstacle else false
+ *
+ * TerrainObstacle = map_mountain, map_swamp
+ */
+ private boolean hasTerrainObstacle()
+ {
+ if(hasElement(map_swamp,1))
+ {
+ return true;
+ }
+
+ return hasElement(map_mountain,1);
+ }
+
+ /**
+ * Checks size of the area, returns true if its ok, else false
+ */
+ private boolean isAreaSizeOk()
+ {
+ if(area.length == 0)
+ {
+ return false;
+ }
+
+ int length = area[0].length;
+
+ for(int i=1; i