|
|
|
|
|
|
|
|
package bot;
|
|
|
package bot;
|
|
|
|
|
|
|
|
|
import java.util.Scanner;
|
|
|
|
|
|
|
|
|
import java.util.*;
|
|
|
|
|
|
|
|
|
public class EscapeBot extends Bot {
|
|
|
public class EscapeBot extends Bot {
|
|
|
private int currentX = 0;
|
|
|
|
|
|
private int currentY = 0;
|
|
|
|
|
|
private int spiralSize = 1;
|
|
|
|
|
|
private int stepsInCurrentDirection = 0;
|
|
|
|
|
|
private char currentDirection = 'd'; // Start with moving to the right
|
|
|
|
|
|
|
|
|
private boolean rocketFound;
|
|
|
|
|
|
private int roverX;
|
|
|
|
|
|
private int roverY;
|
|
|
|
|
|
|
|
|
public EscapeBot(String[] args) {
|
|
|
public EscapeBot(String[] args) {
|
|
|
super(args);
|
|
|
super(args);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
EscapeBot escapeBot = new EscapeBot(args);
|
|
|
|
|
|
escapeBot.run();
|
|
|
|
|
|
|
|
|
this.rocketFound = false;
|
|
|
|
|
|
this.roverX = -1; // Startposition des Rovers ist unbekannt
|
|
|
|
|
|
this.roverY = -1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
@Override
|
|
|
@Override
|
|
|
protected char nextMove(View view) throws Exception {
|
|
|
protected char nextMove(View view) throws Exception {
|
|
|
char[][] map = parseMap(view.data, view.width);
|
|
|
|
|
|
|
|
|
|
|
|
char nextMove = 'w'; // Default move is to go forward
|
|
|
|
|
|
|
|
|
|
|
|
if (map[currentY][currentX] == 'o') {
|
|
|
|
|
|
System.out.println("Rakete gefunden!");
|
|
|
|
|
|
nextMove = 'q'; // Beende die Verbindung, wenn die Rakete gefunden wurde
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Bewegungslogik im Spiralmuster
|
|
|
|
|
|
switch (currentDirection) {
|
|
|
|
|
|
case 'd': // Bewege nach rechts
|
|
|
|
|
|
currentX++;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 's': // Bewege nach unten
|
|
|
|
|
|
currentY++;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'a': // Bewege nach links
|
|
|
|
|
|
currentX--;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'w': // Bewege nach oben
|
|
|
|
|
|
currentY--;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
if (rocketFound) {
|
|
|
|
|
|
System.out.println("Rakete gefunden! Rover kehrt zurück.");
|
|
|
|
|
|
return 'V'; // Rückwärts bewegen
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (roverX == -1 || roverY == -1) {
|
|
|
|
|
|
for (int y = 0; y < view.width; y++) {
|
|
|
|
|
|
for (int x = 0; x < view.width; x++) {
|
|
|
|
|
|
char cell = view.data.charAt(y * view.width + x);
|
|
|
|
|
|
if (cell == 'A') {
|
|
|
|
|
|
roverX = x;
|
|
|
|
|
|
roverY = y;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char[][] grid = new char[view.width][view.width];
|
|
|
|
|
|
for (int y = 0; y < view.width; y++) {
|
|
|
|
|
|
for (int x = 0; x < view.width; x++) {
|
|
|
|
|
|
grid[y][x] = view.data.charAt(y * view.width + x);
|
|
|
}
|
|
|
}
|
|
|
stepsInCurrentDirection++;
|
|
|
|
|
|
|
|
|
|
|
|
// Wenn der Rover die maximale Anzahl von Schritten in dieser Richtung erreicht hat
|
|
|
|
|
|
if (stepsInCurrentDirection == spiralSize) {
|
|
|
|
|
|
// Ändere die Richtung nach rechts
|
|
|
|
|
|
switch (currentDirection) {
|
|
|
|
|
|
case 'd':
|
|
|
|
|
|
currentDirection = 's';
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 's':
|
|
|
|
|
|
currentDirection = 'a';
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'a':
|
|
|
|
|
|
currentDirection = 'w';
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'w':
|
|
|
|
|
|
currentDirection = 'd';
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
List<Node> path = aStarSearch(grid, roverX, roverY);
|
|
|
|
|
|
|
|
|
|
|
|
if (path != null && !path.isEmpty()) {
|
|
|
|
|
|
Node nextNode = path.get(0);
|
|
|
|
|
|
if (nextNode.x > roverX) {
|
|
|
|
|
|
roverX++;
|
|
|
|
|
|
return 'd'; // Nach rechts bewegen
|
|
|
|
|
|
} else if (nextNode.x < roverX) {
|
|
|
|
|
|
roverX--;
|
|
|
|
|
|
return 'a'; // Nach links bewegen
|
|
|
|
|
|
} else if (nextNode.y > roverY) {
|
|
|
|
|
|
roverY++;
|
|
|
|
|
|
return '^'; // Vorwärts bewegen
|
|
|
|
|
|
} else if (nextNode.y < roverY) {
|
|
|
|
|
|
roverY--;
|
|
|
|
|
|
return 'V'; // Rückwärts bewegen
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return '^'; // Standardbewegung, wenn keine Richtung gefunden wurde
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private List<Node> aStarSearch(char[][] grid, int startX, int startY) {
|
|
|
|
|
|
PriorityQueue<Node> openList = new PriorityQueue<>(Comparator.comparingInt(a -> a.f));
|
|
|
|
|
|
Set<Node> closedSet = new HashSet<>();
|
|
|
|
|
|
Map<Node, Node> cameFrom = new HashMap<>();
|
|
|
|
|
|
Map<Node, Integer> gScore = new HashMap<>();
|
|
|
|
|
|
Map<Node, Integer> fScore = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
Node startNode = new Node(startX, startY);
|
|
|
|
|
|
openList.add(startNode);
|
|
|
|
|
|
gScore.put(startNode, 0);
|
|
|
|
|
|
fScore.put(startNode, heuristic(startNode));
|
|
|
|
|
|
|
|
|
|
|
|
while (!openList.isEmpty()) {
|
|
|
|
|
|
Node current = openList.poll();
|
|
|
|
|
|
|
|
|
|
|
|
if (grid[current.y][current.x] == 'o') {
|
|
|
|
|
|
return reconstructPath(cameFrom, current);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
closedSet.add(current);
|
|
|
|
|
|
|
|
|
|
|
|
for (Node neighbor : getNeighbors(current, grid)) {
|
|
|
|
|
|
if (closedSet.contains(neighbor)) {
|
|
|
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
// Setze die Anzahl der Schritte in dieser Richtung zurück und erhöhe die Spiralgöße
|
|
|
|
|
|
stepsInCurrentDirection = 0;
|
|
|
|
|
|
if (currentDirection == 'd' || currentDirection == 'a') {
|
|
|
|
|
|
spiralSize++;
|
|
|
|
|
|
|
|
|
int tentativeGScore = gScore.getOrDefault(current, Integer.MAX_VALUE) + 1;
|
|
|
|
|
|
|
|
|
|
|
|
if (!openList.contains(neighbor) || tentativeGScore < gScore.getOrDefault(neighbor, Integer.MAX_VALUE)) {
|
|
|
|
|
|
cameFrom.put(neighbor, current);
|
|
|
|
|
|
gScore.put(neighbor, tentativeGScore);
|
|
|
|
|
|
fScore.put(neighbor, tentativeGScore + heuristic(neighbor));
|
|
|
|
|
|
|
|
|
|
|
|
if (!openList.contains(neighbor)) {
|
|
|
|
|
|
openList.add(neighbor);
|
|
|
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return null; // Kein Weg gefunden
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private List<Node> getNeighbors(Node node, char[][] grid) {
|
|
|
|
|
|
List<Node> neighbors = new ArrayList<>();
|
|
|
|
|
|
|
|
|
// Überprüfe, ob der nächste Zug innerhalb der Karte liegt
|
|
|
|
|
|
if (currentX < 0 || currentX >= view.width || currentY < 0 || currentY >= view.width) {
|
|
|
|
|
|
// Der nächste Zug liegt außerhalb der Karte, also drehe den Rover um
|
|
|
|
|
|
nextMove = 'a';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Der nächste Zug liegt innerhalb der Karte, bewege den Rover dorthin
|
|
|
|
|
|
nextMove = currentDirection;
|
|
|
|
|
|
|
|
|
int[][] directions = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; // Rechts, Links, Unten, Oben
|
|
|
|
|
|
|
|
|
|
|
|
for (int[] dir : directions) {
|
|
|
|
|
|
int newX = node.x + dir[0];
|
|
|
|
|
|
int newY = node.y + dir[1];
|
|
|
|
|
|
|
|
|
|
|
|
if (newX >= 0 && newX < grid.length && newY >= 0 && newY < grid.length &&
|
|
|
|
|
|
grid[newY][newX] != '#') {
|
|
|
|
|
|
neighbors.add(new Node(newX, newY));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
return nextMove;
|
|
|
|
|
|
|
|
|
return neighbors;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
// Hilfsmethode zum Parsen des Kartenscans in ein char-Array
|
|
|
|
|
|
private char[][] parseMap(String data, int width) {
|
|
|
|
|
|
char[][] map = new char[width][width];
|
|
|
|
|
|
String[] lines = data.split("\n");
|
|
|
|
|
|
for (int i = 0; i < width; i++) {
|
|
|
|
|
|
String line = lines[i];
|
|
|
|
|
|
for (int j = 0; j < width; j++) {
|
|
|
|
|
|
map[i][j] = line.charAt(j);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
private List<Node> reconstructPath(Map<Node, Node> cameFrom, Node current) {
|
|
|
|
|
|
List<Node> path = new ArrayList<>();
|
|
|
|
|
|
path.add(current);
|
|
|
|
|
|
while (cameFrom.containsKey(current)) {
|
|
|
|
|
|
current = cameFrom.get(current);
|
|
|
|
|
|
path.add(current);
|
|
|
}
|
|
|
}
|
|
|
return map;
|
|
|
|
|
|
|
|
|
Collections.reverse(path);
|
|
|
|
|
|
return path;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int heuristic(Node node) {
|
|
|
|
|
|
// Verwenden Sie die Manhattan-Distanz als Heuristik, um die tatsächliche Entfernung zum Ziel zu schätzen
|
|
|
|
|
|
return Math.abs(node.x - roverX) + Math.abs(node.y - roverY);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static class Node {
|
|
|
|
|
|
int x;
|
|
|
|
|
|
int y;
|
|
|
|
|
|
int f;
|
|
|
|
|
|
|
|
|
|
|
|
Node(int x, int y) {
|
|
|
|
|
|
this.x = x;
|
|
|
|
|
|
this.y = y;
|
|
|
|
|
|
this.f = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public boolean equals(Object o) {
|
|
|
|
|
|
if (this == o) return true;
|
|
|
|
|
|
if (o == null || getClass() != o.getClass()) return false;
|
|
|
|
|
|
Node node = (Node) o;
|
|
|
|
|
|
return x == node.x && y == node.y;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public int hashCode() {
|
|
|
|
|
|
return Objects.hash(x, y);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
EscapeBot escapeBot = new EscapeBot(args);
|
|
|
|
|
|
escapeBot.run();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|