From c1bbb2bb5e22ed50afc5a590fb82efec51168134 Mon Sep 17 00:00:00 2001 From: salyt Date: Tue, 11 Feb 2025 13:42:50 +0100 Subject: [PATCH] studientag --- src/Praktikum3/Bot.java | 87 ++++++++++++++++++++++++ src/Praktikum3/SnakeBot.java | 128 +++++++++++++++++++++++++++++++++++ 2 files changed, 215 insertions(+) create mode 100644 src/Praktikum3/Bot.java create mode 100644 src/Praktikum3/SnakeBot.java diff --git a/src/Praktikum3/Bot.java b/src/Praktikum3/Bot.java new file mode 100644 index 0000000..55d31ba --- /dev/null +++ b/src/Praktikum3/Bot.java @@ -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)); + } + } + } +} diff --git a/src/Praktikum3/SnakeBot.java b/src/Praktikum3/SnakeBot.java new file mode 100644 index 0000000..e163bba --- /dev/null +++ b/src/Praktikum3/SnakeBot.java @@ -0,0 +1,128 @@ +package Praktikum3; + +import java.util.*; + +public class SnakeBot extends Bot { + + private Set 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 queue = new LinkedList<>(); + Set 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 getNeighbors(int pos, int width, String data) { + List 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 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 \ No newline at end of file