diff --git a/Client/src/res/TicTacToe_Client.css b/Client/src/game/TicTacToe_Client.css similarity index 100% rename from Client/src/res/TicTacToe_Client.css rename to Client/src/game/TicTacToe_Client.css diff --git a/Client/src/res/TicTacToe_Grid.png b/Client/src/game/TicTacToe_Grid.png similarity index 100% rename from Client/src/res/TicTacToe_Grid.png rename to Client/src/game/TicTacToe_Grid.png diff --git a/Client/src/render/Engine.java b/Client/src/render/Engine.java index ac27a7f..38d45b0 100644 --- a/Client/src/render/Engine.java +++ b/Client/src/render/Engine.java @@ -11,6 +11,7 @@ import javafx.scene.text.FontWeight; import javafx.scene.text.Text; import javafx.stage.Stage; + import java.awt.*; import java.util.concurrent.CountDownLatch; @@ -38,22 +39,9 @@ public class Engine extends Application { grid.setVgap(75); } - private Scene setStartingScene(){ - scene = new Scene(grid, 900, 900); - grid.add(new javafx.scene.control.Label("Your Username"), 0, 0); - grid.add(new javafx.scene.control.TextField(), 1,0); - scene.setOnMousePressed(new EventHandler() { - @Override - public void handle(MouseEvent mouseEvent) { - - } - }); - return scene; - } - private Scene setPlayingScene() { scene = new Scene(grid, 900, 900); - scene.getStylesheets().add("res/TicTacToe_Client.css"); + scene.getStylesheets().add("game/TicTacToe_Client.css"); scene.setOnMousePressed(new EventHandler() { @Override public void handle(MouseEvent event) { @@ -149,7 +137,8 @@ public class Engine extends Application { primaryStage.setTitle("Test"); primaryStage.setResizable(true); this.initializeGrid(); - primaryStage.setScene(this.setPlayingScene()); + this.scene = this.setPlayingScene(); + primaryStage.setScene(scene); primaryStage.sizeToScene(); primaryStage.show(); diff --git a/Client/src/res/TicTacToe_Client_UML.png b/Client/src/res/TicTacToe_Client_UML.png deleted file mode 100644 index 47f65a9..0000000 Binary files a/Client/src/res/TicTacToe_Client_UML.png and /dev/null differ diff --git a/Server/res/TicTacToe_Server_UML.png b/Server/res/TicTacToe_Server_UML.png deleted file mode 100644 index 1cdf991..0000000 Binary files a/Server/res/TicTacToe_Server_UML.png and /dev/null differ diff --git a/Server/src/TicTacToe_Server.java b/Server/src/TicTacToe_Server.java index ca5f6aa..200670b 100644 --- a/Server/src/TicTacToe_Server.java +++ b/Server/src/TicTacToe_Server.java @@ -1,6 +1,6 @@ import logging.LogType; import logging.ServerLogger; -import res.TicTacToe_GameRules; +import game.TicTacToe_GameRules; import java.awt.*; import java.io.DataInputStream; @@ -201,12 +201,16 @@ public class TicTacToe_Server { sendGameState(); serverLogger.printLog("Trigger computer move", LogType.Log); ticTacToe_gameRules.makeComputerMove(); - outstreams.get(client).writeUTF("opponentMove"); - outstreams.get(client).flush(); - sendGameState(); + Thread.sleep(500); if (ticTacToe_gameRules.gameEnded()){ + sendGameState(); + Thread.sleep(1000); this.onGameEnd(); break; + } else { + outstreams.get(client).writeUTF("opponentMove"); + outstreams.get(client).flush(); + sendGameState(); } } @@ -217,6 +221,8 @@ public class TicTacToe_Server { } } catch (IOException e) { e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); } break; diff --git a/Server/src/ai/MinMax.java b/Server/src/ai/MinMax.java new file mode 100644 index 0000000..3255ab6 --- /dev/null +++ b/Server/src/ai/MinMax.java @@ -0,0 +1,208 @@ +package ai; +// Java program to find the +// next optimal move for a player +public class MinMax +{ + static char player = 'o', opponent = 'x'; + + // This function returns true if there are moves +// remaining on the board. It returns false if +// there are no moves left to play. + static Boolean isMovesLeft(char board[][]) + { + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + if (board[i][j] == '-') + return true; + return false; + } + + // This is the evaluation function as discussed +// in the previous article ( http://goo.gl/sJgv68 ) + static int evaluate(char b[][]) + { + // Checking for Rows for X or O victory. + for (int row = 0; row < 3; row++) + { + if (b[row][0] == b[row][1] && + b[row][1] == b[row][2]) + { + if (b[row][0] == player) + return +10; + else if (b[row][0] == opponent) + return -10; + } + } + + // Checking for Columns for X or O victory. + for (int col = 0; col < 3; col++) + { + if (b[0][col] == b[1][col] && + b[1][col] == b[2][col]) + { + if (b[0][col] == player) + return +10; + + else if (b[0][col] == opponent) + return -10; + } + } + + // Checking for Diagonals for X or O victory. + if (b[0][0] == b[1][1] && b[1][1] == b[2][2]) + { + if (b[0][0] == player) + return +10; + else if (b[0][0] == opponent) + return -10; + } + + if (b[0][2] == b[1][1] && b[1][1] == b[2][0]) + { + if (b[0][2] == player) + return +10; + else if (b[0][2] == opponent) + return -10; + } + + // Else if none of them have won then return 0 + return 0; + } + + // This is the minimax function. It considers all +// the possible ways the game can go and returns +// the value of the board + static int minimax(char board[][], + int depth, Boolean isMax) + { + int score = evaluate(board); + + // If Maximizer has won the game + // return his/her evaluated score + if (score == 10) + return score; + + // If Minimizer has won the game + // return his/her evaluated score + if (score == -10) + return score; + + // If there are no more moves and + // no winner then it is a tie + if (isMovesLeft(board) == false) + return 0; + + // If this maximizer's move + if (isMax) + { + int best = -1000; + + // Traverse all cells + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + // Check if cell is empty + if (board[i][j]=='-') + { + // Make the move + board[i][j] = player; + + // Call minimax recursively and choose + // the maximum value + best = Math.max(best, minimax(board, + depth + 1, !isMax)); + + // Undo the move + board[i][j] = '-'; + } + } + } + return best; + } + + // If this minimizer's move + else + { + int best = 1000; + + // Traverse all cells + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + // Check if cell is empty + if (board[i][j] == '-') + { + // Make the move + board[i][j] = opponent; + + // Call minimax recursively and choose + // the minimum value + best = Math.min(best, minimax(board, + depth + 1, !isMax)); + + // Undo the move + board[i][j] = '-'; + } + } + } + return best; + } + } + + // This will return the best possible +// move for the player + public int findBestMove(char board[][]) + { + int bestVal = -1000; + int row = -1; + int col = -1; + + // Traverse all cells, evaluate minimax function + // for all empty cells. And return the cell + // with optimal value. + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + // Check if cell is empty + if (board[i][j] == '-') + { + // Make the move + board[i][j] = player; + + // compute evaluation function for this + // move. + int moveVal = minimax(board, 0, false); + + // Undo the move + board[i][j] = '-'; + + // If the value of the current move is + // more than the best value, then update + // best/ + if (moveVal > bestVal) + { + row = i; + col = j; + bestVal = moveVal; + } + } + } + } + return col*3+row; + } + + public char[][] convertBoard(String gameState){ + char board[][] = new char[3][3]; + for (int i = 0; i < gameState.length(); i++) { + int column = i / 3; + int row = i % 3; + board[row][column] = gameState.charAt(i); + } + return board; + } + +} + \ No newline at end of file diff --git a/Server/src/res/TicTacToe_GameRules.java b/Server/src/game/TicTacToe_GameRules.java similarity index 93% rename from Server/src/res/TicTacToe_GameRules.java rename to Server/src/game/TicTacToe_GameRules.java index a283c86..4b24963 100644 --- a/Server/src/res/TicTacToe_GameRules.java +++ b/Server/src/game/TicTacToe_GameRules.java @@ -1,18 +1,21 @@ -package res; +package game; + +import ai.MinMax; import java.awt.*; import java.nio.charset.StandardCharsets; import java.util.LinkedList; -import java.util.Random; public class TicTacToe_GameRules { private String gameState; private Integer[][] board; + private MinMax ai; Point startWin, endWin; public TicTacToe_GameRules(){ gameState = "---------"; + ai = new MinMax(); } public void resetGameState() { @@ -55,12 +58,8 @@ public class TicTacToe_GameRules { } public void makeComputerMove(){ - LinkedList emptySpaces = getEmptySpaces(); - if (emptySpaces.size() > 0) { - Random random = new Random(); - int index = emptySpaces.get(random.nextInt(emptySpaces.size())); - makeMoveOnBoard(index, 1); - } + int index = ai.findBestMove(ai.convertBoard(this.getGameState())); + makeMoveOnBoard(index, 1); } private LinkedList getEmptySpaces(){ diff --git a/UML/TicTacToe_Client_UML.png b/UML/TicTacToe_Client_UML.png index 47f65a9..6ef9d14 100644 Binary files a/UML/TicTacToe_Client_UML.png and b/UML/TicTacToe_Client_UML.png differ diff --git a/UML/TicTacToe_Server_UML.png b/UML/TicTacToe_Server_UML.png index 1cdf991..a13fe07 100644 Binary files a/UML/TicTacToe_Server_UML.png and b/UML/TicTacToe_Server_UML.png differ diff --git a/deployment/client/deployClient b/deployment/client/deployClient index 1157bce..6dbe2b4 100755 --- a/deployment/client/deployClient +++ b/deployment/client/deployClient @@ -1,6 +1,6 @@ #!/bin/sh cp ~/Code/ArcadeMachine/out/artifacts/Client_jar/Client.jar ~/Code/ArcadeMachine/deployment/client/package cd /var/www/html -scp * root@server:/var/www/html/ -scp files/* root@server:/var/www/html/files +scp index.css index.html root@server:/var/www/html/ +scp files/Client.jar files/startClient.bat root@server:/var/www/html/files ssh root@server systemctl restart apache2 \ No newline at end of file diff --git a/out/production/Client/res/TicTacToe_Client.css b/out/production/Client/game/TicTacToe_Client.css similarity index 100% rename from out/production/Client/res/TicTacToe_Client.css rename to out/production/Client/game/TicTacToe_Client.css diff --git a/out/production/Client/res/TicTacToe_Grid.png b/out/production/Client/game/TicTacToe_Grid.png similarity index 100% rename from out/production/Client/res/TicTacToe_Grid.png rename to out/production/Client/game/TicTacToe_Grid.png diff --git a/out/production/Client/res/TicTacToe_Client_UML.png b/out/production/Client/res/TicTacToe_Client_UML.png deleted file mode 100644 index 47f65a9..0000000 Binary files a/out/production/Client/res/TicTacToe_Client_UML.png and /dev/null differ diff --git a/out/production/Server/TicTacToe_Server_UML.png b/out/production/Server/TicTacToe_Server_UML.png deleted file mode 100644 index 1cdf991..0000000 Binary files a/out/production/Server/TicTacToe_Server_UML.png and /dev/null differ