Compare commits
9 Commits
b1273e759d
...
43545afb45
Author | SHA1 | Date |
---|---|---|
|
43545afb45 | |
|
addf542300 | |
|
1fb284eb1a | |
|
bdde2066f3 | |
|
ab1aae7798 | |
|
cecc44abf4 | |
|
998ff3d663 | |
|
2c6f9adf54 | |
|
3eeb4d25bd |
|
@ -1,10 +1,8 @@
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
public abstract class AiPlayer extends Player {
|
public abstract class AiPlayer extends LocalPlayer {
|
||||||
|
|
||||||
public AiPlayer(int size) {
|
public AiPlayer() {}
|
||||||
super(size);
|
|
||||||
}
|
|
||||||
public Point RandomPoint() {
|
public Point RandomPoint() {
|
||||||
Random random = new Random(); // Pseudo Random für zufallszahlen
|
Random random = new Random(); // Pseudo Random für zufallszahlen
|
||||||
int posx = random.nextInt(super.board.getSize()); // Generiert 0 - 13
|
int posx = random.nextInt(super.board.getSize()); // Generiert 0 - 13
|
||||||
|
|
|
@ -36,7 +36,7 @@ public class AsyncSocket {
|
||||||
String message = this.in.readLine();
|
String message = this.in.readLine();
|
||||||
if (message.length() <= 0) continue;
|
if (message.length() <= 0) continue;
|
||||||
|
|
||||||
// TODO: remove \r\n
|
message = message.strip();
|
||||||
this.handler.receive(message);
|
this.handler.receive(message);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|
|
@ -2,19 +2,33 @@ import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.net.SocketTimeoutException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class GameController {
|
public class GameController {
|
||||||
|
|
||||||
|
// Connection timeout for client sockets in milliseconds
|
||||||
|
public static final int CONNECTION_TIMEOUT = 10 * 1000;
|
||||||
|
|
||||||
|
public static int semesterToBoardSize(int semester) {
|
||||||
|
return semester + 13;
|
||||||
|
}
|
||||||
|
|
||||||
public HashMap<String, Class<? extends OnlinePlayer>> supportedVersions = new HashMap<>(Map.of(
|
public HashMap<String, Class<? extends OnlinePlayer>> supportedVersions = new HashMap<>(Map.of(
|
||||||
"1.1.0", OnlinePlayer_1_1_0.class
|
"1.1.0", OnlinePlayer_1_1_0.class
|
||||||
));
|
));
|
||||||
|
|
||||||
public void startOnlineGame(Class<? extends LocalPlayer> localPlayerClass, InetSocketAddress address) throws IOException {
|
public void startOnlineGame(Class<? extends LocalPlayer> localPlayerClass, InetSocketAddress address, int size) throws IOException {
|
||||||
AsyncSocket clientSocket;
|
AsyncSocket clientSocket;
|
||||||
if (address.getHostName() == null) {
|
|
||||||
|
boolean localPlayerIsServer = address.getHostName() == null;
|
||||||
|
|
||||||
|
if (localPlayerIsServer) {
|
||||||
// SERVER MODE
|
// SERVER MODE
|
||||||
|
|
||||||
ServerSocket serverSocket = new ServerSocket(address.getPort());
|
ServerSocket serverSocket = new ServerSocket(address.getPort());
|
||||||
|
|
||||||
System.out.println("Waiting for client connection...");
|
System.out.println("Waiting for client connection...");
|
||||||
|
@ -23,10 +37,21 @@ public class GameController {
|
||||||
|
|
||||||
serverSocket.close();
|
serverSocket.close();
|
||||||
} else {
|
} else {
|
||||||
Socket socket = new Socket();
|
// CLIENT MODE
|
||||||
socket.connect(address);
|
|
||||||
|
Socket socket = new Socket();
|
||||||
|
|
||||||
|
try {
|
||||||
|
socket.connect(address, CONNECTION_TIMEOUT);
|
||||||
|
|
||||||
|
clientSocket = new AsyncSocket(socket, null);
|
||||||
|
} catch (SocketTimeoutException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Connection timed out");
|
||||||
|
} finally {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
|
||||||
clientSocket = new AsyncSocket(socket, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clientSocket.send("VERSION", "Gruppe03 " + String.join(" ", supportedVersions.keySet()));
|
clientSocket.send("VERSION", "Gruppe03 " + String.join(" ", supportedVersions.keySet()));
|
||||||
|
@ -34,15 +59,101 @@ public class GameController {
|
||||||
|
|
||||||
SocketPackage socketPackage = new SocketPackage(message);
|
SocketPackage socketPackage = new SocketPackage(message);
|
||||||
if (socketPackage.getName().equals("VERSION")) {
|
if (socketPackage.getName().equals("VERSION")) {
|
||||||
// TODO: check version matches - instantiate online player
|
|
||||||
|
List<String> opponentSupportedVersions = socketPackage.splitData();
|
||||||
|
|
||||||
|
String usedVersion = findMostRecentVersion(new ArrayList<String>(supportedVersions.keySet()), opponentSupportedVersions);
|
||||||
|
|
||||||
|
if (usedVersion == null) {
|
||||||
|
throw new RuntimeException("No common versions found");
|
||||||
|
}
|
||||||
|
|
||||||
|
// instantiate players
|
||||||
|
Class<? extends OnlinePlayer> onlinePlayerClass = supportedVersions.get(usedVersion);
|
||||||
|
|
||||||
|
LocalPlayer localPlayer;
|
||||||
|
OnlinePlayer onlinePlayer;
|
||||||
|
try {
|
||||||
|
localPlayer = localPlayerClass.getDeclaredConstructor().newInstance();
|
||||||
|
onlinePlayer = onlinePlayerClass.getDeclaredConstructor().newInstance((Integer)size, clientSocket);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Unable to instantiate players");
|
||||||
|
}
|
||||||
|
|
||||||
|
localPlayer.isServer = localPlayerIsServer;
|
||||||
|
onlinePlayer.isServer = !localPlayerIsServer;
|
||||||
|
|
||||||
|
startGameWithInstancedPlayers(localPlayer, onlinePlayer);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// TODO: received invalid package / package out of order
|
throw new RuntimeException("Unexpected Package received before game initialisation");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// TODO: instantiate local player, set server / client roles
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* finds the largest common version in two lists of version strings
|
||||||
|
* @return null if no common versions are found
|
||||||
|
*/
|
||||||
|
public String findMostRecentVersion(List<String> versions1, List<String> versions2) {
|
||||||
|
if (versions1 == null || versions2 == null) return null;
|
||||||
|
String largestCommonVersion = null;
|
||||||
|
for (String v1 : versions1) {
|
||||||
|
if (!checkVersionString(v1)) continue;
|
||||||
|
|
||||||
|
for (String v2 : versions2) {
|
||||||
|
if (!checkVersionString(v2)) continue;
|
||||||
|
|
||||||
|
// strings within the lists must be equal
|
||||||
|
// if no largest common version has been found or currently checked version is larger than
|
||||||
|
// previous largest common version, new largest version has been found
|
||||||
|
if (compareVersions(v1, v2) == 0 && (largestCommonVersion == null || compareVersions(v1, largestCommonVersion) >= 1)) {
|
||||||
|
largestCommonVersion = v1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return largestCommonVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* compares two version strings
|
||||||
|
* @return
|
||||||
|
* 0 if versions are equal
|
||||||
|
* 1 if version1 is more recent than version2
|
||||||
|
* -1 otherwise
|
||||||
|
*/
|
||||||
|
public int compareVersions(String version1, String version2) {
|
||||||
|
if (!checkVersionString(version1) || !checkVersionString(version2)) {
|
||||||
|
throw new IllegalArgumentException("Version is not valid version string");
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] version1Split = version1.split("\\.");
|
||||||
|
String[] version2Split = version2.split("\\.");
|
||||||
|
|
||||||
|
for (int i = 0; i < version1Split.length; i++) {
|
||||||
|
int v1 = Integer.parseInt(version1Split[i]);
|
||||||
|
int v2 = Integer.parseInt(version2Split[i]);
|
||||||
|
|
||||||
|
if (v1 == v2) continue;
|
||||||
|
if (v1 > v2) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks if a provided string matches the format of a version number
|
||||||
|
*/
|
||||||
|
public boolean checkVersionString(String versionString) {
|
||||||
|
return versionString != null && versionString.matches("\\d+\\.\\d+\\.\\d+");
|
||||||
|
}
|
||||||
|
|
||||||
public void startLocalGame(Class<? extends LocalPlayer> localPlayerClass, Class<? extends AiPlayer> enemyClass, int size) {
|
public void startLocalGame(Class<? extends LocalPlayer> localPlayerClass, Class<? extends AiPlayer> enemyClass, int size) {
|
||||||
|
|
||||||
LocalPlayer localPlayer;
|
LocalPlayer localPlayer;
|
||||||
|
@ -52,10 +163,20 @@ public class GameController {
|
||||||
aiPlayer = enemyClass.getDeclaredConstructor().newInstance();
|
aiPlayer = enemyClass.getDeclaredConstructor().newInstance();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return;
|
throw new RuntimeException("Unable to instantiate players");
|
||||||
}
|
}
|
||||||
localPlayer.setEnemy(aiPlayer);
|
|
||||||
aiPlayer.setEnemy(localPlayer);
|
localPlayer.createBoard(size);
|
||||||
|
aiPlayer.createBoard(size);
|
||||||
|
|
||||||
|
startGameWithInstancedPlayers(localPlayer, aiPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startGameWithInstancedPlayers(LocalPlayer p1, Player p2) {
|
||||||
|
p1.setEnemy(p2);
|
||||||
|
p2.setEnemy(p1);
|
||||||
|
|
||||||
|
// TODO: frontend configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -34,4 +34,8 @@ public class HitResponse {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.getPoint().toString() + " " + this.type.ordinal();
|
return this.getPoint().toString() + " " + this.type.ordinal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HitResponseType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
|
|
||||||
public class HumanPlayer extends LocalPlayer {
|
public class HumanPlayer extends LocalPlayer {
|
||||||
|
|
||||||
public HumanPlayer(int size) {
|
|
||||||
super(size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public class LocalPlayer extends Player {
|
public class LocalPlayer extends Player {
|
||||||
|
|
||||||
LocalPlayer(int size) {
|
public LocalPlayer(){
|
||||||
super(size);
|
super();
|
||||||
|
Random random = new Random();
|
||||||
|
this.myCoin = random.nextBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -9,14 +13,46 @@ public class LocalPlayer extends Player {
|
||||||
HitResponse hitResponse = board.getHitResponsOnPoint(point);
|
HitResponse hitResponse = board.getHitResponsOnPoint(point);
|
||||||
if (!(hitResponse == null)){
|
if (!(hitResponse == null)){
|
||||||
enemy.receiveHit(hitResponse);
|
enemy.receiveHit(hitResponse);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
enemy.receiveHit(this.board.hit(point));
|
hitResponse = this.board.hit(point);
|
||||||
|
enemy.receiveHit(hitResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (hitResponse.getType()) {
|
||||||
|
case HIT, SUNK -> this.myTurn = false;
|
||||||
|
case MISS -> this.myTurn = true;
|
||||||
|
case VICTORY -> System.out.println("Game Over"); //TODO Was halt bei victory passiert ist hier wurder verloheren
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void receiveHit(HitResponse hitResponse) {
|
public synchronized void receiveHit(HitResponse hitResponse) {
|
||||||
enemy.board.addHits(hitResponse);
|
enemy.board.addHits(hitResponse);
|
||||||
|
switch (hitResponse.getType()) {
|
||||||
|
case HIT, SUNK -> this.myTurn = true;
|
||||||
|
case MISS -> this.myTurn = false;
|
||||||
|
case VICTORY -> System.out.println("Win"); // TODO was halt beim victory passier ist hier wurde gewonnen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void receiveCoin(boolean coin) {
|
||||||
|
if (!this.haseReceivedCoin) {
|
||||||
|
boolean result = coin ^ this.myCoin; // XOR
|
||||||
|
this.myTurn = result == this.isServer;
|
||||||
|
this.haseReceivedCoin = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendCoin() {
|
||||||
|
enemy.receiveCoin(this.myCoin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void shoot(Point point){
|
||||||
|
this.myTurn = false;
|
||||||
|
enemy.receiveShoot(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,9 +1,12 @@
|
||||||
public abstract class OnlinePlayer extends Player implements AsyncSocketListener{
|
public abstract class OnlinePlayer extends Player implements AsyncSocketListener{
|
||||||
protected AsyncSocket socket;
|
protected AsyncSocket socket;
|
||||||
|
protected int wantedBoardSize;
|
||||||
|
|
||||||
|
protected boolean hasReceivedCoinPackage;
|
||||||
|
|
||||||
public OnlinePlayer(int size, AsyncSocket socket) {
|
public OnlinePlayer(int size, AsyncSocket socket) {
|
||||||
super(size);
|
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
|
this.wantedBoardSize = size;
|
||||||
socket.setHandler(this);
|
socket.setHandler(this);
|
||||||
//TODO Auto-generated constructor stub
|
//TODO Auto-generated constructor stub
|
||||||
}
|
}
|
||||||
|
@ -16,4 +19,7 @@ public abstract class OnlinePlayer extends Player implements AsyncSocketListener
|
||||||
@Override
|
@Override
|
||||||
public abstract void receiveHit(HitResponse hitResponse);
|
public abstract void receiveHit(HitResponse hitResponse);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract void receiveCoin(boolean coin);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,34 @@ public class OnlinePlayer_1_1_0 extends OnlinePlayer {
|
||||||
public void receive(String message) {
|
public void receive(String message) {
|
||||||
SocketPackage p = new SocketPackage(message);
|
SocketPackage p = new SocketPackage(message);
|
||||||
|
|
||||||
// TODO: parse package
|
List<String> data = p.splitData();
|
||||||
switch (p.getName()) {
|
switch (p.getName()) {
|
||||||
|
case "IAM":
|
||||||
|
if (data.size() < 2) break;
|
||||||
|
if (this.board != null) break;
|
||||||
|
|
||||||
|
int semester = Integer.parseInt(data.get(0));
|
||||||
|
String username = p.getData().substring(data.get(0).length() + 1);
|
||||||
|
|
||||||
|
int usedBoardSize = Math.min(GameController.semesterToBoardSize(semester), this.wantedBoardSize);
|
||||||
|
|
||||||
|
this.setName(username);
|
||||||
|
this.createBoard(usedBoardSize);
|
||||||
|
this.enemy.createBoard(usedBoardSize);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
// TODO: IAMU
|
||||||
|
|
||||||
|
case "COIN":
|
||||||
|
if(!this.hasReceivedCoinPackage && (p.getData().equals("1") || p.getData().equals("0"))){
|
||||||
|
this.myCoin = p.getData().equals("1");
|
||||||
|
enemy.receiveCoin(this.myCoin);
|
||||||
|
this.hasReceivedCoinPackage = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
case "SHOOT":
|
case "SHOOT":
|
||||||
if (Point.isValidSyntax(p.getData())){
|
if (Point.isValidSyntax(p.getData())){
|
||||||
Point point = new Point(p.getData());
|
Point point = new Point(p.getData());
|
||||||
|
@ -21,7 +47,6 @@ public class OnlinePlayer_1_1_0 extends OnlinePlayer {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "HIT":
|
case "HIT":
|
||||||
List<String> data = p.splitData();
|
|
||||||
if (data.size()==2){
|
if (data.size()==2){
|
||||||
Point point = new Point(data.get(0));
|
Point point = new Point(data.get(0));
|
||||||
int typeIndex = Integer.parseInt(data.get(1));
|
int typeIndex = Integer.parseInt(data.get(1));
|
||||||
|
@ -50,4 +75,12 @@ public class OnlinePlayer_1_1_0 extends OnlinePlayer {
|
||||||
public synchronized void receiveHit(HitResponse hitResponse) {
|
public synchronized void receiveHit(HitResponse hitResponse) {
|
||||||
super.socket.send(new SocketPackage("HIT", hitResponse.toString()));
|
super.socket.send(new SocketPackage("HIT", hitResponse.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void receiveCoin(boolean coin) {
|
||||||
|
if (!this.haseReceivedCoin) {
|
||||||
|
super.socket.send(new SocketPackage("COIN", String.valueOf(coin ? 1 : 0)));
|
||||||
|
this.haseReceivedCoin = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public abstract class Player {
|
public abstract class Player {
|
||||||
protected boolean myTurn;
|
protected boolean myTurn;
|
||||||
|
@ -6,8 +7,18 @@ public abstract class Player {
|
||||||
protected Player enemy;
|
protected Player enemy;
|
||||||
protected String name;
|
protected String name;
|
||||||
protected Board board;
|
protected Board board;
|
||||||
|
protected boolean myCoin;
|
||||||
|
|
||||||
public Player(int size) {
|
protected boolean sendCoin;
|
||||||
|
|
||||||
|
protected boolean haseReceivedCoin;
|
||||||
|
|
||||||
|
public Player() {
|
||||||
|
this.haseReceivedCoin = false;
|
||||||
|
this.sendCoin = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createBoard(int size) {
|
||||||
this.board = new Board(size);
|
this.board = new Board(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,9 +26,7 @@ public abstract class Player {
|
||||||
|
|
||||||
public abstract void receiveHit(HitResponse hitResponse);
|
public abstract void receiveHit(HitResponse hitResponse);
|
||||||
|
|
||||||
public void click(Point point) {
|
public abstract void shoot(Point point);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void beginTrun() {
|
public void beginTrun() {
|
||||||
|
|
||||||
|
@ -26,4 +35,14 @@ public abstract class Player {
|
||||||
public void setEnemy(Player enemy) {
|
public void setEnemy(Player enemy) {
|
||||||
this.enemy = enemy;
|
this.enemy = enemy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public abstract void receiveCoin(boolean coin);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
|
|
||||||
public class SpecificAiPlayerEasy extends AiPlayer{
|
public class SpecificAiPlayerEasy extends AiPlayer{
|
||||||
|
|
||||||
public SpecificAiPlayerEasy(int size) {
|
|
||||||
super(size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
|
|
||||||
public class SpecificAiPlayerHard extends AiPlayer{
|
public class SpecificAiPlayerHard extends AiPlayer{
|
||||||
|
|
||||||
public SpecificAiPlayerHard(int size) {
|
|
||||||
super(size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,6 @@ public class SpecificAiPlayerMedium extends AiPlayer{
|
||||||
|
|
||||||
private List<Point> hitsQueue = new ArrayList<>();
|
private List<Point> hitsQueue = new ArrayList<>();
|
||||||
|
|
||||||
public SpecificAiPlayerMedium(int size) {
|
|
||||||
super(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void AiShoot() {
|
public void AiShoot() {
|
||||||
Point nextShot = ComputeNextShot();
|
Point nextShot = ComputeNextShot();
|
||||||
|
|
Loading…
Reference in New Issue