From 5426e67f303ccb3350a3a9a3c21774ed6d73e362 Mon Sep 17 00:00:00 2001 From: Saima Bibi Date: Mon, 30 Dec 2024 18:51:19 +0500 Subject: [PATCH 1/4] Treated code & design smells, applied SOLID priniples --- java/Board.java | 3 +++ java/ComputerPlayer.java | 3 +++ java/Game.java | 3 +-- java/GameEngine.java | 3 +++ java/GameRules.java | 3 +++ java/HumanPlayer.java | 3 +++ java/Main.java | 3 +++ java/Player.java | 3 +++ 8 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 java/Board.java create mode 100644 java/ComputerPlayer.java create mode 100644 java/GameEngine.java create mode 100644 java/GameRules.java create mode 100644 java/HumanPlayer.java create mode 100644 java/Main.java create mode 100644 java/Player.java diff --git a/java/Board.java b/java/Board.java new file mode 100644 index 0000000..b2d7160 --- /dev/null +++ b/java/Board.java @@ -0,0 +1,3 @@ +public class Board { + +} diff --git a/java/ComputerPlayer.java b/java/ComputerPlayer.java new file mode 100644 index 0000000..074bebe --- /dev/null +++ b/java/ComputerPlayer.java @@ -0,0 +1,3 @@ +public class ComputerPlayer { + +} diff --git a/java/Game.java b/java/Game.java index d39eb43..9f27158 100755 --- a/java/Game.java +++ b/java/Game.java @@ -1,5 +1,4 @@ import java.util.Scanner; -import java.util.Arrays; import java.util.ArrayList; import java.util.concurrent.ThreadLocalRandom; @@ -125,7 +124,7 @@ public static int getBestMove() { } /** Return true if it is a draw (no more empty cell) */ - // TODO: maybe there is an easeir way to check this + public static boolean tie() { return board[0] != "0" && board[1] != "1" && diff --git a/java/GameEngine.java b/java/GameEngine.java new file mode 100644 index 0000000..0f005c3 --- /dev/null +++ b/java/GameEngine.java @@ -0,0 +1,3 @@ +public class GameEngine { + +} diff --git a/java/GameRules.java b/java/GameRules.java new file mode 100644 index 0000000..7a1dacc --- /dev/null +++ b/java/GameRules.java @@ -0,0 +1,3 @@ +public class GameRules { + +} diff --git a/java/HumanPlayer.java b/java/HumanPlayer.java new file mode 100644 index 0000000..d13c28a --- /dev/null +++ b/java/HumanPlayer.java @@ -0,0 +1,3 @@ +public class HumanPlayer { + +} diff --git a/java/Main.java b/java/Main.java new file mode 100644 index 0000000..c1b4223 --- /dev/null +++ b/java/Main.java @@ -0,0 +1,3 @@ +public class Main { + +} diff --git a/java/Player.java b/java/Player.java new file mode 100644 index 0000000..02e5a71 --- /dev/null +++ b/java/Player.java @@ -0,0 +1,3 @@ +public class Player { + +} From 236bc3f8b080675149dcc6a381acd9d78e6646cb Mon Sep 17 00:00:00 2001 From: Saima Bibi Date: Mon, 30 Dec 2024 19:00:51 +0500 Subject: [PATCH 2/4] implemented Game interface, GameEngine class, Board class & GameRules class --- java/Board.java | 29 ++++++++- java/Game.java | 147 ++----------------------------------------- java/GameEngine.java | 45 ++++++++++++- java/GameRules.java | 31 ++++++++- 4 files changed, 103 insertions(+), 149 deletions(-) diff --git a/java/Board.java b/java/Board.java index b2d7160..5e93401 100644 --- a/java/Board.java +++ b/java/Board.java @@ -1,3 +1,28 @@ -public class Board { - +class Board { + private String[] board; + + public Board() { + board = new String[]{"0", "1", "2", "3", "4", "5", "6", "7", "8"}; + } + + public void printBoard() { + System.out.println(" " + board[0] + " | " + board[1] + " | " + board[2] + + "\n===+===+===\n" + + " " + board[3] + " | " + board[4] + " | " + board[5] + + "\n===+===+===\n" + + " " + board[6] + " | " + board[7] + " | " + board[8] + "\n"); + } + + public boolean isValidMove(int spot) { + return !board[spot].equals("X") && !board[spot].equals("O"); + } + + public void markSpot(int spot, String symbol) { + board[spot] = symbol; + } + + public String[] getBoard() { + return board; + } } + diff --git a/java/Game.java b/java/Game.java index 9f27158..27384bc 100755 --- a/java/Game.java +++ b/java/Game.java @@ -1,145 +1,6 @@ -import java.util.Scanner; -import java.util.ArrayList; -import java.util.concurrent.ThreadLocalRandom; -/** - * Tic-Tac-Toe: TWo-player console version. - */ -public class Game { - // The game board and the game status - public static String[] board = {"0", "1", "2", "3", "4", "5", "6", "7", "8"}; - public static int currentState; // the current state of the game - public static String currentPlayer; // the current player - public static Scanner input = new Scanner(System.in); // the input Scanner - - /** The entry main method (the program starts here) */ - public static void main(String[] args) { - // Initialize the game-board and current status - initGame(); - printBoard(); - do { - getHumanSpot(); - if (!gameIsOver() && !tie()) { - evalBoard(); - } - } while (!gameIsOver() && !tie()); // repeat if not game-over - System.out.print("Game over\n"); - } - - /** Initializes the game */ - public static void initGame() { - currentState = 0; // "playing" or ready to play - currentPlayer = "X"; // cross plays first - } - - public static String nextPlayer() { - if (currentPlayer == "X") { - return "O"; - } else { - return "X"; - } - } - - /** Update global variables "board" and "currentPlayer". */ - public static void getHumanSpot() { - boolean validInput = false; // for input validation - System.out.print("Enter [0-8]:\n"); - do { - int spot = input.nextInt(); - if (board[spot] != "X" && board[spot] != "O") { - board[spot] = "X"; // update game-board content - printBoard(); - validInput = true; // input okay, exit loop - } - currentPlayer = nextPlayer(); // cross plays first - } while (!validInput); // repeat until input is valid - } - - public static void evalBoard() { - boolean foundSpot = false; - do { - if (board[4] == "4") { - board[4] = "O"; - foundSpot = true; - } else { - int spot = getBestMove(); - if (board[spot] != "X" && board[spot] != "O") { - foundSpot = true; - board[spot] = "O"; - } else { - foundSpot = false; - } - } - } while (!foundSpot); - printBoard(); - } - - /** Return true if the game was just won */ - public static boolean gameIsOver() { - return board[0] == board[1] && board[1] == board[2] || - board[3] == board[4] && board[4] == board[5] || - board[6] == board[7] && board[7] == board[8] || - board[0] == board[3] && board[3] == board[6] || - board[1] == board[4] && board[4] == board[7] || - board[2] == board[5] && board[5] == board[8] || - board[0] == board[4] && board[4] == board[8] || - board[2] == board[4] && board[4] == board[6]; - } - - - public static int getBestMove() { - ArrayList availableSpaces = new ArrayList(); - boolean foundBestMove = false; - int spot = 100; - for (String s: board) { - if (s != "X" && s != "O") { - availableSpaces.add(s); - } - } - for (String as: availableSpaces) { - spot = Integer.parseInt(as); - board[spot] = "O"; - if (gameIsOver()) { - foundBestMove = true; - board[spot] = as; - return spot; - } else { - board[spot] = "X"; - if (gameIsOver()) { - foundBestMove = true; - board[spot] = as; - return spot; - } else { - board[spot] = as; - } - } - } - if (foundBestMove) { - return spot; - } else { - int n = ThreadLocalRandom.current().nextInt(0, availableSpaces.size()); - return Integer.parseInt(availableSpaces.get(n)); - } - } - - /** Return true if it is a draw (no more empty cell) */ - - public static boolean tie() { - return board[0] != "0" && - board[1] != "1" && - board[2] != "2" && - board[3] != "3" && - board[4] != "4" && - board[5] != "5" && - board[6] != "6" && - board[7] != "7" && - board[8] != "8"; - } - - /** Print the game board */ - public static void printBoard() { - System.out.println(" " + board[0] + " | " + board[1] + " | " + board[2] + "\n===+===+===\n" + " " + board[3] + " | " + board[4] + " | " + board[5] + "\n===+===+===\n" + " " + board[6] + " | " + board[7] + " | " + board[8] + "\n"); // print all the board cells - } - -} +interface Game { + void startGame(); + void switchPlayers(); +} \ No newline at end of file diff --git a/java/GameEngine.java b/java/GameEngine.java index 0f005c3..39c8a7b 100644 --- a/java/GameEngine.java +++ b/java/GameEngine.java @@ -1,3 +1,44 @@ -public class GameEngine { - +class GameEngine implements Game { + private Board board; + private Player player1; + private Player player2; + private Player currentPlayer; + private GameRules gameRules; + + public GameEngine(Board board, Player player1, Player player2) { + this.board = board; + this.player1 = player1; + this.player2 = player2; + this.currentPlayer = player1; + this.gameRules = new GameRules(board); + } + + + public void startGame() { + board.printBoard(); + while (true) { + currentPlayer.makeMove(board); + board.printBoard(); + + if (gameRules.isGameOver()) { + System.out.println("Player " + currentPlayer.getSymbol() + " wins!"); + break; + } + + if (gameRules.isTie()) { + System.out.println("It's a tie!"); + break; + } + + switchPlayers(); + } + } + + + public void switchPlayers() { + currentPlayer = (currentPlayer == player1) ? player2 : player1; + } } + + + diff --git a/java/GameRules.java b/java/GameRules.java index 7a1dacc..a136163 100644 --- a/java/GameRules.java +++ b/java/GameRules.java @@ -1,3 +1,30 @@ -public class GameRules { - +class GameRules { + private Board board; + + public GameRules(Board board) { + this.board = board; + } + + public boolean isGameOver() { + String[] b = board.getBoard(); + return (b[0].equals(b[1]) && b[1].equals(b[2])) || + (b[3].equals(b[4]) && b[4].equals(b[5])) || + (b[6].equals(b[7]) && b[7].equals(b[8])) || + (b[0].equals(b[3]) && b[3].equals(b[6])) || + (b[1].equals(b[4]) && b[4].equals(b[7])) || + (b[2].equals(b[5]) && b[5].equals(b[8])) || + (b[0].equals(b[4]) && b[4].equals(b[8])) || + (b[2].equals(b[4]) && b[4].equals(b[6])); + } + + public boolean isTie() { + String[] b = board.getBoard(); + for (int i = 0; i < b.length; i++) { + if (b[i].equals(String.valueOf(i))) { + return false; + } + } + return true; + } } + From 929c40287dbcf1f548a511ead564b4615b78b746 Mon Sep 17 00:00:00 2001 From: Taleeha Tahoor Date: Mon, 30 Dec 2024 19:23:24 +0500 Subject: [PATCH 3/4] Implemented player abstract class, Human Player, Computer Player, sub classes and Main class --- java/ComputerPlayer.java | 28 +++++++++++++++++++++++++++- java/HumanPlayer.java | 34 ++++++++++++++++++++++++++++++++-- java/Main.java | 25 ++++++++++++++++++++++++- java/Player.java | 12 +++++++++++- 4 files changed, 94 insertions(+), 5 deletions(-) diff --git a/java/ComputerPlayer.java b/java/ComputerPlayer.java index 074bebe..d9d775b 100644 --- a/java/ComputerPlayer.java +++ b/java/ComputerPlayer.java @@ -1,3 +1,29 @@ -public class ComputerPlayer { +import java.util.ArrayList; +import java.util.concurrent.ThreadLocalRandom; + +class ComputerPlayer extends Player { + public ComputerPlayer(String symbol) { + super(symbol); + } + + public void makeMove(Board board) { + System.out.println("Computer's turn..."); + int bestMove = getBestMove(board); + board.markSpot(bestMove, getSymbol()); + } + + private int getBestMove(Board board) { + + ArrayList availableSpaces = new ArrayList<>(); + String[] b = board.getBoard(); + for (String s : b) { + if (!s.equals("X") && !s.equals("O")) { + availableSpaces.add(s); + } + } + int n = ThreadLocalRandom.current().nextInt(0, availableSpaces.size()); + return Integer.parseInt(availableSpaces.get(n)); + } } + diff --git a/java/HumanPlayer.java b/java/HumanPlayer.java index d13c28a..0b688d5 100644 --- a/java/HumanPlayer.java +++ b/java/HumanPlayer.java @@ -1,3 +1,33 @@ -public class HumanPlayer { - +import java.util.Scanner; + +class HumanPlayer extends Player{ + private Scanner input = new Scanner(System.in); + + public HumanPlayer(String symbol) { + super(symbol); + } + + + public void makeMove(Board board) { + boolean validInput = false; + int spot; + do { + System.out.print("Player " + getSymbol() + ", enter [0-8]: "); + while (!input.hasNextInt()) { + System.out.println("Please enter a valid number between 0 and 8."); + input.next(); + } + spot = input.nextInt(); + input.nextLine(); + + if (board.isValidMove(spot)) { + board.markSpot(spot, getSymbol()); + validInput = true; + } else { + System.out.println("Invalid move, try again."); + } + } while (!validInput); + } } + + diff --git a/java/Main.java b/java/Main.java index c1b4223..73d29eb 100644 --- a/java/Main.java +++ b/java/Main.java @@ -1,3 +1,26 @@ +import java.util.Scanner; + public class Main { - + public static void main(String[] args) { + + try (Scanner scanner = new Scanner(System.in)) { + System.out.println("Welcome to Tic Tac Toe!"); + System.out.print("Choose game mode (1 - Single Player, 2 - Two Player): "); + int mode = scanner.nextInt(); + + Board board = new Board(); + Player player1 = new HumanPlayer("X"); + GameEngine gameEngine; + + if (mode == 1) { + Player computerPlayer = new ComputerPlayer("O"); + gameEngine = new GameEngine(board, player1, computerPlayer); + } else { + Player player2 = new HumanPlayer("O"); + gameEngine = new GameEngine(board, player1, player2); + } + + gameEngine.startGame(); + } + } } diff --git a/java/Player.java b/java/Player.java index 02e5a71..e3ff28a 100644 --- a/java/Player.java +++ b/java/Player.java @@ -1,3 +1,13 @@ public class Player { - + protected String symbol; + + public Player(String symbol) { + this.symbol = symbol; + } + + public String getSymbol() { + return symbol; + } + + public abstract void makeMove(Board board); } From 0502fcf91bda6c178a1d00efc052d5f325f9327e Mon Sep 17 00:00:00 2001 From: Saima Bibi Date: Mon, 30 Dec 2024 20:08:11 +0500 Subject: [PATCH 4/4] make player abstract class --- java/Player.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/Player.java b/java/Player.java index e3ff28a..f17a35f 100644 --- a/java/Player.java +++ b/java/Player.java @@ -1,4 +1,4 @@ -public class Player { +public abstract class Player { protected String symbol; public Player(String symbol) {