studientag

This commit is contained in:
Saly Toutanji 2025-02-11 13:42:50 +01:00
parent 08b00f7571
commit c1bbb2bb5e
2 changed files with 215 additions and 0 deletions

87
src/Praktikum3/Bot.java Normal file
View File

@ -0,0 +1,87 @@
package Praktikum3;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.InetSocketAddress;
public abstract class Bot {
// Ein Bot ist ein Programm, das sich mit einem Server verbindet und
// mit diesem kommuniziert. Der Server sendet dem Bot eine Zeichenkette,
// die das Spielfeld repräsentiert. Der Bot sendet dem Server ein Zeichen,
// das die nächste Bewegung des Bots repräsentiert.
private final String host; // Hostname oder IP-Adresse des Servers
private final int port; // Port des Servers
protected Bot(String[] args) {
host = args.length > 0 ? args[0] : "localhost";
port = args.length > 1 ? Integer.parseInt(args[1]) : 63187;
}
// Diese Methode stellt die Verbindung zum Server her und startet die
// Kommunikation mit dem Server. Die Methode wird von der main-Methode
// aufgerufen.
protected void run() {
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(host, port));
OutputStream out = socket.getOutputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
View view = new View();
while (true) {
view.read(in);
view.print();
try {
char ch = nextMove(view);
out.write(ch);
}
catch (Exception e) { break; }
}
socket.close();
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
}
}
// Diese Methode ermittelt den nächsten Zug des Bots. Sie wird von der
// run-Methode aufgerufen, nachdem der Server das Spielfeld gesendet hat.
// Subklassen müssen diese Methode implementieren.
abstract protected char nextMove(View view) throws Exception;
// Diese Klasse repräsentiert das Spielfeld. Sie wird von der run-Methode
// verwendet, um das Spielfeld zu lesen und auszugeben.
// Subklassen können diese Klasse verwenden, um das Spielfeld zu analysieren.
public static class View {
protected String data;
protected int width;
// Diese Methode liest das Spielfeld vom Server.
private void read(BufferedReader in) throws IOException {
StringBuilder sb = new StringBuilder();
data = in.readLine();
if (data == null) {
return;
}
sb.append(data);
width = data.length();
for (int i = 1; i < width; ++i) {
sb.append(in.readLine());
}
data = sb.toString();
}
// Diese Methode gibt das Spielfeld aus.
protected void print() {
if (data == null || width < 1) {
return;
}
for (int i = 0, len = data.length(); i < len; i += width) {
System.out.println(data.substring(i, i + width));
}
}
}
}

View File

@ -0,0 +1,128 @@
package Praktikum3;
import java.util.*;
public class SnakeBot extends Bot {
private Set<Integer> visited = new HashSet<>();
public SnakeBot(String[] args) {
super(args);
}
@Override
protected char nextMove(View view) {
if (view == null || view.data == null || view.data.isEmpty()) {
System.err.println("FEHLER: View-Daten fehlen! Verbindung unterbrochen?");
return 'q'; // Stoppt sicher
}
int width = view.width;
String data = view.data;
int pos = data.indexOf('A');
if (pos == -1) {
System.err.println("FEHLER: Rover nicht gefunden! Bewege mich zufällig.");
return randomMove();
}
int rockPos = findClosestRock(pos, width, data);
if (rockPos != -1) {
return pathfindMove(pos, rockPos, width, data);
}
return exploreStrategically(pos, width, data);
}
private int findClosestRock(int pos, int width, String data) {
Queue<Integer> queue = new LinkedList<>();
Set<Integer> visited = new HashSet<>();
queue.add(pos);
visited.add(pos);
while (!queue.isEmpty()) {
int current = queue.poll();
if (data.charAt(current) == '@') {
return current; // `@` gefunden, direkt dorthin!
}
for (int next : getNeighbors(current, width, data)) {
if (!visited.contains(next)) {
visited.add(next);
queue.add(next);
}
}
}
return -1; // Keine `@` gefunden
}
private List<Integer> getNeighbors(int pos, int width, String data) {
List<Integer> neighbors = new ArrayList<>();
int[] deltas = {-width, width, -1, 1};
for (int delta : deltas) {
int newPos = pos + delta;
if (newPos >= 0 && newPos < data.length() && ".@".indexOf(data.charAt(newPos)) != -1) {
neighbors.add(newPos);
}
}
return neighbors;
}
private char pathfindMove(int pos, int target, int width, String data) {
int x = pos % width, y = pos / width;
int tx = target % width, ty = target / width;
if (ty < y && canMove(pos - width, data)) return '^';
if (ty > y && canMove(pos + width, data)) return 'v';
if (tx < x && canMove(pos - 1, data)) return '<';
if (tx > x && canMove(pos + 1, data)) return '>';
return randomMove(); // Falls kein direkter Weg verfügbar ist, bewege dich zufällig
}
private char exploreStrategically(int pos, int width, String data) {
List<Character> possibleMoves = new ArrayList<>();
int[] deltas = {-width, width, -1, 1};
char[] directions = {'^', 'v', '<', '>'};
for (int i = 0; i < deltas.length; i++) {
int newPos = pos + deltas[i];
if (newPos >= 0 && newPos < data.length() && data.charAt(newPos) == '.') {
if (!visited.contains(newPos)) {
visited.add(newPos);
return directions[i];
}
possibleMoves.add(directions[i]);
}
}
if (!possibleMoves.isEmpty()) {
return possibleMoves.get(new Random().nextInt(possibleMoves.size()));
}
return randomMove();
}
private boolean canMove(int pos, String data) {
return pos >= 0 && pos < data.length() && ".@".indexOf(data.charAt(pos)) != -1;
}
private char randomMove() {
char[] moves = {'^', 'v', '<', '>'};
return moves[new Random().nextInt(moves.length)];
}
public static void main(String[] args) {
try {
new SnakeBot(args).run();
} catch (Exception e) {
System.err.println("Fehler im Bot-Hauptprozess: " + e.getMessage());
}
}
}
// docker run --rm -p 63187:63187 mediaeng/bots snakes