java programming
/**
* Bishnu karki
* 3127350
* fall 2020
* Class: COSC 1436
* EL Centro College
* Professor Keith Smelser
*
*
*/
/**
* The TicTacToe board is a 2 dimensional array
* This is very similar to an Excel Spreadsheet - using rows and columns
*
* col 012
* row 0 xxx (0,0) | (0,1) | (0,2)
* row 1 xxx (1,0) | (1,1) | (1,2)
* row 2 xxx (2,0) | (2,1) | (2,2)
*
* The array is loaded with the Boolean Class.
* Boolean allows for true and false and also null.
* This program treats null as not loaded, true as X and false as O
*/
import java.util.concurrent.ThreadLocalRandom;
public class TicTacToeBoard {
public static final byte MAX_ROWS = 3;
public static final byte MAX_COLS = 3;
public static final char NOT_PLAYED = ' ';
public static final char PLAYER_1 = 'X';
public static final char PLAYER_2 = 'O';
private static final char NO_WINNER = '?';
private GuiBoard theGUIBoard;
private boolean smartPlay = false;
// This enum is used as an indicator to know to process
// rows or columns
private enum ROW_OR_COLUMN {
ROW, COLUMN
};
private Character[][] ticTacToeBoard = new Character[MAX_ROWS][MAX_COLS];
private char computerPlayer = NOT_PLAYED;
/**
* Constructor - Set the computer player X/O + security code
*/
public TicTacToeBoard(char myComputerPlayer, boolean smartPlay) {
if (myComputerPlayer == PLAYER_1 || myComputerPlayer == PLAYER_2) {
computerPlayer = myComputerPlayer;
} else {
exit("Invalid TicTacToe Player - must be " + PLAYER_1 + " or " + PLAYER_2);
}
this.smartPlay = smartPlay; // set method level variable
System.out.println("Computer Player is " + computerPlayer + ", Smart Computer is " + smartPlay);
theGUIBoard = new GuiBoard();
}
/**
* Show a message and force the program to exit
*/
private void exit(String msg) {
System.err.println(msg);
System.err.println("Program will exit now.");
System.exit(1);
}
/**
* Check for a Rows or Columns for all same valid values If found - set the
* theWinnerIs value
*/
private Character checkRowOrColumnForWinner(ROW_OR_COLUMN rowOrColumn) {
Character locatedWinner = null;
// Since MAX_ROWS and MAX_COLS is 3 - will set MAX to 3 for all situations
final int MAX = MAX_ROWS;
for (byte idxDirection_1 = 0; idxDirection_1 < MAX; ++idxDirection_1) {
if (locatedWinner != null) {
// owner was set - No need to work on other rows or columns
break;
}
for (byte idxDirection_2 = 0; idxDirection_2 < MAX; ++idxDirection_2) {
Character entry = null;
if (rowOrColumn.equals(ROW_OR_COLUMN.ROW)) {
entry = ticTacToeBoard[idxDirection_1][idxDirection_2];
} else { // must be column
entry = ticTacToeBoard[idxDirection_2][idxDirection_1];
}
if (entry == null) { // Unused location - No Winner here
locatedWinner = null; // reset back to Null for next row/col
break;
}
if (locatedWinner == null) {
locatedWinner = entry;
} else if (!locatedWinner.equals(entry)) {
// Multiple entries in Row or Column - No Winner here
locatedWinner = null; // reset back to Null
break;
}
}
}
return locatedWinner;
}
/**
* Report true if a winner is found
* or false if no winner detected
*/
public boolean hasWinner() {
return (theWinnerIs() != NO_WINNER);
}
/**
* Returns X or O or ? if no winner found
*/
public char theWinnerIs() {
Character theWinner = checkRowOrColumnForWinner(ROW_OR_COLUMN.ROW);
if (theWinner == null) { // If not Row Winner - try Column Winner
theWinner = checkRowOrColumnForWinner(ROW_OR_COLUMN.COLUMN);
}
// Final result
if (theWinner == null) {
theWinner = NO_WINNER;
}
return theWinner;
}
/**
* Return true if no items have been played. Return false if game has started
*/
private boolean checkFirstPlay() {
for (byte idxRow = 0; idxRow < MAX_ROWS; ++idxRow) {
for (byte idxCol = 0; idxCol < MAX_COLS; ++idxCol) {
if (ticTacToeBoard[idxRow][idxCol] != null) {
return false;
}
}
}
return true;
}
/**
* Set the entry value only if it has the default null value.
*/
private boolean setValue(int row, int column, char player) {
if (player == PLAYER_2) {
if (checkFirstPlay()) {
System.err.println(PLAYER_1 + " must start the game");
return false;
}
}
if (ticTacToeBoard[row][column] == null) {
ticTacToeBoard[row][column] = player;
theGUIBoard.setSquare(row, column, player);
return true;
}
return false;
}
/**
* Public setValue method for the human player (Overloaded)
*/
public boolean setValue(int row, int column) {
char thePlayer = PLAYER_1;
if (computerPlayer == PLAYER_1) {
thePlayer = PLAYER_2;
}
return setValue(row, column, thePlayer);
}
/**
* Private setValue for the Computer player
*/
private boolean setValueComputer(int row, int column) {
return setValue(row, column, computerPlayer);
}
/**
* Determines the best offensive or defensive move
* @param player
* @return
* Returns -1 for no options or 0-8 for spot.
*/
private int bestComputerPlacement() {
//Grab center square if available
if (ticTacToeBoard[1][1] == null) {
return 4;
}
// Init counter
WinOptions[] computerOptions = new WinOptions[8];
WinOptions[] humanOptions = new WinOptions[8];
int idx = 0;
char humanPlayer = PLAYER_1;
if (computerPlayer == PLAYER_1) {
humanPlayer = PLAYER_2;
}
idx = -1;
computerOptions[++idx] = new WinOptions(ticTacToeBoard, WinOptions.WIN_WAY.ROW1, computerPlayer);
computerOptions[++idx] = new WinOptions(ticTacToeBoard, WinOptions.WIN_WAY.ROW2, computerPlayer);
computerOptions[++idx] = new WinOptions(ticTacToeBoard, WinOptions.WIN_WAY.ROW3, computerPlayer);
computerOptions[++idx] = new WinOptions(ticTacToeBoard, WinOptions.WIN_WAY.COL1, computerPlayer);
computerOptions[++idx] = new WinOptions(ticTacToeBoard, WinOptions.WIN_WAY.COL2, computerPlayer);
computerOptions[++idx] = new WinOptions(ticTacToeBoard, WinOptions.WIN_WAY.COL3, computerPlayer);
computerOptions[++idx] = new WinOptions(ticTacToeBoard, WinOptions.WIN_WAY.DIAG_DOWN, computerPlayer);
computerOptions[++idx] = new WinOptions(ticTacToeBoard, WinOptions.WIN_WAY.DIAG_UP, computerPlayer);
idx = -1;
humanOptions[++idx] = new WinOptions(ticTacToeBoard, WinOptions.WIN_WAY.ROW1, humanPlayer);
humanOptions[++idx] = new WinOptions(ticTacToeBoard, WinOptions.WIN_WAY.ROW2, humanPlayer);
humanOptions[++idx] = new WinOptions(ticTacToeBoard, WinOptions.WIN_WAY.ROW3, humanPlayer);
humanOptions[++idx] = new WinOptions(ticTacToeBoard, WinOptions.WIN_WAY.COL1, humanPlayer);
humanOptions[++idx] = new WinOptions(ticTacToeBoard, WinOptions.WIN_WAY.COL2, humanPlayer);
humanOptions[++idx] = new WinOptions(ticTacToeBoard, WinOptions.WIN_WAY.COL3, humanPlayer);
humanOptions[++idx] = new WinOptions(ticTacToeBoard, WinOptions.WIN_WAY.DIAG_DOWN, humanPlayer);
humanOptions[++idx] = new WinOptions(ticTacToeBoard, WinOptions.WIN_WAY.DIAG_UP, humanPlayer);
//System.out.println("PC HIGH");
for (idx = 0; idx < 8; ++idx) {
//System.out.println(idx + ":" + computerOptions[idx].getWinState() + ":" + computerOptions[idx].getPosition());
if (computerOptions[idx].getWinState().equals(WinOptions.STATE.PREFERRED)) {
return computerOptions[idx].getPosition();
}
}
//System.out.println("HUMAN HIGH");
for (idx = 0; idx < 8; ++idx) {
//System.out.println(idx + ":" + humanOptions[idx].getWinState() + ":" + computerOptions[idx].getPosition());
if (humanOptions[idx].getWinState().equals(WinOptions.STATE.PREFERRED)) {
return humanOptions[idx].getPosition();
}
}
//System.out.println("PC AVAIL");
for (idx = 0; idx < 8; ++idx) {
//System.out.println(idx + ":" + computerOptions[idx].getWinState());
if (computerOptions[idx].getWinState().equals(WinOptions.STATE.AVAILABLE)) {
return computerOptions[idx].getPosition();
}
}
//System.out.println("HUMAN AVAIL");
for (idx = 0; idx < 8; ++idx) {
//System.out.println(idx + ":" + humanOptions[idx].getWinState());
if (humanOptions[idx].getWinState().equals(WinOptions.STATE.AVAILABLE)) {
return humanOptions[idx].getPosition();
}
}
return -1;
}
/**
* Place the computer position
* @param position
* @return
*/
private boolean placement(int position) {
// determine the row and column
int row = position / MAX_ROWS;
int col = position % MAX_COLS;
if (setValueComputer(row, col)) {
System.out.println("Computer played at row " + row + " column " + col);
return true; // found and loaded
}
return false; // default
}
/**
* The computer will play now.
* It will set its mark (X or O) at an empty location.
* Based on Random results - smartPlay flag plays with intelligent mode
*
*/
public boolean theComputersTurn() {
if (smartPlay) {
int answer = bestComputerPlacement();
if (answer != -1) {
if (placement(answer)) {
return true;
} // otherwise continue and issue a random choice
}
}
final int MIN_RANGE = 0;
final int MAX_RANGE = 8;
final int RETRY_LIMIT = 15;
short count = 0;
int boxNumber = 0;
do {
++count;
// Get a Random Number - 0-8 (9 values)
boxNumber = ThreadLocalRandom.current().nextInt(MIN_RANGE, MAX_RANGE + 1);
if (placement(boxNumber)) {
return true; // found and loaded
}
} while (count < RETRY_LIMIT);
return false; // Exiting - Could not find an open spot by random process
}
}