Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

PLEASE USE TEMPLATE PROVIDED AT THE BOTTOM OF QUESTION!!!! Human vs (Dumb) Machine A very simple way to have a program play Tic-Tac-Toe is to

PLEASE USE TEMPLATE PROVIDED AT THE BOTTOM OF QUESTION!!!!

Human vs (Dumb) Machine

A very simple way to have a program play Tic-Tac-Toe is to simply have the program pick the first empty cell to play at each turn. Of course, such an implementation should be easy to beat, but at least it can be played against.

In order to design this solution, we want to introduce the concept of aPlayer. For now, we will have three kinds of players: the human player, and two dumb computer players. Later, we can introduce more types of players, e.g. a smart computer player, a perfect player etc. All of these are Players.

Figure 1: The interface Player and the two classes implementing it.

What we gain from thisPlayersabstraction is that it is possible to organize a match between two players, and have these two players play a series of games, keeping score for the match etc., without having to worry about the type of players involved. We can have human vs human, human vs dumb computer, smart vs dumb computer players, or any combination of players, this does not impact the way the game is played: we have two players, and they alternate playing a move on the game until the game is over. The requirement to be able to do is that allPlayerimplement the same method, sayplay(), which can be called when it is that player's turn to play.

We can choose who plays whom, for example a human against a computer. The player who plays first, is initially chosen randomly. In subsequent games, the players alternate as first player. As usual, the first player plays X and the second player plays O so each player will alternate between playing playing X and playing O.

The following printout shows a typical game.

$ java GameMain Player 2's turn. Player 1's turn. X | | ----------- | | ----------- | | O to play: 

Here, player 2 (the computer) was selected to start for the first game.

As can be seen, the computer player doesn't print out anything when it plays, it just makes its move silently. Then, it is player 1's turn (human). Following what we did in assignment 1, the HumanPlayer object first prints the game (here, we can see that the computer played cell 1, the first that was available) and then prompts the actual human (us, the user) for a move. Below, we see that the human has selected cell 2. The computer will then play (silently) and the human will be prompt again. It continues until the game finishes:

O to play: 2 Player 2's turn. Player 1's turn. X | O | X ----------- | | ----------- | | O to play: 

And then.

O to play: 6 Player 2's turn. Player 1's turn. X | O | X ----------- X | | O ----------- | | O to play: 

And then.

O to play: 7 Player 2's turn. Player 1's turn. X | O | X ----------- X | X | O ----------- O | | O to play: 

And then

O to play: 9 Player 2's turn. Game over X | O | X ----------- X | X | O ----------- O | X | O Result: DRAW Play again (y)?: 

This game finishes with a DRAW. The sentence "Game over" is printed after the last move (made by the computer in this case), then the final board is printed, and the outcome of the game ("Result: DRAW").

The user is then asked if they want to play again.

Here, we want to play another game. This time, the human will make the first move. Below, you can see the entire game, which is a human win. Then a third game is played, also a human win, and we stop playing after this.

Play again (y)?: y Player 1's turn. | | ----------- | | ----------- | | X to play: 1 Player 2's turn. Player 1's turn. X | O | ----------- | | ----------- | | X to play: 4 Player 2's turn. Player 1's turn. X | O | O ----------- X | | ----------- | | X to play: 7 Game over X | O | O ----------- X | | ----------- X | | Result: XWIN Play again (y)?: y Player 2's turn. Player 1's turn. X | | ----------- | | ----------- | | O to play: 3 Player 2's turn. Player 1's turn. X | X | O ----------- | | ----------- | | O to play: 6 Player 2's turn. Player 1's turn. X | X | O ----------- X | | O ----------- | | O to play: 9 Game over X | X | O ----------- X | | O ----------- | | O Result: OWIN Play again (y)?: n 

We are now ready to program our solution. We will reuse the implementation of the class TicTacToe from assignment 1 with a few small tweaks.

Player

Playeris an interface. It defines only one method, the method play. Play is returns a boolean (did the player succeed in playing) and has one input parameter, a reference to a TicTacToe game.

HumanPlayer

HumanPlayeris a class which implements the interface Player. In its implementation of the method play, it first checks that the game is indeed playable (and returns false if it isn't), and then prompts the user for a valid input (similar to that from Assignment 1). Once an input has been provided, it plays in on the board and returns true.

ComputerInOrderPlayer

ComputerInOrderPlayeris a class which also implements the interfacePlayer. In its implementation of the method play, it first checks that the game is playable (and returns false if it isn't), and then chooses the first available cell.

ComputerRandomPlayer

Let us make a slightly smarter, but still dumb computer player.

ComputerRandomPlayeris a class which also implements the interfacePlayer. In its implementation of the method play, it first checks that the game is indeed playable (and returns false if it isn't), and then chooses randomly the next move and plays it on the game and returns. All the possible next moves have an equal chance of being played.

GameMain

This class implements playing the game. You are provided with the initial part, but you will need to complete it. The entire game is played in the main method. A local variableplayers, a reference to an array of two players, is used to store the human and the computer player. Youmustuse that array to store yourPlayerreferences.

You need to finish the implementation of the main to obtain the specified behaviour. You need to ensure that the first player is initially chosen randomly, and that the first move alternate between both players in subsequent games.

Below is another sample run, this time on a 4x4 grid with a win length of 2. The human players makes a series of input mistakes along the way.

We have two additional arguments than we had from Assignment #1, "player1" and "player2" which can be one of

  • "h" for the human player
  • "ic" for the in order computer player
  • "rc" for the random computer player
$ java GameMain h ic 4 4 2 Player 1's turn. | | | --------------- | | | --------------- | | | --------------- | | | X to play: 2 Player 2's turn. Player 1's turn. O | X | | --------------- | | | --------------- | | | --------------- | | | X to play: 99 The value should be between 1 and 16 X to play: 2 Cell 2 has already been played with X X to play: 6 Game over O | X | | --------------- | X | | --------------- | | | --------------- | | | Result: XWIN Play again (Y)?:n 

TicTacToe Enumerations

We are now looking at something else: game enumerations. We would like to generate all the possible games for a given size of grid and win size.

For example, if we take the default, 3x3 grid, there is 1 grid at level 0, namely:

 | | ----------- | | ----------- | | 

At level 1, there are 9 grids, namely:

 X | | ----------- | | ----------- | | | X | ----------- | | ----------- | | | | X ----------- | | ----------- | | | | ----------- X | | ----------- | | | | ----------- | X | ----------- | | | | ----------- | | X ----------- | | | | ----------- | | ----------- X | | | | ----------- | | ----------- | X | | | ----------- | | ----------- | | X 

There are then 72 grids at level 2, too many to print here. In Appendix A, we provide the complete list of games for a 2x2 grid, with a win size of 2. Note that no game of level 4 appears on that list: it is simply impossible to reach level 3 and not win on a 2x2 grid with a win size of 2. In our enumeration, we do not list the same game twice, and we do not continue after a game has been won.

Our Implementation

For this implementation, we are going to add a couple of new methods to our classTicTacToeand we will make a new class,TicTacToeEnumerations, to generate our games. We will store our games in a list of lists. We will have our own implementation of the abstract data type List very soon, but we do not have it yet. Therefore, exceptionally for ITI1X21, we are going to use a ready-to-use solution. In this case, we will use java.util.LinkedList. The documentation is available athttps://docs.oracle.com/javase/9/docs/api/java/util/LinkedList.html.

The goal is to make a list of lists: each list will have all the different games for a given level. Consider again the default, 3x3 grid. Our list will have 10 elements.

  • The first element is the list of 3x3 grid at level 0. There is 1 such grid, so this list has 1 element.
  • The second element is the list of 3x3 grid at level 1. There are 9 such grids, so this list has 9 elements.
  • The third element is the list of 3x3 grid at level 2. There are 72 such grids, so this list has 72 elements.
  • The fourth element is the list of 3x3 grid at level 3. There are 252 such grids, so this list has 252 elements.
  • The fifth element is the list of 3x3 grid at level 4. There are 756 such grids, so this list has 756 elements.

...

  • The ninth element is the list of 3x3 grid at level 8. There are 390 such grids, so this list has 390 elements.
  • The tenth element is the list of 3x3 grid at level 9. There are 78 such grids, so this list has 78 elements.

The classEnumerationsMain.javais provided to you. Here are a few typical runs:

$ java EnumerationsMain ======= level 0 =======: 1 element(s) (1 still playing) ======= level 1 =======: 9 element(s) (9 still playing) ======= level 2 =======: 72 element(s) (72 still playing) ======= level 3 =======: 252 element(s) (252 still playing) ======= level 4 =======: 756 element(s) (756 still playing) ======= level 5 =======: 1260 element(s) (1140 still playing) ======= level 6 =======: 1520 element(s) (1372 still playing) ======= level 7 =======: 1140 element(s) (696 still playing) ======= level 8 =======: 390 element(s) (222 still playing) ======= level 9 =======: 78 element(s) (0 still playing) that's 5478 games 564 won by X 316 won by O 78 draw 

We can specify the grid size and the number of in a row to win

$ java EnumerationsMain 3 3 2 ======= level 0 =======: 1 element(s) (1 still playing) ======= level 1 =======: 9 element(s) (9 still playing) ======= level 2 =======: 72 element(s) (72 still playing) ======= level 3 =======: 252 element(s) (112 still playing) ======= level 4 =======: 336 element(s) (136 still playing) ======= level 5 =======: 436 element(s) (40 still playing) ======= level 6 =======: 116 element(s) (4 still playing) ======= level 7 =======: 12 element(s) (0 still playing) that's 1234 games 548 won by X 312 won by O 0 draw 

Here is a small 2x2 grid.

$ java EnumerationsMain 2 2 2 ======= level 0 =======: 1 element(s) (1 still playing) ======= level 1 =======: 4 element(s) (4 still playing) ======= level 2 =======: 12 element(s) (12 still playing) ======= level 3 =======: 12 element(s) (0 still playing) that's 29 games 12 won by X 0 won by O 0 draw 

Here is animpossible to win2x2 grid.

$ java EnumerationsMain 2 2 3 ======= level 0 =======: 1 element(s) (1 still playing) ======= level 1 =======: 4 element(s) (4 still playing) ======= level 2 =======: 12 element(s) (12 still playing) ======= level 3 =======: 12 element(s) (12 still playing) ======= level 4 =======: 6 element(s) (0 still playing) that's 35 games 0 won by X 0 won by O 6 draw 

Here is a larger 5x2 board.

$ java EnumerationsMain 5 2 3 ======= level 0 =======: 1 element(s) (1 still playing) ======= level 1 =======: 10 element(s) (10 still playing) ======= level 2 =======: 90 element(s) (90 still playing) ======= level 3 =======: 360 element(s) (360 still playing) ======= level 4 =======: 1260 element(s) (1260 still playing) ======= level 5 =======: 2520 element(s) (2394 still playing) ======= level 6 =======: 3990 element(s) (3798 still playing) ======= level 7 =======: 3990 element(s) (3290 still playing) ======= level 8 =======: 2580 element(s) (2162 still playing) ======= level 9 =======: 1032 element(s) (646 still playing) ======= level 10 =======: 150 element(s) (0 still playing) that's 15983 games 1212 won by X 610 won by O 150 draw 

TicTacToe Changes

We need to add three new public methods to the class TicTacToe:

cloneNextPlay

public TicTacToe cloneNextPlay(int nextMove) 

ThecloneNextPlayis used to make a new instance of the classTicTacToe, based on the current instance (akathis). The new instance will copy (also known as clone) the current state of the game, and will then apply thenextMove. For example, imagine the following game:

 O | | X ----------- X | | ----------- | | 

A call to

game.cloneNextPlay(7); 

Returns a new game as follows:

 O | | X ----------- X | | ----------- O | | 

One important consideration in implementing this method is that the underlying game should not be modified by the call. Have a look at Appendix B to better understand what is required to achieve this.

equals

public boolean equals(Object obj) 

Theequalscompares the current game with the game referenced by other object. This method returns true if and only if both games are considered the same: they have the same characteristics, and their board is in the same state.

emptyPositions

TheemptyPositionsreturns an array of positions that are empty and available to be played on. The results are 1-based (not zero).

For example, imagine the following game:

 O | | X ----------- X | | ----------- | | 

A call to

game.emptyPositions(); 

Returns

[2, 5, 6, 7, 8, 9] 

TicTacToeEnumerations

This new class computes has a constructor the same asTicTacToe

public TicTacToeEnumerations(int aNumRows, int aNumColumns, int aSizeToWin) 

And then implement the methodgenerateAllGamesto generate the list of lists of games.

public LinkedList>> generateAllGames() 

This method returns the (Linked) list of (Linked) lists of TicTacToe references that we are looking for, for the games on a gridnumRowsxnumColumnswith a particularsizeToWin. As explained, each of the (secondary) lists contains the lists of references to the game of the same level. There are three important factors to take into account when building the list:

  • We only build games up to their winning point (or until they reach a draw). We never extend a game that is already won.
  • We do not duplicate games. There are several ways to reach the same state, so make sure that the same game is not listed several times.
  • We do not include empty lists. As can be seen in A, we stop our enumeration once all the games are finished. In the 2x2 case with a win size of 2, since all the games are finished after 3 moves, the list of lists has only 4 elements: games after 0 move, games after 1 move, games after 2 moves and games after 3 moves.

JUnit

We provide a set of JUnit tests. These tests should help ensure that your implementation is correct. They can also help clarify the expected behavior of this class.

Please read thejunit instructionsfor help with running the tests.

Submission

Please read theSubmission Guidelinescarefully. Submission errors will affect your grades.

Submit the following files.

  • STUDENT.md
  • ComputerInOrderPlayer.java
  • ComputerRandomPlayer.java
  • GameMain.java
  • HumanPlayer.java
  • TicTacToe.java
  • TicTacToeEnumerations.java

Submit the following files, but they should not be changed.

  • CellValue.java
  • EnumerationsMain.java
  • GameState.java
  • Player.java
  • Utils.java

This assignment can be done in groups of 2 +/- 1 person. Ensure thatSTUDENT.mdincludes the names of all participants; only submit 1 solution per group.

Appendix A: Enumerating all games of a 2x2 grid

======= level 0 =======: 1 element(s) | ------- | ======= level 1 =======: 4 element(s) X | ------- | | X ------- | | ------- X | | ------- | X ======= level 2 =======: 12 element(s) X | O ------- | X | ------- O | X | ------- | O O | X ------- | | X ------- O | | X ------- | O O | ------- X | | O ------- X | | ------- X | O O | ------- | X | O ------- | X | ------- O | X ======= level 3 =======: 12 element(s) X | O ------- X | X | O ------- | X X | X ------- O | X | ------- O | X X | X ------- | O X | ------- X | O O | X ------- X | O | X ------- | X | X ------- O | X | X ------- X | O O | ------- X | X | O ------- X | X 

Appendix B: Shallow copy versus Deep copy

As you know, objects have variables which are either a primitive type, or a reference type. Primitive variables hold a value from one of the language primitive type, while reference variables hold a reference (the address) of another object (including arrays, which are objects in Java).

If you are copying the current state of an object, in order to obtain a duplicate object, you will make a copy of each of the variables. By doing so, the value of each instance primitive variable will be duplicated (thus, modifying one of these values in one of the copy will not modify the value on the other copy). However, with reference variables, what will be copied is the actual reference, the address of the object that this variable is pointing at. Consequently, the reference variables in both the original object and the duplicated object will point at the same address, and the reference variables will refer to the same objects. This is known as a shallow copy: you indeed have two objects, but they share all the objects pointed at by their instance reference variables. The Figure B provides an example: the object referenced by variable b is a shallow copy of the object referenced by variable a: it has its own copies of the instances variables, but the references variables title and time are referencing the same objects.

Often, a shallow copy is not adequate: what is required is a so-called deep copy. A deep copy differs from a shallow copy in that objects referenced by reference variable must also be recursively duplicated, in such a way that when the initial object is (deep) copied, the copy does not share any reference with the initial object. The Figure B provides an example: this time, the object referenced by variable b is a deep copy of the object referenced by variable a: now, the references variables title and time are referencing different objects. Note that, in turn, the objects referenced by the variable time have also been deep-copied. The entire set of objects reachable from a have been duplicated.

TEMPLATES TO USE (EACH FILE WILL BE SEPERATED BY A "____________________________________________________") AND PLEASE ONLY WRITE CODE WHERE IT'S WRITTEN "YOUR CODE HERE":

/** * An enum class that defines the values * INVALID, * EMPTY, * X, and * O. * * @author Guy-Vincent Jourdan, University of Ottawa */

public enum CellValue { INVALID("?"), EMPTY(" "), X("X"), O("O");

private String display;

private CellValue(String aDisplay) { display = aDisplay; }

@Override public String toString() { return display; }

}

____________________________________________________

public class ComputerInOrderPlayer {

// YOUR CODE HERE

}

____________________________________________________

public class ComputerRandomPlayer {

// YOUR CODE HERE

}

____________________________________________________

public class EnumerationsMain {

/** * Another main application. * This one will generate a list of games * and describe the outputs * * @param args command lines parameters */ public static void main(String[] args) {

int numRows = validateInt(args, 0); int numColumns = validateInt(args, 1); int wins = validateInt(args, 2);

if (args.length > 3){ System.out.println("Too many arguments. Only the first 3 are used."); }

TicTacToeEnumerations generator = new TicTacToeEnumerations(numRows, numColumns, wins); generator.generateAllGames(); System.out.println(generator); }

/** * Extract an integer from the provided argument * it must be 2 or more. * * @param args The command lines parameters * @param index Which index to parse */ private static int validateInt(String[] args, int index) { if (index >= 0 && index < args.length) { int num = Integer.parseInt(args[index]); if(num >= 2){ return num; } else { System.out.println("Invalid argument, using default..."); } } return 3; }

}

____________________________________________________

public class GameMain {

/** * main of the application. Creates the instance of TicTacToe * and starts the game. If two parameters lines and columns * are passed, they are used. If the paramters lines, columns * and win are passed, they are used. * Otherwise, a default value is used. Defaults values (3) are also * used if the paramters are too small (less than 2). * Here, we assume that the command lines arguments are indeed integers * * @param args command lines parameters */ public static void main(String[] args) {

Player p1 = validatePlayer(args, 0, "h"); Player p2 = validatePlayer(args, 1, "ic");

int lines = validateInt(args, 2); int columns = validateInt(args, 3); int wins = validateInt(args, 4);

if (args.length > 5){ System.out.println("Too many arguments. Only the first 5 are used."); }

TicTacToe game; Player[] players = new Player[] {p1, p2};

// YOUR CODE HERE

}

/** * Toggle the current player to be the next player * @param currentPlayer the current player index (0 or 1) * @return The next player index (1 or 0) */ private static int nextPlayer(int currentPlayer) { return currentPlayer == 1 ? 0 : 1; }

/** * Extract the player from the arguments * "h" for HumanPlayer * "ic" for ComputerInOrderPlayer * "rc" for ComputerRandomPlayer * * @param args The command lines parameters * @param index Which index to parse * @param defaultIfMissing Default value if no input at that index * @return String The value at that position of the default if not available */ private static Player validatePlayer(String[] args, int index, String defaultIfMissing) { String player; if (index >= 0 && index < args.length) { player = args[index]; } else { player = defaultIfMissing; }

switch (player) { case "h": return new HumanPlayer(); case "ic": return new ComputerInOrderPlayer(); case "rc": return new ComputerRandomPlayer(); default: System.out.println("Unknown player " + player + " expected 'h', 'ic' or 'rc', defaulting to Human."); return new HumanPlayer(); } }

/** * Extract an integer from the provided argument * it must be 2 or more. * * @param args The command lines parameters * @param index Which index to parse */ private static int validateInt(String[] args, int index) { if (index >= 0 && index < args.length) { int num = Integer.parseInt(args[index]); if(num >= 2){ return num; } else { System.out.println("Invalid argument, using default..."); } } return 3; }

}

____________________________________________________

/** * An enum class that defines the values * PLAYING, * DRAW, * XWIN, and * OWIN * * @author Guy-Vincent Jourdan, University of Ottawa */

public enum GameState{ PLAYING, DRAW, XWIN, OWIN;}

____________________________________________________

public class HumanPlayer {

// YOUR CODE HERE

}

____________________________________________________

public interface Player {

boolean play(TicTacToe game);

}

____________________________________________________

/** * The class TicTacToe is the * class that implements the Tic Tac Toe Game. * It contains the grid and tracks its progress. * It automatically maintain the current state of * the game as players are making moves. * * Originally written by Guy-Vincent Jourdan, University of Ottawa */public class TicTacToe {

// FINISH THE VARIABLE DECLARATION /** * The internal representation of the board * as a one dimensional array, but visualized * as a 2d board based on the number of rows * and number of columns. * * For example, below is a board of 3 rows * and 4 columns. The board would be an array * of size 12 shown below. * * 1 | 2 | 3 | 4 * -------------------- * 5 | 6 | 7 | 8 * -------------------- * 9 | 10 | 11 | 12 * */ CellValue[] board;

/** * The number of rows in your grid. */ int numRows;

/** * The number of columns in your grid. */ int numColumns;

/** * How many rounds have the players played so far. */ int numRounds;

/** * What is the current state of the game */ GameState gameState;

/** * How many cells of the same type must be * aligned (vertically, horizontally, or diagonally) * to determine a winner of the game */ int sizeToWin;

/** * Who is the current player? */ CellValue currentPlayer;

/** * What was the last played position */ int lastPlayedPosition;

private static int DEFAULT_ROWS = 3; private static int DEFAULT_COLUMNS = 3; private static int DEFAULT_SIZETOWIN = 3;

/** * The default empty constructor. The default game * should be a 3x3 grid with 3 cells in a row to win. */ public TicTacToe() { this(DEFAULT_ROWS, DEFAULT_COLUMNS, DEFAULT_SIZETOWIN); }

/** * A constructor where you can specify the dimensions * of your game as rows x coluns grid, and a sizeToWin * * @param aNumRows the number of lines in the game * @param aNumColumns the number of columns in the game * @param aSizeToWin the number of cells that must be aligned to win. */ public TicTacToe(int aNumRows, int aNumColumns, int aSizeToWin) { numRows = aNumRows; numColumns = aNumColumns; sizeToWin = aSizeToWin; gameState = GameState.PLAYING; currentPlayer = CellValue.EMPTY; lastPlayedPosition = 0;

int boardSize = numRows * numColumns; board = new CellValue[boardSize]; for (int i=0; i

/** * Who should play next (X or O). * * This method does not modify the state of the game. * Instead it tells you who should play next. * * @return The player that should play next. */ public CellValue nextPlayer() { switch(currentPlayer) { case X: return CellValue.O; default: return CellValue.X; } }

/** * What is the value at the provided cell based on the * grid of numRows x numColumns as illustrated below. * * 1 | 2 | 3 | 4 * -------------------- * 5 | 6 | 7 | 8 * -------------------- * 9 | 10 | 11 | 12 * * Note that the input is 1-based (HINT: arrays are 0-based) * * If the position is invalid, return CellValue.INVALID. * * @param position The position on the board to look up its current value * @return The CellValue at that position */ public CellValue valueAt(int position) { int maxPosition = numRows * numColumns; if (position < 1 || position > maxPosition) { return CellValue.INVALID; } else { return board[position - 1]; } }

/** * What is the value at the provided row and column number. * * [1,1] | [1,2] | [1,3] | [1,4] * ---------------------------------- * [2,1] | [2,2] | [2,3] | [2,4] * ---------------------------------- * [3,1] | [3,2] | [3,3] | [2,4] * * Note that the input is 1-based (HINT: arrays are 0-based) * * If the row/column is invalid, return CellValue.INVALID. * * @param position The position on the board to look up its current value * @return The CellValue at that row/column */ public CellValue valueAt(int row, int column) { if (row < 1 || row > numRows) { return CellValue.INVALID; } else if (column < 1 || column > numColumns) { return CellValue.INVALID; } else { return valueAt((row - 1) * numColumns + column); } }

/** * The next player has decided their move to the * provided position. * * * 1 | 2 | 3 | 4 * -------------------- * 5 | 6 | 7 | 8 * -------------------- * 9 | 10 | 11 | 12 * * A position is invalid if: * a) It's off the board (e.g. based on the above < 1 or > 12) * b) That cell is not empty (i.e. it's no longer available) * * If the position is invalid, an error should be printed out. * * If the position is valid, then * a) Update the board * b) Update the state of the game * c) Allow the next player to play. * * A game can continue even after a winner is declared. * If that is the case, a message should be printed out * (that the game is infact over), but the move should * still be recorded. * * The winner of the game is the player who won first. * @param position The position that has been selected by the next player. * @return A message about the current play (see tests for details) */ public String play(int position) { CellValue playedBy = nextPlayer(); CellValue cell = valueAt(position); switch (cell) { case EMPTY: currentPlayer = playedBy; lastPlayedPosition = position; board[position - 1] = playedBy; numRounds += 1;

// Only check for a winner if we were still playing. if (gameState == GameState.PLAYING) { gameState = checkForWinner(position); } return null; case INVALID: return "The value should be between 1 and " + (numRows * numColumns); default: return "Cell "+ position +" has already been played with " + cell; } }

/** * A help method to determine if the game has been won * to be called after a player has played * * This method is called after the board has been updated * and provides the last position that was played * (to help you analyze the board). * * @param position The middle position to start our check * @return GameState to show if XWIN or OWIN. If the result was a DRAW, or if * the game is still being played. */ private GameState checkForWinner(int position) {

if (numRounds == numRows * numColumns) { return GameState.DRAW; }

GameState ifWon; switch(currentPlayer) { case X: ifWon = GameState.XWIN; break; case O: ifWon = GameState.OWIN; break; default: ifWon = GameState.PLAYING; }

int currentRow = (position-1)/numColumns + 1; int currentColumn = (position-1)%numColumns + 1;

// Look left and right if (checkSizeToWin(currentRow, currentColumn, 1, 0)) { return ifWon; }

// Look up and down if (checkSizeToWin(currentRow, currentColumn, 0, 1)) { return ifWon; }

// Look diagonal down/left and diagonal up/right if (checkSizeToWin(currentRow, currentColumn, -1, 1)) { return ifWon; }

// Look diagonal down/right and diagonal up/left if (checkSizeToWin(currentRow, currentColumn, 1, 1)) { return ifWon; }

return GameState.PLAYING; }

/** * Starting from a position, look "before" and "after" * to see if we have reached the size to win amount * to declare a winner. * @param row The current row to check * @param column The current row to check * @param rowOffset Where should we move +1 right, -1 left and 0 for no change. * @param columnOffset Where should we move +1 up, -1 down and 0 for no change. * @return Boolean True if we have at least the sizeToWin of matching cells */ private boolean checkSizeToWin(int row, int column, int rowOffset, int columnOffset) { int numBefore = countMatches(row, column, rowOffset, columnOffset); int numAfter = countMatches(row, column, -rowOffset, -columnOffset); return (numBefore + numAfter + 1) >= sizeToWin; }

/** * Look around the last position played for * the number of the same values * To look left, the offset is -1 * To look right, the offsewt is +1 * To look up, the offset is - numColumns * To look down, the offset is + numColumns * @param row The current row to check * @param column The current row to check * @param rowOffset Where should we move +1 right, -1 left and 0 for no change. * @param columnOffset Where should we move +1 up, -1 down and 0 for no change. * @return The number of similar plays based on the offset */ private int countMatches(int row, int column, int rowOffset, int columnOffset) { int numFound = 0; int checkRow = row; int checkColumn = column; while (true) { checkRow += rowOffset; checkColumn += columnOffset; if (valueAt(checkRow, checkColumn) == currentPlayer) { numFound += 1; } else { break; } } return numFound; }

/** * A text based representation of the 2D grid, and * should include all played Xs and Os. For example * On a 3x3 board. (HINT: for newlines) * * | X | * ----------- * O | | * ----------- * | | * * @return String representation of the game */ public String toString() { StringBuilder b = new StringBuilder(); int maxRowsIndex = numRows - 1; int maxColumnsIndex = numColumns - 1;

String lineSeparator = repeat("---", numColumns) + repeat("-", numColumns - 1);

for (int i = 0; i < numRows; i++) { for (int j = 0; j < this.numColumns; j++) { int index = i*numColumns + j;

b.append(" "); b.append(board[index]); b.append(" ");

if (j < maxColumnsIndex) { b.append("|"); } }

// Line separator after each row, except the last if (i < maxRowsIndex) { b.append(" "); b.append(lineSeparator); b.append(" "); } }

return b.toString(); }

/** * An array of positions that are empty * and available to be played on. * * | X | * ----------- * O | | * ----------- * | | * * The results are 1-based (not zero), and * in the above board the empty positions are * [1, 3, 5, 6, 7, 8, 9] * * Hint: Useful for a computer to know which * positions are available to choose from. * Also useful for generating all game boards. * * @return All empty positions */ public int[] emptyPositions() {

// YOUR CODE HERE

}

/** * make a copy of the current game with one extra move * added. The new game is a deep copy of this game * and then we apply the next move. If the move * is not valid, return null; * @param nextMove The desired next move (1 to numRows x numColumns) * @return A new TicTacToe game */ public TicTacToe cloneNextPlay(int nextMove) {

// YOUR CODE HERE

}

/** * Compares this instance of the game with the * instance passed as parameter. Return true * if and only if the two instance represent * the same state of the game including * The board dimensions, number of cells to * win, and the pieces on the board. * @param obj An object we are comparing against * @return True if they represent the same state */ public boolean equals(Object obj) {

// YOUR CODE HERE

}

/** * Expose all internal data for debugging purposes * * @return String representation of the game */ public String toDebug() { StringBuilder b = new StringBuilder(); b.append("Grid (rows x columns): " + numRows + " x " + numColumns); b.append(" "); b.append("Size To Win: " + sizeToWin); b.append(" "); b.append("Num Rounds: " + numRounds); b.append(" "); b.append("Game State: " + gameState); b.append(" "); b.append("Current Player: " + currentPlayer); b.append(" "); b.append("Next Player: " + nextPlayer()); b.append(" ");

b.append("Board (array): ["); for (int i=0; i 0) { b.append(","); } b.append(board[i]); } b.append("] ");

return b.toString(); }

/** * The method String repeat is availabe in Java 11+ * Some students still have Java 8 (or less) so we * will implement this method directly for backwards * compatibility * @param str The string the repeat * @param numTimes How often to repeat */ private static String repeat(String str, int numTimes) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < numTimes; i++) { sb.append(str); } return sb.toString(); }}

____________________________________________________

import java.util.LinkedList;

public class TicTacToeEnumerations {

// YOUR CODE HERE

/** * The list of lists of all generated games */ LinkedList> allGames;

/** * A constructor where you can specify the dimensions * of your game as rows x coluns grid, and a sizeToWin * to analyze. * * @param aNumRows the number of lines in the game * @param aNumColumns the number of columns in the game * @param aSizeToWin the number of cells that must be aligned to win. */ public TicTacToeEnumerations(int aNumRows, int aNumColumns, int aSizeToWin) {

// YOUR CODE HERE

}

/** * Generate a list of lists of all games, storing the * result in the member variables `allGames`. */ public LinkedList> generateAllGames() {

// YOUR CODE HERE

return allGames; }

public String toString() { if (allGames == null) { return "No games generated."; }

StringBuilder s = new StringBuilder();

int numGames = 0; int numXWin = 0; int numOWin = 0; int numDraw = 0; for (int i=0; i games = allGames.get(i); int numStillPlaying = 0; for (TicTacToe g : games) { numGames += 1; switch (g.gameState) { case PLAYING: numStillPlaying += 1; break; case XWIN: numXWin += 1; break; case OWIN: numOWin += 1; break; case DRAW: numDraw += 1; break; } } s.append("======= level "+ i +" =======: "); s.append(games.size() + " element(s) ("); s.append(numStillPlaying + " still playing) "); }

s.append("that's "+ numGames +" games "); s.append(numXWin + " won by X "); s.append(numOWin + " won by O "); s.append(numDraw + " draw"); return s.toString(); }

}

____________________________________________________

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

Financial management theory and practice

Authors: Eugene F. Brigham and Michael C. Ehrhardt

12th Edition

978-0030243998, 30243998, 324422695, 978-0324422696

Students also viewed these Programming questions