Made game playable

This commit is contained in:
2021-02-21 23:01:30 +01:00
parent 758d9fc235
commit 8fc1867d9e
9 changed files with 653 additions and 21 deletions

View File

@@ -1,3 +1,3 @@
Manifest-Version: 1.0
Main-Class: networking.Server
Main-Class: networking.SinglePlayerServer

View File

@@ -1,10 +1,15 @@
package game;
import java.awt.*;
import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.Random;
public class TicTacToe_Server {
private String gameState;
private Integer[][] board;
Point startWin, endWin;
public TicTacToe_Server(){
gameState = "---------";
@@ -18,24 +23,130 @@ public class TicTacToe_Server {
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) {
int column = Double.valueOf(input.split("\\|")[0]).intValue() / 300;
int row = Double.valueOf(input.split("\\|")[1]).intValue() / 300;
int index = column * 3 + row;
if (isLegalMove(column, row)) {
byte[] gameStateBytes = gameState.getBytes();
gameStateBytes[index] = (byte) 'x';
gameState = new String(gameStateBytes, StandardCharsets.UTF_8);
makeMoveOnBoard(index, 0);
return 200;
} else {
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){
int index = column * 3 + row;
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};
}
}

View 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();
}
}

View 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();
}
}

View 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;
}
}