Made game playable
This commit is contained in:
@@ -8,5 +8,6 @@
|
|||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" exported="" name="JavaFx" level="project" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
@@ -6,16 +6,22 @@ import javafx.geometry.Pos;
|
|||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.shape.Line;
|
||||||
import javafx.scene.text.Font;
|
import javafx.scene.text.Font;
|
||||||
import javafx.scene.text.FontWeight;
|
import javafx.scene.text.FontWeight;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import networking.Client;
|
import networking.Client;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
public class TicTacToe_Client extends Application {
|
public class TicTacToe_Client extends Application {
|
||||||
|
|
||||||
GridPane grid;
|
GridPane grid;
|
||||||
Client client;
|
Client client;
|
||||||
|
Scene scene;
|
||||||
|
|
||||||
private void initializeGrid(){
|
private void initializeGrid(){
|
||||||
grid = new GridPane();
|
grid = new GridPane();
|
||||||
@@ -23,7 +29,6 @@ public class TicTacToe_Client extends Application {
|
|||||||
grid.setAlignment(Pos.CENTER);
|
grid.setAlignment(Pos.CENTER);
|
||||||
grid.setHgap(150);
|
grid.setHgap(150);
|
||||||
grid.setVgap(75);
|
grid.setVgap(75);
|
||||||
grid.setGridLinesVisible(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawCross(int column, int row){
|
private void drawCross(int column, int row){
|
||||||
@@ -39,8 +44,8 @@ public class TicTacToe_Client extends Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void drawEmptyField(int column, int row) {
|
private void drawEmptyField(int column, int row) {
|
||||||
Text emptyField = new Text(" ");
|
Text emptyField = new Text(" ");
|
||||||
emptyField.setFont(Font.font("Tahoma", FontWeight.NORMAL, 200));
|
emptyField.setFont(Font.font("Tahoma", FontWeight.NORMAL, 220));
|
||||||
grid.add(emptyField, column, row);
|
grid.add(emptyField, column, row);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,27 +69,49 @@ public class TicTacToe_Client extends Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Scene setScene(){
|
private Scene setScene(){
|
||||||
Scene scene = new Scene(grid, 900, 900);
|
scene = new Scene(grid, 900, 900);
|
||||||
scene.getStylesheets().add
|
scene.getStylesheets().add
|
||||||
(TicTacToe_Client.class.getResource("TicTacToe_Client.css").toExternalForm());
|
(TicTacToe_Client.class.getResource("TicTacToe_Client.css").toExternalForm());
|
||||||
scene.setOnMousePressed(new EventHandler<MouseEvent>() {
|
scene.setOnMousePressed(new EventHandler<MouseEvent>() {
|
||||||
@Override
|
@Override
|
||||||
public void handle(MouseEvent event) {
|
public void handle(MouseEvent event) {
|
||||||
client.sendToServer("update");
|
onMouseClick(event);
|
||||||
client.sendToServer(String.format("%f|%f", event.getX(), event.getY()));
|
|
||||||
String gameState = client.getResponse();
|
|
||||||
if (gameState.length() == 9) {
|
|
||||||
drawBoard(gameState);
|
|
||||||
} else {
|
|
||||||
int column = (int) event.getX() / 300;
|
|
||||||
int row = (int) event.getY() / 300;
|
|
||||||
System.err.printf("You are not allowed to place at %f|%f%n", column, row);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return scene;
|
return scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onMouseClick(MouseEvent event){
|
||||||
|
client.sendToServer("update");
|
||||||
|
client.sendToServer(String.format("%f|%f", event.getX(), event.getY()));
|
||||||
|
String gameState = client.getResponse();
|
||||||
|
if (gameState.length() == 9) {
|
||||||
|
drawBoard(gameState);
|
||||||
|
if (!client.getGameEnded()){
|
||||||
|
gameState = client.getResponse();
|
||||||
|
drawBoard(gameState);
|
||||||
|
} else {
|
||||||
|
LinkedList<Integer> winCoordinates = new LinkedList<>();
|
||||||
|
String response = client.getResponse();
|
||||||
|
for (String s: Arrays.copyOfRange(response.split(";"),0, 4)) {
|
||||||
|
winCoordinates.add(Integer.valueOf(s) * 300);
|
||||||
|
}
|
||||||
|
this.drawWinningLine(winCoordinates);
|
||||||
|
client.exitProcess();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int column = (int) event.getX() / 300;
|
||||||
|
int row = (int) event.getY() / 300;
|
||||||
|
System.err.printf("You are not allowed to place at %d|%d%n", column, row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawWinningLine(LinkedList<Integer>winCoordinates){
|
||||||
|
Line winningLine = new Line(winCoordinates.get(0), winCoordinates.get(1), winCoordinates.get(2), winCoordinates.get(3));
|
||||||
|
winningLine.setFill(Color.RED);
|
||||||
|
grid.add(winningLine, winCoordinates.get(0)/300, winCoordinates.get(1)/300, 3, 3);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) {
|
public void start(Stage primaryStage) {
|
||||||
client = new Client("localhost", 2589, "TestClient");
|
client = new Client("localhost", 2589, "TestClient");
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package networking;
|
|||||||
import logging.ClientLogger;
|
import logging.ClientLogger;
|
||||||
import logging.LogType;
|
import logging.LogType;
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -75,12 +74,29 @@ public class Client {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getBooleanResponse(String value){
|
||||||
|
try {
|
||||||
|
boolean booleanResponse = in.readBoolean();
|
||||||
|
clientLogger.printLog(String.format(value + ": %b", booleanResponse), serverName, booleanResponse, LogType.Log);
|
||||||
|
return booleanResponse;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public String getGameState() {
|
public String getGameState() {
|
||||||
this.sendToServer("gameState");
|
this.sendToServer("gameState");
|
||||||
String gameState = this.getResponse();
|
String gameState = this.getResponse();
|
||||||
return gameState;
|
return gameState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getGameEnded() {
|
||||||
|
this.sendToServer("gameEnded");
|
||||||
|
boolean gameEnded = this.getBooleanResponse("Game ended");
|
||||||
|
return gameEnded;
|
||||||
|
}
|
||||||
|
|
||||||
public void exitProcess(){
|
public void exitProcess(){
|
||||||
try {
|
try {
|
||||||
out.writeUTF("exit()");
|
out.writeUTF("exit()");
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
Manifest-Version: 1.0
|
Manifest-Version: 1.0
|
||||||
Main-Class: networking.Server
|
Main-Class: networking.SinglePlayerServer
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
Manifest-Version: 1.0
|
Manifest-Version: 1.0
|
||||||
Main-Class: networking.Server
|
Main-Class: networking.SinglePlayerServer
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
package game;
|
package game;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public class TicTacToe_Server {
|
public class TicTacToe_Server {
|
||||||
|
|
||||||
private String gameState;
|
private String gameState;
|
||||||
|
private Integer[][] board;
|
||||||
|
Point startWin, endWin;
|
||||||
|
|
||||||
public TicTacToe_Server(){
|
public TicTacToe_Server(){
|
||||||
gameState = "---------";
|
gameState = "---------";
|
||||||
@@ -18,24 +23,130 @@ public class TicTacToe_Server {
|
|||||||
return gameState;
|
return gameState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void makeMoveOnBoard(int index, int player){
|
||||||
|
byte[] gameStateBytes = gameState.getBytes();
|
||||||
|
if (player == 0){
|
||||||
|
gameStateBytes[index] = (byte) 'x';
|
||||||
|
} else if (player == 1) {
|
||||||
|
gameStateBytes[index] = (byte) 'o';
|
||||||
|
}
|
||||||
|
gameState = new String(gameStateBytes, StandardCharsets.UTF_8);
|
||||||
|
board = this.convertToNumbers(gameState);
|
||||||
|
}
|
||||||
|
|
||||||
public int makeClientMove(String input) {
|
public int makeClientMove(String input) {
|
||||||
int column = Double.valueOf(input.split("\\|")[0]).intValue() / 300;
|
int column = Double.valueOf(input.split("\\|")[0]).intValue() / 300;
|
||||||
int row = Double.valueOf(input.split("\\|")[1]).intValue() / 300;
|
int row = Double.valueOf(input.split("\\|")[1]).intValue() / 300;
|
||||||
int index = column * 3 + row;
|
int index = column * 3 + row;
|
||||||
|
|
||||||
if (isLegalMove(column, row)) {
|
if (isLegalMove(column, row)) {
|
||||||
byte[] gameStateBytes = gameState.getBytes();
|
makeMoveOnBoard(index, 0);
|
||||||
gameStateBytes[index] = (byte) 'x';
|
|
||||||
gameState = new String(gameStateBytes, StandardCharsets.UTF_8);
|
|
||||||
return 200;
|
return 200;
|
||||||
} else {
|
} else {
|
||||||
return 404;
|
return 404;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void makeServerMove(){
|
||||||
|
LinkedList<Integer> emptySpaces = getEmptySpaces();
|
||||||
|
if (emptySpaces.size() > 0) {
|
||||||
|
Random random = new Random();
|
||||||
|
int index = emptySpaces.get(random.nextInt(emptySpaces.size()));
|
||||||
|
makeMoveOnBoard(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LinkedList<Integer> getEmptySpaces(){
|
||||||
|
LinkedList<Integer> emptySpaces = new LinkedList<>();
|
||||||
|
for (int column = 0; column < 3; column++){
|
||||||
|
for (int row = 0; row < 3; row++){
|
||||||
|
if (isLegalMove(column, row)){
|
||||||
|
emptySpaces.add(column * 3 + row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return emptySpaces;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isLegalMove(int column, int row){
|
private boolean isLegalMove(int column, int row){
|
||||||
int index = column * 3 + row;
|
int index = column * 3 + row;
|
||||||
return gameState.charAt(index) == '-';
|
return gameState.charAt(index) == '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
private Integer[][] convertToNumbers(String gameState){
|
||||||
|
Integer[][] board = new Integer[3][3];
|
||||||
|
for (int i = 0; i < 3; i++){
|
||||||
|
for (int k = 0; k < 3; k++){
|
||||||
|
char currentChar = gameState.charAt(i*3+k);
|
||||||
|
if (currentChar == 'x'){
|
||||||
|
board[i][k] = 1;
|
||||||
|
} else if (currentChar == 'o'){
|
||||||
|
board[i][k] = -1;
|
||||||
|
} else if (currentChar == '-'){
|
||||||
|
board[i][k] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return board;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean diagonalWin(){
|
||||||
|
int sumLeftUp = 0;
|
||||||
|
int sumLeftDown = 0;
|
||||||
|
for (int i = 0; i < 3; i++){
|
||||||
|
sumLeftUp += board[i][i];
|
||||||
|
sumLeftDown += board[i][2-i];
|
||||||
|
}
|
||||||
|
if (sumLeftDown == 3 || sumLeftDown == -3){
|
||||||
|
startWin = new Point(2,0);
|
||||||
|
endWin = new Point(0,2);
|
||||||
|
return true;
|
||||||
|
} else if (sumLeftUp == 3 || sumLeftUp == -3){
|
||||||
|
startWin = new Point(0,0);
|
||||||
|
endWin = new Point(2,2);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean horizontalWin(){
|
||||||
|
for (int row = 0; row < 3; row++){
|
||||||
|
int sum = 0;
|
||||||
|
for (int column = 0; column < 3; column++){
|
||||||
|
sum += board[row][column];
|
||||||
|
}
|
||||||
|
if (sum == 3 || sum == -3){
|
||||||
|
startWin = new Point(row, 0);
|
||||||
|
endWin = new Point(row, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean verticalWin(){
|
||||||
|
for (int column = 0; column < 3; column++){
|
||||||
|
int sum = 0;
|
||||||
|
for (int row = 0; row < 3; row++){
|
||||||
|
sum += board[row][column];
|
||||||
|
}
|
||||||
|
if (sum == 3 || sum == -3){
|
||||||
|
startWin = new Point(0, column);
|
||||||
|
endWin = new Point(2, column);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean gameEnded(){
|
||||||
|
return horizontalWin() || verticalWin() || diagonalWin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Point[] getWinCoordinates(){
|
||||||
|
return new Point[]{startWin, endWin};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
185
Server/src/networking/MultiPlayerServer.java
Normal file
185
Server/src/networking/MultiPlayerServer.java
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
package networking;
|
||||||
|
|
||||||
|
import game.TicTacToe_Server;
|
||||||
|
import logging.LogType;
|
||||||
|
import logging.ServerLogger;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
public class MultiPlayerServer {
|
||||||
|
private ServerSocket serverSocket;
|
||||||
|
private HashMap<Integer, Socket> clients;
|
||||||
|
private HashMap<Socket, String> clientNames;
|
||||||
|
private HashMap<Socket, DataOutputStream> outstreams;
|
||||||
|
private HashMap<Socket, DataInputStream> instreams;
|
||||||
|
private TicTacToe_Server ticTacToe_server;
|
||||||
|
private ServerLogger serverLogger;
|
||||||
|
private Scanner scanner;
|
||||||
|
private int requiredConnections;
|
||||||
|
|
||||||
|
public MultiPlayerServer(int port) {
|
||||||
|
try {
|
||||||
|
serverSocket = new ServerSocket(port);
|
||||||
|
clients = new HashMap<>();
|
||||||
|
clientNames = new HashMap<>();
|
||||||
|
outstreams = new HashMap<>();
|
||||||
|
instreams = new HashMap<>();
|
||||||
|
ticTacToe_server = new TicTacToe_Server();
|
||||||
|
scanner = new Scanner(System.in);
|
||||||
|
serverLogger = new ServerLogger();
|
||||||
|
requiredConnections = 2;
|
||||||
|
|
||||||
|
serverLogger.printLog("Server started successfully", LogType.Log);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connectClients() {
|
||||||
|
try {
|
||||||
|
int id = 0;
|
||||||
|
serverLogger.printLog(String.format("Waiting for %d clients to connect ...", requiredConnections), LogType.Log);
|
||||||
|
while (clients.size() < requiredConnections) {
|
||||||
|
Socket momentaryClient = serverSocket.accept();
|
||||||
|
clients.put(id, momentaryClient);
|
||||||
|
outstreams.put(momentaryClient, new DataOutputStream(momentaryClient.getOutputStream()));
|
||||||
|
instreams.put(momentaryClient, new DataInputStream(momentaryClient.getInputStream()));
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handshake() {
|
||||||
|
for (Socket client : clients.values()) {
|
||||||
|
try {
|
||||||
|
int handshakeValue = instreams.get(client).readInt();
|
||||||
|
if (handshakeValue == 165313125) {
|
||||||
|
outstreams.get(client).writeInt(200);
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
clientNames.put(client, instreams.get(client).readUTF());
|
||||||
|
outstreams.get(client).writeUTF(serverSocket.getInetAddress().getHostAddress() + ":" + serverSocket.getLocalPort());
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog(String.format("%s got connected", clientNames.get(client)), LogType.Log);
|
||||||
|
} else {
|
||||||
|
outstreams.get(client).writeInt(403);
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ticTacToe_gameloop() {
|
||||||
|
for (Socket client : clients.values()) {
|
||||||
|
try {
|
||||||
|
while (!client.isClosed()) {
|
||||||
|
String message = instreams.get(client).readUTF();
|
||||||
|
serverLogger.printLog(message, clientNames.get(client), LogType.Message);
|
||||||
|
outstreams.get(client).writeInt(200);
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog("Sent verification code", clientNames.get(client), LogType.Log);
|
||||||
|
this.gameFlow(message, client);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
try {
|
||||||
|
client.close();
|
||||||
|
} catch (IOException ioException) {
|
||||||
|
ioException.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void gameFlow(String input, Socket client) {
|
||||||
|
switch (input) {
|
||||||
|
case "gameState":
|
||||||
|
try {
|
||||||
|
outstreams.get(client).writeUTF(ticTacToe_server.getGameState());
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog("Sent gameState", clientNames.get(client), LogType.Log);
|
||||||
|
break;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
case "update":
|
||||||
|
try {
|
||||||
|
String position = instreams.get(client).readUTF();
|
||||||
|
serverLogger.printLog(position, clientNames.get(client), LogType.Message);
|
||||||
|
outstreams.get(client).writeInt(200);
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog("Sent verification code", clientNames.get(client), LogType.Log);
|
||||||
|
int verificationCode = ticTacToe_server.makeClientMove(position);
|
||||||
|
if (verificationCode == 200) {
|
||||||
|
String gameState = ticTacToe_server.getGameState();
|
||||||
|
outstreams.get(client).writeUTF(gameState);
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog(String.format("Sent gameState: %s", gameState), clientNames.get(client), LogType.Log);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
outstreams.get(client).writeUTF(" ");
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog(String.format("Move is not allowed!"), clientNames.get(client), LogType.Error);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
case "gameEnded":
|
||||||
|
try {
|
||||||
|
boolean gameEnded = ticTacToe_server.gameEnded();
|
||||||
|
outstreams.get(client).writeBoolean(gameEnded);
|
||||||
|
if (gameEnded) {
|
||||||
|
String coordinates = "";
|
||||||
|
for (Point point : ticTacToe_server.getWinCoordinates()) {
|
||||||
|
coordinates += point.x + ";" + point.y + ";";
|
||||||
|
}
|
||||||
|
outstreams.get(client).writeUTF(coordinates);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
ticTacToe_server.makeServerMove();
|
||||||
|
String gameState = ticTacToe_server.getGameState();
|
||||||
|
outstreams.get(client).writeUTF(gameState);
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog(String.format("Sent gameState: %s", gameState), clientNames.get(client), LogType.Log);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
case "exit()":
|
||||||
|
try {
|
||||||
|
outstreams.get(client).writeInt(200);
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
outstreams.get(client).close();
|
||||||
|
instreams.get(client).close();
|
||||||
|
client.close();
|
||||||
|
serverLogger.printLog(String.format("%s closed the connection", clientNames.get(client)), LogType.Log);
|
||||||
|
break;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
MultiPlayerServer server = new MultiPlayerServer(2589);
|
||||||
|
server.connectClients();
|
||||||
|
server.handshake();
|
||||||
|
server.ticTacToe_gameloop();
|
||||||
|
}
|
||||||
|
}
|
||||||
185
Server/src/networking/SinglePlayerServer.java
Normal file
185
Server/src/networking/SinglePlayerServer.java
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
package networking;
|
||||||
|
|
||||||
|
import game.TicTacToe_Server;
|
||||||
|
import logging.LogType;
|
||||||
|
import logging.ServerLogger;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
public class SinglePlayerServer {
|
||||||
|
private ServerSocket serverSocket;
|
||||||
|
private HashMap<Integer, Socket> clients;
|
||||||
|
private HashMap<Socket, String> clientNames;
|
||||||
|
private HashMap<Socket, DataOutputStream> outstreams;
|
||||||
|
private HashMap<Socket, DataInputStream> instreams;
|
||||||
|
private TicTacToe_Server ticTacToe_server;
|
||||||
|
private ServerLogger serverLogger;
|
||||||
|
private Scanner scanner;
|
||||||
|
private int requiredConnections;
|
||||||
|
|
||||||
|
public SinglePlayerServer(int port){
|
||||||
|
try {
|
||||||
|
serverSocket = new ServerSocket(port);
|
||||||
|
clients = new HashMap<>();
|
||||||
|
clientNames = new HashMap<>();
|
||||||
|
outstreams = new HashMap<>();
|
||||||
|
instreams = new HashMap<>();
|
||||||
|
ticTacToe_server = new TicTacToe_Server();
|
||||||
|
scanner = new Scanner(System.in);
|
||||||
|
serverLogger = new ServerLogger();
|
||||||
|
requiredConnections = 1;
|
||||||
|
|
||||||
|
serverLogger.printLog("Server started successfully", LogType.Log);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connectClients(){
|
||||||
|
try {
|
||||||
|
int id = 0;
|
||||||
|
serverLogger.printLog(String.format("Waiting for %d clients to connect ...", requiredConnections), LogType.Log);
|
||||||
|
while(clients.size() < requiredConnections) {
|
||||||
|
Socket momentaryClient = serverSocket.accept();
|
||||||
|
clients.put(id, momentaryClient);
|
||||||
|
outstreams.put(momentaryClient, new DataOutputStream(momentaryClient.getOutputStream()));
|
||||||
|
instreams.put(momentaryClient, new DataInputStream(momentaryClient.getInputStream()));
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handshake(){
|
||||||
|
for (Socket client: clients.values()) {
|
||||||
|
try {
|
||||||
|
int handshakeValue = instreams.get(client).readInt();
|
||||||
|
if (handshakeValue == 165313125) {
|
||||||
|
outstreams.get(client).writeInt(200);
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
clientNames.put(client, instreams.get(client).readUTF());
|
||||||
|
outstreams.get(client).writeUTF(serverSocket.getInetAddress().getHostAddress()+":"+serverSocket.getLocalPort());
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog(String.format("%s got connected", clientNames.get(client)), LogType.Log);
|
||||||
|
} else {
|
||||||
|
outstreams.get(client).writeInt(403);
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ticTacToe_gameloop(){
|
||||||
|
for (Socket client: clients.values()) {
|
||||||
|
try {
|
||||||
|
while (!client.isClosed()) {
|
||||||
|
String message = instreams.get(client).readUTF();
|
||||||
|
serverLogger.printLog(message, clientNames.get(client), LogType.Message);
|
||||||
|
outstreams.get(client).writeInt(200);
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog("Sent verification code", clientNames.get(client), LogType.Log);
|
||||||
|
this.gameFlow(message, client);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
try {
|
||||||
|
client.close();
|
||||||
|
} catch (IOException ioException) {
|
||||||
|
ioException.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void gameFlow(String input, Socket client){
|
||||||
|
switch (input){
|
||||||
|
case "gameState":
|
||||||
|
try {
|
||||||
|
outstreams.get(client).writeUTF(ticTacToe_server.getGameState());
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog("Sent gameState", clientNames.get(client), LogType.Log);
|
||||||
|
break;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
case "update":
|
||||||
|
try {
|
||||||
|
String position = instreams.get(client).readUTF();
|
||||||
|
serverLogger.printLog(position, clientNames.get(client), LogType.Message);
|
||||||
|
outstreams.get(client).writeInt(200);
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog("Sent verification code", clientNames.get(client), LogType.Log);
|
||||||
|
int verificationCode = ticTacToe_server.makeClientMove(position);
|
||||||
|
if (verificationCode == 200) {
|
||||||
|
String gameState = ticTacToe_server.getGameState();
|
||||||
|
outstreams.get(client).writeUTF(gameState);
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog(String.format("Sent gameState: %s", gameState), clientNames.get(client), LogType.Log);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
outstreams.get(client).writeUTF(" ");
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog(String.format("Move is not allowed!"), clientNames.get(client), LogType.Error);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
case "gameEnded":
|
||||||
|
try {
|
||||||
|
boolean gameEnded = ticTacToe_server.gameEnded();
|
||||||
|
outstreams.get(client).writeBoolean(gameEnded);
|
||||||
|
if (gameEnded) {
|
||||||
|
String coordinates = "";
|
||||||
|
for (Point point: ticTacToe_server.getWinCoordinates()) {
|
||||||
|
coordinates += point.x + ";" + point.y + ";";
|
||||||
|
}
|
||||||
|
outstreams.get(client).writeUTF(coordinates);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
ticTacToe_server.makeServerMove();
|
||||||
|
String gameState = ticTacToe_server.getGameState();
|
||||||
|
outstreams.get(client).writeUTF(gameState);
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog(String.format("Sent gameState: %s", gameState), clientNames.get(client), LogType.Log);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
case "exit()":
|
||||||
|
try {
|
||||||
|
outstreams.get(client).writeInt(200);
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
outstreams.get(client).close();
|
||||||
|
instreams.get(client).close();
|
||||||
|
client.close();
|
||||||
|
serverLogger.printLog(String.format("%s closed the connection",clientNames.get(client)), LogType.Log);
|
||||||
|
break;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SinglePlayerServer server = new SinglePlayerServer(2589);
|
||||||
|
server.connectClients();
|
||||||
|
server.handshake();
|
||||||
|
server.ticTacToe_gameloop();
|
||||||
|
}
|
||||||
|
}
|
||||||
107
Server/src/tests/GenerateAllGameStates.java
Normal file
107
Server/src/tests/GenerateAllGameStates.java
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
package tests;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
public class GenerateAllGameStates {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
GenerateAllGameStates testGame = new GenerateAllGameStates();
|
||||||
|
LinkedList<String> gameStates = testGame.getAllPossibleBoards();
|
||||||
|
System.out.printf("All possible boards: %d%n", gameStates.size());
|
||||||
|
LinkedList<Integer[][]> gameStateBoards = new LinkedList<>();
|
||||||
|
for (String gameState: gameStates) {
|
||||||
|
gameStateBoards.add(testGame.convertToNumbers(gameState));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer[][] convertToNumbers(String gameState){
|
||||||
|
Integer[][] board = new Integer[3][3];
|
||||||
|
for (int i = 0; i < 3; i++){
|
||||||
|
for (int k = 0; k < 3; k++){
|
||||||
|
char currentChar = gameState.charAt(i*3+k);
|
||||||
|
if (currentChar == 'x'){
|
||||||
|
board[i][k] = 1;
|
||||||
|
} else if (currentChar == 'o'){
|
||||||
|
board[i][k] = -1;
|
||||||
|
} else if (currentChar == '-'){
|
||||||
|
board[i][k] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return board;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean diagonalWin(Integer[][] board){
|
||||||
|
int sumLeftUp = 0;
|
||||||
|
int sumLeftDown = 0;
|
||||||
|
for (int i = 0; i < 3; i++){
|
||||||
|
sumLeftUp += board[i][i];
|
||||||
|
sumLeftDown += board[i][2-i];
|
||||||
|
}
|
||||||
|
return (sumLeftDown == 3 || sumLeftDown == -3) || (sumLeftUp == 3 || sumLeftUp == -3);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean horizontalWin(Integer[][] board){
|
||||||
|
for (int row = 0; row < 3; row++){
|
||||||
|
int sum = 0;
|
||||||
|
for (int column = 0; column < 3; column++){
|
||||||
|
sum += board[row][column];
|
||||||
|
}
|
||||||
|
if (sum == 3 || sum == -3){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean verticalWin(Integer[][] board){
|
||||||
|
for (int column = 0; column < 3; column++){
|
||||||
|
int sum = 0;
|
||||||
|
for (int row = 0; row < 3; row++){
|
||||||
|
sum += board[row][column];
|
||||||
|
}
|
||||||
|
if (sum == 3 || sum == -3){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LinkedList<String> getAllPossibleBoards(){
|
||||||
|
LinkedList<String> possibleGameStates = new LinkedList<>();
|
||||||
|
|
||||||
|
String[] possibleChars = new String[]{"x","o","-"};
|
||||||
|
|
||||||
|
for (int c1r1 = 0; c1r1 < 3; c1r1++){
|
||||||
|
String s1 = possibleChars[c1r1];
|
||||||
|
for (int c1r2 = 0; c1r2 < 3; c1r2++){
|
||||||
|
String s2 = possibleChars[c1r2];
|
||||||
|
for (int c1r3 = 0; c1r3 < 3; c1r3++){
|
||||||
|
String s3 = possibleChars[c1r3];
|
||||||
|
for (int c2r1 = 0; c2r1 < 3; c2r1++){
|
||||||
|
String s4 = possibleChars[c2r1];
|
||||||
|
for (int c2r2 = 0; c2r2 < 3; c2r2++){
|
||||||
|
String s5 = possibleChars[c2r2];
|
||||||
|
for(int c2r3 = 0; c2r3 <3; c2r3++){
|
||||||
|
String s6 = possibleChars[c2r3];
|
||||||
|
for (int c3r1 = 0; c3r1 < 3; c3r1++){
|
||||||
|
String s7 = possibleChars[c3r1];
|
||||||
|
for (int c3r2 = 0; c3r2 < 3; c3r2++){
|
||||||
|
String s8 = possibleChars[c3r2];
|
||||||
|
for (int c3r3 = 0; c3r3 < 3; c3r3++){
|
||||||
|
String s9 = possibleChars[c3r3];
|
||||||
|
String gameState = s1+s2+s3+s4+s5+s6+s7+s8+s9;
|
||||||
|
possibleGameStates.add(gameState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return possibleGameStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user