Merge branch 'main' into cleanup-work
This commit is contained in:
commit
931a757a67
|
@ -1,3 +1,8 @@
|
|||
/**
|
||||
* Die Klasse AiPlayer ist die Basis für alle Ki Spieler und jede Spezifische Ki erweitert diese Klasse.
|
||||
* @author Florian und Florian
|
||||
* */
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
@ -6,19 +11,34 @@ import java.util.Random;
|
|||
|
||||
public abstract class AiPlayer extends LocalPlayer implements Runnable {
|
||||
|
||||
/**
|
||||
* Liste aller erstellten ShootThreads
|
||||
*/
|
||||
List<Thread> shootThreads;
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*/
|
||||
public AiPlayer() {
|
||||
this.setName("AI Player");
|
||||
this.shootThreads = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt einen zufälligen Punkt im Spielfeld zurück.
|
||||
* @return Ein zufälliger Punkt
|
||||
*/
|
||||
public Point RandomPoint() {
|
||||
Random random = new Random(); // Pseudo Random für zufallszahlen
|
||||
int posx = random.nextInt(super.board.getSize()); // Generiert 0 - 13
|
||||
int posy = random.nextInt(super.board.getSize()); //
|
||||
return new Point(posx,posy);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialisiert das Board.
|
||||
* @param size größe des Boards
|
||||
*/
|
||||
@Override
|
||||
public void createBoard(int size) {
|
||||
super.createBoard(size);
|
||||
|
@ -26,31 +46,39 @@ public abstract class AiPlayer extends LocalPlayer implements Runnable {
|
|||
this.ready();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ki Methode zum zufälligen Setzten der Schiffe
|
||||
*/
|
||||
public void aiSetShips() {
|
||||
for(int i = 0; i < super.board.getShips().size(); i++) { // Interiert durch alle Shiffe
|
||||
//TODO: set horizontal
|
||||
while(!super.board.getShips().get(i).setPosition(RandomPoint(), true, super.board.getShips(), super.board.getSize())) {}
|
||||
} // Versucht das Aktuelle Shiff zu setzten und wiederholt solange bis es funktioniert
|
||||
} // Versucht das aktuelle Schiff zu setzten und wiederholt solange bis es funktioniert
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ki Methode zum zufälligen Schießen auf das gegnerische Board.
|
||||
*/
|
||||
public void aiShoot() {
|
||||
if (!this.myTurn) return;
|
||||
this.enemy.receiveShoot(RandomPoint());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized void receiveHit(HitResponse hitResponse) {
|
||||
// Eltern-Klasse LocalPlayer updatet myTurn
|
||||
super.receiveHit(hitResponse);
|
||||
if (this.myTurn) {
|
||||
// Neuer Schuss wird erstellt und gestartet.
|
||||
Thread t = new Thread(this);
|
||||
t.start();
|
||||
this.shootThreads.add(t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized void receiveShoot(Point point) {
|
||||
super.receiveShoot(point);
|
||||
|
@ -60,8 +88,11 @@ public abstract class AiPlayer extends LocalPlayer implements Runnable {
|
|||
this.shootThreads.add(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Wird aufgerufen, wenn in determineCoinToss festgestellt wurde das die Ki anfängt.
|
||||
* Erster Schuss wird gestartet.
|
||||
*/
|
||||
@Override
|
||||
public void beginTurn() {
|
||||
Thread t = new Thread(this);
|
||||
|
@ -90,7 +121,7 @@ public abstract class AiPlayer extends LocalPlayer implements Runnable {
|
|||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(300);
|
||||
Thread.sleep(250);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
|
@ -118,4 +149,4 @@ public abstract class AiPlayer extends LocalPlayer implements Runnable {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
|
||||
/**
|
||||
* Diese Klasse implementiert den Einfachsten Ki Spieler.
|
||||
* @author Florian und Florian
|
||||
* */
|
||||
public class SpecificAiPlayerEasy extends AiPlayer{
|
||||
|
||||
/**
|
||||
* Bein einfachen Ki Spieler wird nur der AiPlayer initialisiert und der Name gesetzt,
|
||||
* da in der Eltern-Klasse AiPlayer eine default implementierung für alle Methoden existieren.
|
||||
*/
|
||||
public SpecificAiPlayerEasy() {
|
||||
super();
|
||||
this.setName("AI Player Easy");
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
/**
|
||||
* Diese Klasse implementiert den Harten Ki Spieler.
|
||||
* @author Florian und Florian
|
||||
* */
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
|
||||
|
@ -10,6 +14,17 @@ public class SpecificAiPlayerHard extends AiPlayer{
|
|||
private int nextChessRow;
|
||||
private int nextChessCol;
|
||||
|
||||
// Enum für die Orientierung
|
||||
private enum Orientierung {
|
||||
UNBEKANNT,
|
||||
HORIZONTAL,
|
||||
VERTIKAL
|
||||
}
|
||||
private Orientierung orientierung;
|
||||
private Point firstHit; // Speichert den ersten Treffer zur Bestimmung der Orientierung
|
||||
|
||||
|
||||
|
||||
public SpecificAiPlayerHard() {
|
||||
super();
|
||||
this.setName("AI Player Hard");
|
||||
|
@ -20,6 +35,8 @@ public class SpecificAiPlayerHard extends AiPlayer{
|
|||
this.random = new Random();
|
||||
this.nextChessRow = 0;
|
||||
this.nextChessCol = 0;
|
||||
this.orientierung = Orientierung.UNBEKANNT;
|
||||
this.firstHit = null;
|
||||
}
|
||||
|
||||
// Checks if a position has already been shot at
|
||||
|
@ -33,16 +50,16 @@ public class SpecificAiPlayerHard extends AiPlayer{
|
|||
this.gridSize = super.board.getSize();
|
||||
this.shotsFired = new boolean[gridSize][gridSize];
|
||||
}
|
||||
// If there are hits to process, prioritize those
|
||||
// Wenn wir noch Treffer in der Queue haben, diese priorisieren
|
||||
while (!hitQueue.isEmpty()) {
|
||||
Point target = hitQueue.remove(0);
|
||||
|
||||
Point target = hitQueue.remove(0);
|
||||
if (!alreadyShot(target)) {
|
||||
shotsFired[target.getX()][target.getY()] = true;
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, use chess pattern targeting
|
||||
// Ansonsten weiterhin "Schachbrettmuster"
|
||||
int row = nextChessRow;
|
||||
int col = nextChessCol;
|
||||
while (alreadyShot(new Point(row, col))) {
|
||||
|
@ -55,16 +72,113 @@ public class SpecificAiPlayerHard extends AiPlayer{
|
|||
advanceChessPattern();
|
||||
return new Point(row, col);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized void receiveHit(HitResponse hitResponse) {
|
||||
super.receiveHit(hitResponse);
|
||||
// If it's a hit or sunk, add adjacent cells to the hitsQueue
|
||||
|
||||
// Wenn es ein Treffer ist, Adjacent-Punkte hinzufügen
|
||||
if (hitResponse.getHitResponse() == HitResponseType.HIT) {
|
||||
addAdjacentPoints(hitResponse.getPoint());
|
||||
Point hitPoint = hitResponse.getPoint();
|
||||
|
||||
// Wenn wir noch keinen ersten Treffer haben, speicher ihn
|
||||
if (firstHit == null) {
|
||||
firstHit = hitPoint;
|
||||
// Orientierung noch unbekannt: alle möglichen Richtungen hinzufügen
|
||||
addAdjacentPoints(hitPoint);
|
||||
} else {
|
||||
// Wenn Orientierung noch nicht bestimmt, jetzt prüfen
|
||||
if (this.orientierung == Orientierung.UNBEKANNT) {
|
||||
// Prüfen, ob der zweite Treffer horizontal oder vertikal liegt
|
||||
if (firstHit.getY() == hitPoint.getY()) {
|
||||
this.orientierung = Orientierung.VERTIKAL;
|
||||
} else if (firstHit.getX() == hitPoint.getX()) {
|
||||
this.orientierung = Orientierung.HORIZONTAL;
|
||||
}
|
||||
|
||||
// Sobald die Orientierung erkannt wurde, entferne alle „unpassenden“ Punkte
|
||||
if (this.orientierung != Orientierung.UNBEKANNT) {
|
||||
cleanUpHitQueue();
|
||||
}
|
||||
}
|
||||
// Für den aktuellen Treffer nur in passender Orientierung erweitern
|
||||
addPointsByOrientation(hitPoint);
|
||||
}
|
||||
} else if (hitResponse.getHitResponse() == HitResponseType.SUNK) {
|
||||
this.orientierung = Orientierung.UNBEKANNT;
|
||||
firstHit = null;
|
||||
hitQueue.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Entfernt aus der hitQueue alle Punkte, die nicht der erkannten Orientierung entsprechen.
|
||||
*/
|
||||
private void cleanUpHitQueue() {
|
||||
if (firstHit == null || this.orientierung == Orientierung.UNBEKANNT) {
|
||||
return;
|
||||
}
|
||||
ArrayList<Point> toRemove = new ArrayList<>();
|
||||
for (Point p : hitQueue) {
|
||||
if (this.orientierung == Orientierung.HORIZONTAL) {
|
||||
// HORIZONTAL => gleiche Zeile wie firstHit
|
||||
if (p.getX() != firstHit.getX()) {
|
||||
toRemove.add(p);
|
||||
}
|
||||
} else if (this.orientierung == Orientierung.VERTIKAL) {
|
||||
// VERTICAL => gleiche Spalte wie firstHit
|
||||
if (p.getY() != firstHit.getY()) {
|
||||
toRemove.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
hitQueue.removeAll(toRemove);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt benachbarte Felder in der **erkannten Orientierung** hinzu.
|
||||
* - Ist die Orientierung HORIZONTAL, so werden nur links/rechts hinzugefügt.
|
||||
* - Ist sie VERTICAL, so werden nur oben/unten hinzugefügt.
|
||||
*/
|
||||
private void addPointsByOrientation(Point point) {
|
||||
if (this.orientierung == Orientierung.UNBEKANNT) {
|
||||
// Fallback: füge alle benachbarten Punkte hinzu
|
||||
addAdjacentPoints(point);
|
||||
return;
|
||||
}
|
||||
|
||||
int x = point.getX();
|
||||
int y = point.getY();
|
||||
if (this.orientierung == Orientierung.HORIZONTAL) {
|
||||
// Gleiche Zeile => links und rechts vom Point
|
||||
Point left = new Point(x, y - 1);
|
||||
Point right = new Point(x, y + 1);
|
||||
|
||||
if (isValidPoint(left) && !alreadyShot(left) && !hitQueue.contains(left)) {
|
||||
hitQueue.add(left);
|
||||
}
|
||||
if (isValidPoint(right) && !alreadyShot(right) && !hitQueue.contains(right)) {
|
||||
hitQueue.add(right);
|
||||
}
|
||||
} else if (this.orientierung == Orientierung.VERTIKAL) {
|
||||
// Gleiche Spalte => oben und unten
|
||||
Point up = new Point(x - 1, y);
|
||||
Point down = new Point(x + 1, y);
|
||||
|
||||
if (isValidPoint(up) && !alreadyShot(up) && !hitQueue.contains(up)) {
|
||||
hitQueue.add(up);
|
||||
}
|
||||
if (isValidPoint(down) && !alreadyShot(down) && !hitQueue.contains(down)) {
|
||||
hitQueue.add(down);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Diese Methode erweitert die hitsQueue um die umliegenden Punkte die Schiffe seien könnten.
|
||||
* @param point
|
||||
*/
|
||||
private void addAdjacentPoints(Point point) {
|
||||
int x = point.getX();
|
||||
int y = point.getY();
|
||||
|
@ -83,12 +197,18 @@ public class SpecificAiPlayerHard extends AiPlayer{
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Methode gibt zurück, ob eine Position auf dem Board ist. (Boolean)
|
||||
* @param point Punkt der geprüft werden soll
|
||||
* @return Ist auf dem Board oder nicht.
|
||||
*/
|
||||
private boolean isValidPoint(Point point) {
|
||||
return point.getX() >= 0 && point.getX() < gridSize &&
|
||||
point.getY() >= 0 && point.getY() < gridSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ki Methode um zu schießen.
|
||||
*/
|
||||
@Override
|
||||
public void aiShoot() {
|
||||
this.enemy.receiveShoot(getNextMove());
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
/**
|
||||
* Diese Klasse implementiert den Medium Ki Spieler.
|
||||
* @author Florian und Florian
|
||||
* */
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SpecificAiPlayerMedium extends AiPlayer{
|
||||
|
||||
/**
|
||||
* Liste an Punkten die beschossen werden sollen. (Mögliche weitere Segmente vom schiff)
|
||||
*/
|
||||
private List<Point> hitsQueue = new ArrayList<>();
|
||||
|
||||
public SpecificAiPlayerMedium() {
|
||||
|
@ -10,6 +16,9 @@ public class SpecificAiPlayerMedium extends AiPlayer{
|
|||
this.setName("AI Player Medium");
|
||||
}
|
||||
|
||||
/**
|
||||
* Ki Methode um zu schießen.
|
||||
*/
|
||||
@Override
|
||||
public void aiShoot() {
|
||||
Point nextShot = ComputeNextShot();
|
||||
|
@ -26,6 +35,10 @@ public class SpecificAiPlayerMedium extends AiPlayer{
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Methode bestimmt welche Position als nächstes beschossen werden soll.
|
||||
* @return
|
||||
*/
|
||||
public Point ComputeNextShot() {
|
||||
Point nextShot;
|
||||
|
||||
|
@ -45,6 +58,10 @@ public class SpecificAiPlayerMedium extends AiPlayer{
|
|||
return nextShot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Methode erweitert die hitsQueue um die umliegenden Punkte die Schiffe seien könnten.
|
||||
* @param point
|
||||
*/
|
||||
private void addAdjacentPoints(Point point) {
|
||||
int x = point.getX();
|
||||
int y = point.getY();
|
||||
|
@ -64,12 +81,22 @@ public class SpecificAiPlayerMedium extends AiPlayer{
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Methode gibt zurück, ob eine Position schon beschossen wurde. (Boolean)
|
||||
* @param p Punkt der geprüft werden soll
|
||||
* @return wurde schon beschossen oder nicht.
|
||||
*/
|
||||
private boolean alreadyShot(Point p) {
|
||||
|
||||
return this.enemy.board.getHitResponseOnPoint(p) != null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Methode gibt zurück, ob eine Position auf dem Board ist. (Boolean)
|
||||
* @param point Punkt der geprüft werden soll
|
||||
* @return Ist auf dem Board oder nicht.
|
||||
*/
|
||||
private boolean isValidPoint(Point point) {
|
||||
return point.getX() >= 0 && point.getX() < board.getSize() &&
|
||||
point.getY() >= 0 && point.getY() < board.getSize();
|
||||
|
|
Loading…
Reference in New Issue