Repository: Dungeon-CampusMinden/Dungeon
Pull request #1961: Blockly: add choose a pathfinding algo
Author: login: Tobi511
Labels: name: blockly
Created: 2025-05-07T09:52:38Z | Merged: 2025-05-14T09:06:37Z


Ich habe im `PathfindingStarter` eine Methode `switchToAlgorithm` hinzugefügt, mit der einer der vorhandenen Pathfinding-Algorithmen ausgewählt werden kann.
Außerdem werden die Keybinds in der `onLevelLoad` Methode als Callback dem PlayerComponent hinzugefügt.

In der `KeyboardConfig` sind die entsprechenden Tastenkombinationen hinterlegt. Aktuell `J`, `K`, und `L`, um nicht mit den Keys für das LevelEditorSystem übereinzustimmen.

Zusätzlich wurde die Klasse `SuSPathFinding` eingeführt. Hier können die Schüler:innen ihren eigenen Pathfinding-Algorithmus implementieren.

Closes #1935.
#1862 ist damit meiner Meinung nach ebenfalls erledigt.

Linked issue #1935: Pathfinding Algo auswählen
Aktuell haben wir nur die Logik Pathfinding umzusetzen und darzustellen. Aber noch nicht für das "Starten" bzw. das Auswählen eines Suchalgorithms.

Idee:
1. Im Levelhandler wird das festgelegt
2. Mehrere Keybinds (Eins für jeden Algo)
3. Statisch in der Starter
Linked issue comments: user: login: AMatutat
created_at: 2025-05-05T09:53:28Z
body: Als einfache/erste Solutuon: 


Irgendwie 3 mit 2 gemischt

Spiel start => Kein Alog ist ausgewählt

Titlebar zeigt dann an welche ausgewählt ist.


Ich drücke:
1. Tiefensuche
2. Breitensuche
3. SuS Implementierung (da muss dann noch geprüft werden, ob die schon gebaut ist) (`OperationNotSupportedException`)

Und dann sind erst die Keys fürs durchführen freigeschaltet (+ 1,2,3 ist deaktiviert). 


author_association: CONTRIBUTOR

Diff:
diff --git a/blockly/build.gradle b/blockly/build.gradle
index 0e8876e638..6dc86a311c 100644
--- a/blockly/build.gradle
+++ b/blockly/build.gradle
@@ -42,6 +42,11 @@ tasks.register('runBlockly', JavaExec) {
     classpath = sourceSets.main.runtimeClasspath
 }
 
+tasks.register('runPathfinder', JavaExec) {
+    mainClass = 'starter.PathfinderStarter'
+    classpath = sourceSets.main.runtimeClasspath
+}
+
 tasks.register('runPathFindingComparison', JavaExec) {
     mainClass = 'starter.ComparePathfindingStarter'
     classpath = sourceSets.main.runtimeClasspath
diff --git a/blockly/src/client/KeyboardConfig.java b/blockly/src/client/KeyboardConfig.java
index 66d5b3c303..64388f4af3 100644
--- a/blockly/src/client/KeyboardConfig.java
+++ b/blockly/src/client/KeyboardConfig.java
@@ -22,4 +22,22 @@ public class KeyboardConfig {
       new core.configuration.ConfigKey<>(
           new String[] {"pathfinding", "start_moving_pathfinding"},
           new core.configuration.values.ConfigIntValue(Input.Keys.SPACE));
+
+  /** Switch to DFS algorithm. */
+  public static final core.configuration.ConfigKey<Integer> SELECT_DFS =
+      new core.configuration.ConfigKey<>(
+          new String[] {"pathfinding", "select_dfs"},
+          new core.configuration.values.ConfigIntValue(Input.Keys.J));
+
+  /** Switch to BFS algorithm. */
+  public static final core.configuration.ConfigKey<Integer> SELECT_BFS =
+      new core.configuration.ConfigKey<>(
+          new String[] {"pathfinding", "select_bfs"},
+          new core.configuration.values.ConfigIntValue(Input.Keys.K));
+
+  /** Switch to the algorithm that the students will implement. */
+  public static final core.configuration.ConfigKey<Integer> SELECT_SUS_ALGO =
+      new core.configuration.ConfigKey<>(
+          new String[] {"pathfinding", "select_sus_algo"},
+          new core.configuration.values.ConfigIntValue(Input.Keys.L));
 }
diff --git a/blockly/src/starter/PathfinderStarter.java b/blockly/src/starter/PathfinderStarter.java
index 4ae13c7457..40643bf59a 100644
--- a/blockly/src/starter/PathfinderStarter.java
+++ b/blockly/src/starter/PathfinderStarter.java
@@ -1,26 +1,35 @@
 package starter;
 
+import client.KeyboardConfig;
 import contrib.entities.HeroFactory;
 import contrib.level.DevDungeonLoader;
 import contrib.systems.*;
 import core.Entity;
 import core.Game;
 import core.components.CameraComponent;
+import core.components.PlayerComponent;
+import core.level.utils.Coordinate;
 import core.systems.LevelSystem;
-import core.utils.MissingHeroException;
 import core.utils.Tuple;
+import core.utils.components.MissingComponentException;
 import core.utils.components.path.SimpleIPath;
 import java.io.IOException;
 import java.util.logging.Level;
+import java.util.logging.Logger;
 import level.AiMazeLevel;
 import systems.MazeEditorSystem;
 import systems.PathfindingSystem;
 import utils.CheckPatternPainter;
+import utils.pathfinding.BFSPathFinding;
 import utils.pathfinding.DFSPathFinding;
+import utils.pathfinding.PathfindingLogic;
+import utils.pathfinding.SusPathFinding;
 
 /** This class starts the dungeon Ai level to visualize the DFS and BFS. */
 public class PathfinderStarter {
+  private static final Logger LOGGER = Logger.getLogger(PathfinderStarter.class.getName());
   private static final boolean DRAW_CHECKER_PATTERN = true;
+  private static Tuple<PathfindingLogic, PathfindingLogic> pathfindings = Tuple.of(null, null);
 
   /**
    * Setup and run the game. Also start the server that is listening to the requests from blockly
@@ -65,16 +74,44 @@ private static void onLevelLoad() {
           if (DRAW_CHECKER_PATTERN)
             CheckPatternPainter.paintCheckerPattern(Game.currentLevel().layout());
 
-          Game.system(
-              PathfindingSystem.class,
-              (pfs) -> {
-                pfs.autoStep(true);
-                pfs.updatePathfindingAlgorithm(
-                    Tuple.of(
-                        new DFSPathFinding(
-                            Game.currentLevel().startTile().coordinate(),
-                            Game.currentLevel().endTile().coordinate()),
-                        Game.hero().orElseThrow(MissingHeroException::new)));
+          Coordinate startCoords = Game.currentLevel().startTile().coordinate();
+          Coordinate endTileCoords = Game.currentLevel().endTile().coordinate();
+          PlayerComponent pc =
+              Game.hero()
+                  .get()
+                  .fetch(PlayerComponent.class)
+                  .orElseThrow(
+                      () ->
+                          MissingComponentException.build(
+                              Game.hero().get(), PlayerComponent.class));
+          pc.registerCallback(
+              KeyboardConfig.SELECT_DFS.value(),
+              entity -> {
+                if (pathfindings.a() == null && pathfindings.b() == null) {
+                  pathfindings = Tuple.of(new DFSPathFinding(startCoords, endTileCoords), null);
+                  switchToAlgorithm(pathfindings.a(), entity);
+                }
+              });
+          pc.registerCallback(
+              KeyboardConfig.SELECT_BFS.value(),
+              entity -> {
+                if (pathfindings.a() == null && pathfindings.b() == null) {
+                  pathfindings = Tuple.of(new BFSPathFinding(startCoords, endTileCoords), null);
+                  switchToAlgorithm(pathfindings.a(), entity);
+                }
+              });
+          pc.registerCallback(
+              KeyboardConfig.SELECT_SUS_ALGO.value(),
+              entity -> {
+                if (pathfindings.a() == null && pathfindings.b() == null) {
+                  try {
+                    pathfindings = Tuple.of(null, new SusPathFinding(startCoords, endTileCoords));
+                    switchToAlgorithm(pathfindings.b(), entity);
+                  } catch (UnsupportedOperationException e) {
+                    LOGGER.info(e.getMessage());
+                    pathfindings = Tuple.of(null, null);
+                  }
+                }
               });
         });
   }
@@ -101,7 +138,7 @@ private static void createSystems() {
    * Creates and adds a new hero entity to the game.
    *
    * <p>The new hero is generated using the {@link HeroFactory} and the {@link CameraComponent} of
-   * the hero is removed.
+   * the hero is removed. And movement callbacks are removed.
    *
    * @throws RuntimeException if an {@link IOException} occurs during hero creation
    */
@@ -110,5 +147,27 @@ public static void createHero() throws IOException {
     hero = HeroFactory.newHero();
     hero.remove(CameraComponent.class);
     Game.add(hero);
+
+    hero.remove(PlayerComponent.class);
+    hero.add(new PlayerComponent());
+  }
+
+  /**
+   * Changes the pathfinding algorithm used in the game to the specified one.
+   *
+   * <p>This method updates the active pathfinding algorithm in the {@link PathfindingSystem} and
+   * updates the game window title to reflect the newly selected algorithm.
+   *
+   * @param algorithm The new pathfinding algorithm to be used (e.g., DFS, BFS, SuS).
+   * @param hero The entity using the algorithm
+   */
+  private static void switchToAlgorithm(PathfindingLogic algorithm, Entity hero) {
+    Game.system(
+        PathfindingSystem.class,
+        pfs -> {
+          pfs.autoStep(true);
+          pfs.updatePathfindingAlgorithm(Tuple.of(algorithm, hero));
+        });
+    Game.updateWindowTitle("Blockly KI-Dungeon – " + algorithm.getClass().getSimpleName());
   }
 }
diff --git a/blockly/src/utils/pathfinding/SusPathFinding.java b/blockly/src/utils/pathfinding/SusPathFinding.java
new file mode 100644
index 0000000000..4612f71848
--- /dev/null
+++ b/blockly/src/utils/pathfinding/SusPathFinding.java
@@ -0,0 +1,57 @@
+package utils.pathfinding;
+
+import core.level.utils.Coordinate;
+
+/**
+ * {@code SusPathFinding} is a customizable pathfinding class intended for student implementation.
+ *
+ * <p>It extends {@link PathfindingLogic} and allows learners to experiment with different search
+ * strategies by choosing between a {@link BFSQueue} (FIFO) or {@link DFSStack} (LIFO) as the
+ * frontier data structure.
+ *
+ * <p>This class serves as a template for recreating common pathfinding algorithms such as BFS or
+ * DFS.
+ *
+ * <p>Students are expected to:
+ *
+ * <ul>
+ *   <li>Choose the desired frontier data structure in the constructor.
+ *   <li>Implement the {@link #performSearch()} method with their own algorithm.
+ * </ul>
+ *
+ * @see PathfindingLogic
+ * @see systems.PathfindingSystem
+ * @see BFSQueue
+ * @see DFSStack
+ */
+public class SusPathFinding extends PathfindingLogic {
+  /**
+   * Constructs a new {@code SusPathFinding} instance.
+   *
+   * <p>This constructor initializes the pathfinding algorithm with a chosen data structure for the
+   * frontier set. Students should select either a {@link BFSQueue} (for breadth-first search
+   * behavior) or a {@link DFSStack} (for depth-first search).
+   *
+   * <p>TODO: Replace {@code BFSQueue} with the desired data structure (e.g., {@code DFSStack}).
+   *
+   * @param start The starting coordinate for the pathfinding search.
+   * @param end The ending coordinate for the pathfinding search.
+   */
+  public SusPathFinding(Coordinate start, Coordinate end) {
+    super(start, end, new BFSQueue()); // TODO: Replace with DFSStack if needed
+  }
+
+  /**
+   * Performs the pathfinding search.
+   *
+   * <p>This method must be implemented by students to define their own search logic.
+   *
+   * <p>TODO: Implement the pathfinding logic.
+   *
+   * @throws UnsupportedOperationException if not yet implemented
+   */
+  @Override
+  public void performSearch() {
+    throw new UnsupportedOperationException("Bitte eigenes Pathfinding implementieren.");
+  }
+}
diff --git a/game/src/core/Game.java b/game/src/core/Game.java
index ddecc7146b..595465e2aa 100644
--- a/game/src/core/Game.java
+++ b/game/src/core/Game.java
@@ -140,6 +140,15 @@ public static void windowTitle(final String windowTitle) {
     PreRunConfiguration.windowTitle(windowTitle);
   }
 
+  /**
+   * Updates the window title.
+   *
+   * @param newTitle The new window title.
+   */
+  public static void updateWindowTitle(String newTitle) {
+    Gdx.graphics.setTitle(newTitle);
+  }
+
   /**
    * Gets the path to the game logo.
    *


Reviews:
user: login: Flamtky
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-07T10:29:12Z
user: login: Tobi511
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T11:01:41Z
user: login: AMatutat
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T11:33:24Z
user: login: AMatutat
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T11:35:20Z
user: login: Tobi511
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T12:47:31Z
user: login: Tobi511
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T13:18:10Z
user: login: Tobi511
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T13:20:18Z
user: login: Flamtky
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-07T23:25:10Z
user: login: AMatutat
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T04:57:21Z
user: login: AMatutat
body: - player hat noch controll (WASD)
- wie start ich das denn? Also das er losläuft und so?
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T12:43:17Z
user: login: Flamtky
body: Bitte auch eine Gradle Task für den Starter ergänzen. Plus Merge Konflikte beheben
state: DISMISSED
author_association: MEMBER
submitted_at: 2025-05-12T15:11:24Z
user: login: AMatutat
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T09:05:39Z

Review comments:
diff_hunk: @@ -108,4 +106,55 @@ public static void createHero() throws IOException {
     hero.remove(CameraComponent.class);
     Game.add(hero);
   }
+
+  /**
+   * Checks if any key for selecting a pathfinding algorithm has been pressed.
+   *
+   * <p>This method listens for specific key presses for DFS, BFS, and other pathfinding algorithms.
+   * It switches the current algorithm accordingly and prevents further input until a new algorithm
+   * is selected. If the "SuS Pathfinding" algorithm is selected but not implemented, an {@link
+   * OperationNotSupportedException} is thrown to indicate the feature is not available.
+   */
+  private static void checkForAlgorithmSwitch() {
+    try {
+      Coordinate startCoords = Game.currentLevel().startTile().coordinate();
+      Coordinate endTileCoords = Game.currentLevel().endTile().coordinate();
+      if (noPathfindingSelected && Gdx.input.isKeyJustPressed(KeyboardConfig.SELECT_DFS.value())) {
+        switchToAlgorithm(new DFSPathFinding(startCoords, endTileCoords), "DFS-Pathfinding");
+      } else if (noPathfindingSelected
+          && Gdx.input.isKeyJustPressed(KeyboardConfig.SELECT_BFS.value())) {
+        switchToAlgorithm(new BFSPathFinding(startCoords, endTileCoords), "BFS-Pathfinding");
+      } else if (noPathfindingSelected
+          && Gdx.input.isKeyJustPressed(KeyboardConfig.SELECT_SUS_ALGO.value())) {
+        if (noSuSAlgorithmAvailable) {
+          throw new OperationNotSupportedException(
+              "The SuS Pathfinding algorithm is not implemented yet.");
+        }
+        // switchToAlgorithm(new SuSPathFinding(startCoords, endTileCoords), "SuS-Pathfinding");
+      }
+    } catch (OperationNotSupportedException e) {
+      System.err.println(e.getMessage());
+    }
+  }
+
+  /**
+   * Changes the pathfinding algorithm used in the game to the specified one.
+   *
+   * <p>This method updates the active pathfinding algorithm in the {@link PathfindingSystem} and
+   * updates the game window title to reflect the newly selected algorithm.
+   *
+   * @param algorithm The new pathfinding algorithm to be used (e.g., DFS, BFS, SuS).
+   * @param name The name of the algorithm to display in the window title for the player's
+   *     reference.
+   */
+  private static void switchToAlgorithm(utils.pathfinding.PathfindingLogic algorithm, String name) {
+    Game.system(
+        PathfindingSystem.class,
+        pfs -> {
+          pfs.autoStep(true);
+          pfs.updatePathfindingAlgorithm(algorithm);
+        });
+    Gdx.graphics.setTitle("Blockly KI-Dungeon – " + name);
path: blockly/src/starter/PathfinderStarter.java
user: login: Flamtky
body: ```suggestion
    Game.windowTitle("Blockly KI-Dungeon – " + name);
```
ist glaub ich sinnvoller, bevor wir mehr Abhängigkeiten von gdx hinzufügen
created_at: 2025-05-07T10:20:20Z
author_association: MEMBER
diff_hunk: @@ -35,6 +41,8 @@ public static void main(String[] args) throws IOException {
     configGame();
     // Set up components and level
     onSetup();
+    // be able to choose between the available pathfinding algorithms
+    Game.userOnFrame(PathfinderStarter::checkForAlgorithmSwitch);
path: blockly/src/starter/PathfinderStarter.java
user: login: Flamtky
body: Mmm finde ich irgendwie blöd das mir nicht das `PlayerSystem` verwenden. Ich weiß dass der Spieler wieder die Kontrolle vom Helden dann bekommt, aber ich glaub wir können auch einfach die Callbacks clearen.
Kontext: Per `PlayerSystem` kann man callbacks für key presses hinzufügen. Siehe dafür `Herofactory`
created_at: 2025-05-07T10:22:41Z
author_association: MEMBER
diff_hunk: @@ -108,4 +106,55 @@ public static void createHero() throws IOException {
     hero.remove(CameraComponent.class);
     Game.add(hero);
   }
+
+  /**
+   * Checks if any key for selecting a pathfinding algorithm has been pressed.
+   *
+   * <p>This method listens for specific key presses for DFS, BFS, and other pathfinding algorithms.
+   * It switches the current algorithm accordingly and prevents further input until a new algorithm
+   * is selected. If the "SuS Pathfinding" algorithm is selected but not implemented, an {@link
+   * OperationNotSupportedException} is thrown to indicate the feature is not available.
+   */
+  private static void checkForAlgorithmSwitch() {
+    try {
+      Coordinate startCoords = Game.currentLevel().startTile().coordinate();
+      Coordinate endTileCoords = Game.currentLevel().endTile().coordinate();
+      if (noPathfindingSelected && Gdx.input.isKeyJustPressed(KeyboardConfig.SELECT_DFS.value())) {
+        switchToAlgorithm(new DFSPathFinding(startCoords, endTileCoords), "DFS-Pathfinding");
+      } else if (noPathfindingSelected
+          && Gdx.input.isKeyJustPressed(KeyboardConfig.SELECT_BFS.value())) {
+        switchToAlgorithm(new BFSPathFinding(startCoords, endTileCoords), "BFS-Pathfinding");
+      } else if (noPathfindingSelected
+          && Gdx.input.isKeyJustPressed(KeyboardConfig.SELECT_SUS_ALGO.value())) {
+        if (noSuSAlgorithmAvailable) {
+          throw new OperationNotSupportedException(
+              "The SuS Pathfinding algorithm is not implemented yet.");
path: blockly/src/starter/PathfinderStarter.java
user: login: Flamtky
body: Ist das wirklich ein Fehler? Oder vlt nur ein Hinweis?
created_at: 2025-05-07T10:24:59Z
author_association: MEMBER
diff_hunk: @@ -108,4 +106,55 @@ public static void createHero() throws IOException {
     hero.remove(CameraComponent.class);
     Game.add(hero);
   }
+
+  /**
+   * Checks if any key for selecting a pathfinding algorithm has been pressed.
+   *
+   * <p>This method listens for specific key presses for DFS, BFS, and other pathfinding algorithms.
+   * It switches the current algorithm accordingly and prevents further input until a new algorithm
+   * is selected. If the "SuS Pathfinding" algorithm is selected but not implemented, an {@link
+   * OperationNotSupportedException} is thrown to indicate the feature is not available.
+   */
+  private static void checkForAlgorithmSwitch() {
+    try {
+      Coordinate startCoords = Game.currentLevel().startTile().coordinate();
+      Coordinate endTileCoords = Game.currentLevel().endTile().coordinate();
+      if (noPathfindingSelected && Gdx.input.isKeyJustPressed(KeyboardConfig.SELECT_DFS.value())) {
+        switchToAlgorithm(new DFSPathFinding(startCoords, endTileCoords), "DFS-Pathfinding");
+      } else if (noPathfindingSelected
+          && Gdx.input.isKeyJustPressed(KeyboardConfig.SELECT_BFS.value())) {
+        switchToAlgorithm(new BFSPathFinding(startCoords, endTileCoords), "BFS-Pathfinding");
+      } else if (noPathfindingSelected
+          && Gdx.input.isKeyJustPressed(KeyboardConfig.SELECT_SUS_ALGO.value())) {
+        if (noSuSAlgorithmAvailable) {
+          throw new OperationNotSupportedException(
+              "The SuS Pathfinding algorithm is not implemented yet.");
+        }
+        // switchToAlgorithm(new SuSPathFinding(startCoords, endTileCoords), "SuS-Pathfinding");
+      }
+    } catch (OperationNotSupportedException e) {
+      System.err.println(e.getMessage());
path: blockly/src/starter/PathfinderStarter.java
user: login: Flamtky
body: Hier bitte den Logger verwenden
created_at: 2025-05-07T10:25:08Z
author_association: MEMBER
diff_hunk: @@ -1,25 +1,31 @@
 package starter;
 
+import client.KeyboardConfig;
+import com.badlogic.gdx.Gdx;
 import contrib.entities.HeroFactory;
 import contrib.level.DevDungeonLoader;
 import contrib.systems.*;
-import contrib.systems.LevelEditorSystem;
 import core.Entity;
 import core.Game;
 import core.components.CameraComponent;
+import core.level.utils.Coordinate;
 import core.systems.LevelSystem;
 import core.utils.Tuple;
 import core.utils.components.path.SimpleIPath;
 import java.io.IOException;
 import java.util.logging.Level;
+import javax.naming.OperationNotSupportedException;
 import level.AiMazeLevel;
 import systems.PathfindingSystem;
 import utils.CheckPatternPainter;
+import utils.pathfinding.BFSPathFinding;
 import utils.pathfinding.DFSPathFinding;
 
 /** This class starts the dungeon Ai level to visualize the DFS and BFS. */
 public class PathfinderStarter {
   private static final boolean DRAW_CHECKER_PATTERN = true;
+  private static boolean noPathfindingSelected = true;
+  private static final boolean noSuSAlgorithmAvailable = true;
path: blockly/src/starter/PathfinderStarter.java
user: login: Flamtky
body: Vlt statt 2 booleans einfach ein Tuple speichern mit 2x PathfindingLogic?
```suggestion
  // Tuple<Original, SuSAlgo>
  private static Tuple<PathFindingLogic, PathFindingLogic> pathfindigs = Tuple.of();
```
created_at: 2025-05-07T10:29:04Z
author_association: MEMBER
diff_hunk: @@ -108,4 +106,55 @@ public static void createHero() throws IOException {
     hero.remove(CameraComponent.class);
     Game.add(hero);
   }
+
+  /**
+   * Checks if any key for selecting a pathfinding algorithm has been pressed.
+   *
+   * <p>This method listens for specific key presses for DFS, BFS, and other pathfinding algorithms.
+   * It switches the current algorithm accordingly and prevents further input until a new algorithm
+   * is selected. If the "SuS Pathfinding" algorithm is selected but not implemented, an {@link
+   * OperationNotSupportedException} is thrown to indicate the feature is not available.
+   */
+  private static void checkForAlgorithmSwitch() {
+    try {
+      Coordinate startCoords = Game.currentLevel().startTile().coordinate();
+      Coordinate endTileCoords = Game.currentLevel().endTile().coordinate();
+      if (noPathfindingSelected && Gdx.input.isKeyJustPressed(KeyboardConfig.SELECT_DFS.value())) {
+        switchToAlgorithm(new DFSPathFinding(startCoords, endTileCoords), "DFS-Pathfinding");
+      } else if (noPathfindingSelected
+          && Gdx.input.isKeyJustPressed(KeyboardConfig.SELECT_BFS.value())) {
+        switchToAlgorithm(new BFSPathFinding(startCoords, endTileCoords), "BFS-Pathfinding");
+      } else if (noPathfindingSelected
+          && Gdx.input.isKeyJustPressed(KeyboardConfig.SELECT_SUS_ALGO.value())) {
+        if (noSuSAlgorithmAvailable) {
+          throw new OperationNotSupportedException(
+              "The SuS Pathfinding algorithm is not implemented yet.");
+        }
+        // switchToAlgorithm(new SuSPathFinding(startCoords, endTileCoords), "SuS-Pathfinding");
+      }
+    } catch (OperationNotSupportedException e) {
+      System.err.println(e.getMessage());
+    }
+  }
+
+  /**
+   * Changes the pathfinding algorithm used in the game to the specified one.
+   *
+   * <p>This method updates the active pathfinding algorithm in the {@link PathfindingSystem} and
+   * updates the game window title to reflect the newly selected algorithm.
+   *
+   * @param algorithm The new pathfinding algorithm to be used (e.g., DFS, BFS, SuS).
+   * @param name The name of the algorithm to display in the window title for the player's
+   *     reference.
+   */
+  private static void switchToAlgorithm(utils.pathfinding.PathfindingLogic algorithm, String name) {
+    Game.system(
+        PathfindingSystem.class,
+        pfs -> {
+          pfs.autoStep(true);
+          pfs.updatePathfindingAlgorithm(algorithm);
+        });
+    Gdx.graphics.setTitle("Blockly KI-Dungeon – " + name);
path: blockly/src/starter/PathfinderStarter.java
user: login: Tobi511
body: Das wollte ich eigentlich auch verwenden, aber das funktioniert leider nicht. Der Titel aktualisiert sich damit nicht.
created_at: 2025-05-07T11:01:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -108,4 +106,55 @@ public static void createHero() throws IOException {
     hero.remove(CameraComponent.class);
     Game.add(hero);
   }
+
+  /**
+   * Checks if any key for selecting a pathfinding algorithm has been pressed.
+   *
+   * <p>This method listens for specific key presses for DFS, BFS, and other pathfinding algorithms.
+   * It switches the current algorithm accordingly and prevents further input until a new algorithm
+   * is selected. If the "SuS Pathfinding" algorithm is selected but not implemented, an {@link
+   * OperationNotSupportedException} is thrown to indicate the feature is not available.
+   */
+  private static void checkForAlgorithmSwitch() {
+    try {
+      Coordinate startCoords = Game.currentLevel().startTile().coordinate();
+      Coordinate endTileCoords = Game.currentLevel().endTile().coordinate();
+      if (noPathfindingSelected && Gdx.input.isKeyJustPressed(KeyboardConfig.SELECT_DFS.value())) {
+        switchToAlgorithm(new DFSPathFinding(startCoords, endTileCoords), "DFS-Pathfinding");
+      } else if (noPathfindingSelected
+          && Gdx.input.isKeyJustPressed(KeyboardConfig.SELECT_BFS.value())) {
+        switchToAlgorithm(new BFSPathFinding(startCoords, endTileCoords), "BFS-Pathfinding");
+      } else if (noPathfindingSelected
+          && Gdx.input.isKeyJustPressed(KeyboardConfig.SELECT_SUS_ALGO.value())) {
+        if (noSuSAlgorithmAvailable) {
+          throw new OperationNotSupportedException(
+              "The SuS Pathfinding algorithm is not implemented yet.");
+        }
+        // switchToAlgorithm(new SuSPathFinding(startCoords, endTileCoords), "SuS-Pathfinding");
+      }
+    } catch (OperationNotSupportedException e) {
+      System.err.println(e.getMessage());
+    }
+  }
+
+  /**
+   * Changes the pathfinding algorithm used in the game to the specified one.
+   *
+   * <p>This method updates the active pathfinding algorithm in the {@link PathfindingSystem} and
+   * updates the game window title to reflect the newly selected algorithm.
+   *
+   * @param algorithm The new pathfinding algorithm to be used (e.g., DFS, BFS, SuS).
+   * @param name The name of the algorithm to display in the window title for the player's
+   *     reference.
+   */
+  private static void switchToAlgorithm(utils.pathfinding.PathfindingLogic algorithm, String name) {
+    Game.system(
+        PathfindingSystem.class,
+        pfs -> {
+          pfs.autoStep(true);
+          pfs.updatePathfindingAlgorithm(algorithm);
+        });
+    Gdx.graphics.setTitle("Blockly KI-Dungeon – " + name);
path: blockly/src/starter/PathfinderStarter.java
user: login: AMatutat
body: > Das wollte ich eigentlich auch verwenden, aber das funktioniert leider nicht. Der Titel aktualisiert sich damit nicht.

Hmm ja, das setzt das nur für die PreRunConfig.

Aber erstell mal in game/core/Game eine funktion, die genau das macht.
Also 

```
public static void updateWindowTitle(String newTitle)
  Gdx.graphics.setTitle(newTitle);
 ```
 
created_at: 2025-05-07T11:33:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -35,6 +41,8 @@ public static void main(String[] args) throws IOException {
     configGame();
     // Set up components and level
     onSetup();
+    // be able to choose between the available pathfinding algorithms
+    Game.userOnFrame(PathfinderStarter::checkForAlgorithmSwitch);
path: blockly/src/starter/PathfinderStarter.java
user: login: AMatutat
body: Versteh wo du herkommst, diese Variante ist natürlich ganz nett, weil sie theoretisch ohne Player Funktioniert.

Ist mir beides recht. 
created_at: 2025-05-07T11:35:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,25 +1,31 @@
 package starter;
 
+import client.KeyboardConfig;
+import com.badlogic.gdx.Gdx;
 import contrib.entities.HeroFactory;
 import contrib.level.DevDungeonLoader;
 import contrib.systems.*;
-import contrib.systems.LevelEditorSystem;
 import core.Entity;
 import core.Game;
 import core.components.CameraComponent;
+import core.level.utils.Coordinate;
 import core.systems.LevelSystem;
 import core.utils.Tuple;
 import core.utils.components.path.SimpleIPath;
 import java.io.IOException;
 import java.util.logging.Level;
+import javax.naming.OperationNotSupportedException;
 import level.AiMazeLevel;
 import systems.PathfindingSystem;
 import utils.CheckPatternPainter;
+import utils.pathfinding.BFSPathFinding;
 import utils.pathfinding.DFSPathFinding;
 
 /** This class starts the dungeon Ai level to visualize the DFS and BFS. */
 public class PathfinderStarter {
   private static final boolean DRAW_CHECKER_PATTERN = true;
+  private static boolean noPathfindingSelected = true;
+  private static final boolean noSuSAlgorithmAvailable = true;
path: blockly/src/starter/PathfinderStarter.java
user: login: Tobi511
body: Also in dem Tupel setze ich dann den jeweils ausgewählten Algorithmus und kann damit überprüfen ob schon einer ausgewählt wurde. Aber wie kann ich dann vorher prüfen ob der zu setzende Algo (eigene implementierung der Sus) schon existiert? dafür hatte ich den `noSusAlgorithmAvailable` erstmal als festen bool und den würde ich ja weiterhin brauchen? Wo könnte ich mir die Info her holen, ob der implementiert wurde?
created_at: 2025-05-07T12:47:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -35,6 +41,8 @@ public static void main(String[] args) throws IOException {
     configGame();
     // Set up components and level
     onSetup();
+    // be able to choose between the available pathfinding algorithms
+    Game.userOnFrame(PathfinderStarter::checkForAlgorithmSwitch);
path: blockly/src/starter/PathfinderStarter.java
user: login: Tobi511
body: War eben schon dabei es umzubauen und habs dann auch gemacht.
created_at: 2025-05-07T13:18:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -108,4 +106,55 @@ public static void createHero() throws IOException {
     hero.remove(CameraComponent.class);
     Game.add(hero);
   }
+
+  /**
+   * Checks if any key for selecting a pathfinding algorithm has been pressed.
+   *
+   * <p>This method listens for specific key presses for DFS, BFS, and other pathfinding algorithms.
+   * It switches the current algorithm accordingly and prevents further input until a new algorithm
+   * is selected. If the "SuS Pathfinding" algorithm is selected but not implemented, an {@link
+   * OperationNotSupportedException} is thrown to indicate the feature is not available.
+   */
+  private static void checkForAlgorithmSwitch() {
+    try {
+      Coordinate startCoords = Game.currentLevel().startTile().coordinate();
+      Coordinate endTileCoords = Game.currentLevel().endTile().coordinate();
+      if (noPathfindingSelected && Gdx.input.isKeyJustPressed(KeyboardConfig.SELECT_DFS.value())) {
+        switchToAlgorithm(new DFSPathFinding(startCoords, endTileCoords), "DFS-Pathfinding");
+      } else if (noPathfindingSelected
+          && Gdx.input.isKeyJustPressed(KeyboardConfig.SELECT_BFS.value())) {
+        switchToAlgorithm(new BFSPathFinding(startCoords, endTileCoords), "BFS-Pathfinding");
+      } else if (noPathfindingSelected
+          && Gdx.input.isKeyJustPressed(KeyboardConfig.SELECT_SUS_ALGO.value())) {
+        if (noSuSAlgorithmAvailable) {
+          throw new OperationNotSupportedException(
+              "The SuS Pathfinding algorithm is not implemented yet.");
path: blockly/src/starter/PathfinderStarter.java
user: login: Tobi511
body: Hatte mich da an der Erwähnung von der Exception im Issue orientiert. Aber habs dann jetzt raus genommen und nur noch als Logger Nachricht drinn.
created_at: 2025-05-07T13:20:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,25 +1,31 @@
 package starter;
 
+import client.KeyboardConfig;
+import com.badlogic.gdx.Gdx;
 import contrib.entities.HeroFactory;
 import contrib.level.DevDungeonLoader;
 import contrib.systems.*;
-import contrib.systems.LevelEditorSystem;
 import core.Entity;
 import core.Game;
 import core.components.CameraComponent;
+import core.level.utils.Coordinate;
 import core.systems.LevelSystem;
 import core.utils.Tuple;
 import core.utils.components.path.SimpleIPath;
 import java.io.IOException;
 import java.util.logging.Level;
+import javax.naming.OperationNotSupportedException;
 import level.AiMazeLevel;
 import systems.PathfindingSystem;
 import utils.CheckPatternPainter;
+import utils.pathfinding.BFSPathFinding;
 import utils.pathfinding.DFSPathFinding;
 
 /** This class starts the dungeon Ai level to visualize the DFS and BFS. */
 public class PathfinderStarter {
   private static final boolean DRAW_CHECKER_PATTERN = true;
+  private static boolean noPathfindingSelected = true;
+  private static final boolean noSuSAlgorithmAvailable = true;
path: blockly/src/starter/PathfinderStarter.java
user: login: Flamtky
body: Die Idee ist es ja, dass die SuSAlgo Klassen schon existieren, und dann evtl per Default ein `OperationNotSupportedException` geworfen wird. @AMatutat sonst deine Meinung?
created_at: 2025-05-07T23:25:10Z
author_association: MEMBER
diff_hunk: @@ -1,25 +1,31 @@
 package starter;
 
+import client.KeyboardConfig;
+import com.badlogic.gdx.Gdx;
 import contrib.entities.HeroFactory;
 import contrib.level.DevDungeonLoader;
 import contrib.systems.*;
-import contrib.systems.LevelEditorSystem;
 import core.Entity;
 import core.Game;
 import core.components.CameraComponent;
+import core.level.utils.Coordinate;
 import core.systems.LevelSystem;
 import core.utils.Tuple;
 import core.utils.components.path.SimpleIPath;
 import java.io.IOException;
 import java.util.logging.Level;
+import javax.naming.OperationNotSupportedException;
 import level.AiMazeLevel;
 import systems.PathfindingSystem;
 import utils.CheckPatternPainter;
+import utils.pathfinding.BFSPathFinding;
 import utils.pathfinding.DFSPathFinding;
 
 /** This class starts the dungeon Ai level to visualize the DFS and BFS. */
 public class PathfinderStarter {
   private static final boolean DRAW_CHECKER_PATTERN = true;
+  private static boolean noPathfindingSelected = true;
+  private static final boolean noSuSAlgorithmAvailable = true;
path: blockly/src/starter/PathfinderStarter.java
user: login: AMatutat
body: > Die Idee ist es ja, dass die SuSAlgo Klassen schon existieren, und dann evtl per Default ein `OperationNotSupportedException` geworfen wird. @AMatutat sonst deine Meinung?

So. 
Ich kann das Ding ja im Hintergrund aufrufen und dann die exception fangen. 

Im devDungeon mit der SpeedPootion macht @Flamtky das auch. Kannst da Mal gucken 
created_at: 2025-05-08T04:57:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -107,5 +146,39 @@ public static void createHero() throws IOException {
     hero = HeroFactory.newHero();
     hero.remove(CameraComponent.class);
     Game.add(hero);
+
+    PlayerComponent pc =
+        Game.hero()
+            .get()
+            .fetch(PlayerComponent.class)
+            .orElseThrow(
+                () -> MissingComponentException.build(Game.hero().get(), PlayerComponent.class));
+    pc.removeCallback(core.configuration.KeyboardConfig.MOVEMENT_UP.value());
+    pc.removeCallback(core.configuration.KeyboardConfig.MOVEMENT_DOWN.value());
+    pc.removeCallback(core.configuration.KeyboardConfig.MOVEMENT_LEFT.value());
+    pc.removeCallback(core.configuration.KeyboardConfig.MOVEMENT_RIGHT.value());
+    pc.removeCallback(contrib.configuration.KeyboardConfig.MOUSE_FIRST_SKILL.value());
+    pc.removeCallback(contrib.configuration.KeyboardConfig.MOUSE_MOVE.value());
+    pc.removeCallback(contrib.configuration.KeyboardConfig.FIRST_SKILL.value());
path: blockly/src/starter/PathfinderStarter.java
user: login: Flamtky
body: ```suggestion
    hero.remove(PlayerComponent.class);
    hero.add(new PlayerComponent());
```
created_at: 2025-05-12T15:03:29Z
author_association: MEMBER
diff_hunk: @@ -1,25 +1,34 @@
 package starter;
 
+import client.KeyboardConfig;
 import contrib.entities.HeroFactory;
 import contrib.level.DevDungeonLoader;
 import contrib.systems.*;
-import contrib.systems.LevelEditorSystem;
 import core.Entity;
 import core.Game;
 import core.components.CameraComponent;
+import core.components.PlayerComponent;
+import core.level.utils.Coordinate;
 import core.systems.LevelSystem;
 import core.utils.Tuple;
+import core.utils.components.MissingComponentException;
 import core.utils.components.path.SimpleIPath;
 import java.io.IOException;
 import java.util.logging.Level;
+import java.util.logging.Logger;
 import level.AiMazeLevel;
 import systems.PathfindingSystem;
 import utils.CheckPatternPainter;
+import utils.pathfinding.BFSPathFinding;
 import utils.pathfinding.DFSPathFinding;
+import utils.pathfinding.SusPathFinding;
 
 /** This class starts the dungeon Ai level to visualize the DFS and BFS. */
 public class PathfinderStarter {
+  private static final Logger LOGGER = Logger.getLogger(PathfinderStarter.class.getName());
   private static final boolean DRAW_CHECKER_PATTERN = true;
+  private static Tuple<utils.pathfinding.PathfindingLogic, utils.pathfinding.PathfindingLogic>
path: blockly/src/starter/PathfinderStarter.java
user: login: Flamtky
body: ```suggestion
  private static Tuple<PathfindingLogic, PathfindingLogic>
```
Und noch oben `import utils.pathfinding.PathfindingLogic;` ergänzen
created_at: 2025-05-12T15:06:27Z
author_association: MEMBER
diff_hunk: @@ -107,5 +146,39 @@ public static void createHero() throws IOException {
     hero = HeroFactory.newHero();
     hero.remove(CameraComponent.class);
     Game.add(hero);
+
+    PlayerComponent pc =
+        Game.hero()
+            .get()
+            .fetch(PlayerComponent.class)
+            .orElseThrow(
+                () -> MissingComponentException.build(Game.hero().get(), PlayerComponent.class));
+    pc.removeCallback(core.configuration.KeyboardConfig.MOVEMENT_UP.value());
+    pc.removeCallback(core.configuration.KeyboardConfig.MOVEMENT_DOWN.value());
+    pc.removeCallback(core.configuration.KeyboardConfig.MOVEMENT_LEFT.value());
+    pc.removeCallback(core.configuration.KeyboardConfig.MOVEMENT_RIGHT.value());
+    pc.removeCallback(contrib.configuration.KeyboardConfig.MOUSE_FIRST_SKILL.value());
+    pc.removeCallback(contrib.configuration.KeyboardConfig.MOUSE_MOVE.value());
+    pc.removeCallback(contrib.configuration.KeyboardConfig.FIRST_SKILL.value());
+  }
+
+  /**
+   * Changes the pathfinding algorithm used in the game to the specified one.
+   *
+   * <p>This method updates the active pathfinding algorithm in the {@link PathfindingSystem} and
+   * updates the game window title to reflect the newly selected algorithm.
+   *
+   * @param algorithm The new pathfinding algorithm to be used (e.g., DFS, BFS, SuS).
+   * @param name The name of the algorithm to display in the window title for the player's
+   *     reference.
+   */
+  private static void switchToAlgorithm(utils.pathfinding.PathfindingLogic algorithm, String name) {
+    Game.system(
+        PathfindingSystem.class,
+        pfs -> {
+          pfs.autoStep(true);
+          pfs.updatePathfindingAlgorithm(algorithm);
+        });
+    Game.updateWindowTitle("Blockly KI-Dungeon – " + name);
   }
path: blockly/src/starter/PathfinderStarter.java
user: login: Flamtky
body: ```suggestion
  /**
   * Changes the pathfinding algorithm used in the game to the specified one.
   *
   * <p>This method updates the active pathfinding algorithm in the {@link PathfindingSystem} and
   * updates the game window title to reflect the newly selected algorithm.
   *
   * @param algorithm The new pathfinding algorithm to be used (e.g., DFS, BFS, SuS).
   */
  private static void switchToAlgorithm(PathfindingLogic algorithm) {
    Game.system(
        PathfindingSystem.class,
        pfs -> {
          pfs.autoStep(true);
          pfs.updatePathfindingAlgorithm(algorithm);
        });
    Game.updateWindowTitle("Blockly KI-Dungeon – " + algorithm.getClass().getSimpleName());
  }
```

Den Namen können wir uns auch sparen als Parameter, am Besten verwende wir einfach den Klassen Namen
created_at: 2025-05-12T15:08:46Z
author_association: MEMBER

PR comments:
user: login: Tobi511
created_at: 2025-05-07T10:02:59Z
body: @AMatutat @Flamtky gerne einmal Feedback bezüglich der Auswahl des eigenen Agorithmus der SuS.
author_association: CONTRIBUTOR
user: login: Tobi511
created_at: 2025-05-12T13:32:06Z
body: 1. Algo auswählen mit J K oder L
2. Algo mit B starten und abwarten bis der gefundene Weg blau markiert ist
3. mit drücken von Leertaste läuft der Held den gefundenen Weg automatisch bis zum ausgang
author_association: CONTRIBUTOR
user: login: AMatutat
created_at: 2025-05-14T08:06:44Z
body: @Tobi511 status?
author_association: CONTRIBUTOR
user: login: Tobi511
created_at: 2025-05-14T08:07:47Z
body: Ist ready
author_association: CONTRIBUTOR