diff --git a/java/Board.java b/java/Board.java new file mode 100644 index 0000000..5e93401 --- /dev/null +++ b/java/Board.java @@ -0,0 +1,28 @@ +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/ComputerPlayer.java b/java/ComputerPlayer.java new file mode 100644 index 0000000..d9d775b --- /dev/null +++ b/java/ComputerPlayer.java @@ -0,0 +1,29 @@ +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/Game.java b/java/Game.java index d39eb43..27384bc 100755 --- a/java/Game.java +++ b/java/Game.java @@ -1,146 +1,6 @@ -import java.util.Scanner; -import java.util.Arrays; -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) */ - // TODO: maybe there is an easeir way to check this - 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 new file mode 100644 index 0000000..39c8a7b --- /dev/null +++ b/java/GameEngine.java @@ -0,0 +1,44 @@ +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 new file mode 100644 index 0000000..a136163 --- /dev/null +++ b/java/GameRules.java @@ -0,0 +1,30 @@ +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; + } +} + diff --git a/java/HumanPlayer.java b/java/HumanPlayer.java new file mode 100644 index 0000000..0b688d5 --- /dev/null +++ b/java/HumanPlayer.java @@ -0,0 +1,33 @@ +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 new file mode 100644 index 0000000..73d29eb --- /dev/null +++ b/java/Main.java @@ -0,0 +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 new file mode 100644 index 0000000..f17a35f --- /dev/null +++ b/java/Player.java @@ -0,0 +1,13 @@ +public abstract class Player { + protected String symbol; + + public Player(String symbol) { + this.symbol = symbol; + } + + public String getSymbol() { + return symbol; + } + + public abstract void makeMove(Board board); +}