Instructions
Objective
Write a Java assignment program to build a Nim and tic tac toe game using programming language.
Requirements and Specifications
Create a game build based on tic tac toe and Nim game
Use methods, classes and functions for this program
The game should work on a single run basis
Source Code
TIC TAC TOE
package game;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
class TicTacToe5 implements Game {
private static final int EMPTY = 4;
private static final String COMPUTER_SYMBOL = "O";
private static final String HUMAN_SYMBOL = "X";
private int[][] board = new int[3][3];
private Map store = new HashMap<>();
private int nextPlayer;
private Scanner scanner;
/**
* Construct an instance of the TicTacToe Game
*/
public TicTacToe5(Scanner scanner) {
if (scanner == null) {
throw new IllegalArgumentException("Scanner must not be null");
}
this.scanner = scanner;
}
@Override
public void init() {
clearBoard();
nextPlayer = COMPUTER;
}
@Override
public int winner() {
return positionValue();
}
@Override
public int nextPlayer() {
return nextPlayer;
}
@Override
public String[] askHumanMove() {
String[] params = new String[2];
System.out.println("row: ");
params[0] = scanner.nextLine();
System.out.println("col: ");
params[1] = scanner.nextLine();
return params;
}
// Find optimal move
@Override
public Best chooseMove(int side) {
return chooseMove(side, -4);
}
// Play move, including checking legality
@Override
public boolean makeMove(int side, int row, int column) {
if (row < 0 || row >= 3 || column < 0 || column >= 3 || board[row][column] != EMPTY)
return false;
board[row][column] = side;
nextPlayer = 2 - nextPlayer;
return true;
}
@Override
public String position() {
StringBuilder boardStr = new StringBuilder();
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
String spot;
switch (board[row][col]) {
case HUMAN:
spot = " " + HUMAN_SYMBOL + " ";
break;
case COMPUTER:
spot = " " + COMPUTER_SYMBOL + " ";
break;
case EMPTY:
spot = " ";
break;
default:
throw new IllegalArgumentException();
}
boardStr.append(spot);
if (col < 2)
boardStr.append("|");
}
if (row < 2)
boardStr.append("\n-----------\n");
}
return boardStr.toString();
}
private Best chooseMove(int side, int depth) {
int opp; // The other side
Best reply; // Opponent's best reply
int simpleEval; // Result of an immediate evaluation
int bestRow = -1; // Initialize running value with out-of-range value
int bestColumn = -1;
int value;
Position thisPosition = new Position(board);
if ((simpleEval = positionValue()) != UNCLEAR)
return new Best(simpleEval);
// Don't look up top-level value: can't use it (already used for last move)
if (depth > 0) {
Integer lookupVal = store.get(thisPosition);
if (lookupVal != null)
return new Best(lookupVal);
}
// Initialize running values with out-of-range values (good software practice)
// Here also to ensure that *some* move is chosen, even if a hopeless case
if (side == COMPUTER) {
opp = HUMAN;
value = HUMAN - 1; // impossibly low value
} else {
opp = COMPUTER;
value = COMPUTER + 1; // impossibly high value
}
for (int row = 0; row < 3; row++)
for (int column = 0; column < 3; column++)
if (squareIsEmpty(row, column)) {
place(row, column, side);
reply = chooseMove(opp, depth+1);
place(row, column, EMPTY);
// Update if side gets better position
if (side == COMPUTER && reply.val > value || side == HUMAN && reply.val < value) {
value = reply.val;
bestRow = row;
bestColumn = column;
}
}
store.put(thisPosition, value);
return new Best(value, bestRow, bestColumn);
}
// Simple supporting routines
private void clearBoard() {
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
board[i][j] = EMPTY;
}
private boolean boardIsFull() {
for (int row = 0; row < 3; row++)
for (int column = 0; column < 3; column++)
if (board[row][column] == EMPTY)
return false;
return true;
}
private boolean isAWin(int side) {
int row, column;
/* Look for all in a row */
for (row = 0; row < 3; row++) {
for (column = 0; column < 3; column++)
if (board[row][column] != side)
break;
if (column >= 3)
return true;
}
/* Look for all in a column */
for (column = 0; column < 3; column++) {
for (row = 0; row < 3; row++)
if (board[row][column] != side)
break;
if (row >= 3)
return true;
}
/* Look on diagonals */
if (board[1][1] == side && board[2][2] == side && board[0][0] == side)
return true;
return board[0][2] == side && board[1][1] == side && board[2][0] == side;
}
// Play a move, possibly clearing a square
private void place(int row, int column, int piece) {
board[row][column] = piece;
}
private boolean squareIsEmpty(int row, int column) {
return board[row][column] == EMPTY;
}
// Compute static value of current position (win, draw, etc.)
private int positionValue() {
return isAWin(COMPUTER) ? COMPUTER : isAWin(HUMAN) ? HUMAN : boardIsFull() ? DRAW : UNCLEAR;
}
final static class Position {
private int[][] board;
public Position(int[][] theBoard) {
board = new int[3][3];
for (int i = 0; i < 3; i++)
System.arraycopy(theBoard[i], 0, board[i], 0, 3);
}
public boolean equals(Object rhs) {
if (!(rhs instanceof Position))
return false;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
if (board[i][j] != ((Position) rhs).board[i][j])
return false;
return true;
}
public int hashCode() {
int hashVal = 0;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
hashVal = hashVal * 4 + board[i][j];
return hashVal;
}
}
}
NIM
package game;
import java.util.Scanner;
public class Nim5 implements Game{
private final static int NUM_ROWS = 3;
private final static int SZ_ROW0 = 5;
private final static int SZ_ROW1 = 3;
private final static int SZ_ROW2 = 1;
// These fields represent the actual position at any time.
private int[] heap = new int[NUM_ROWS];
private int nextPlayer;
private Scanner scanner;
/**
* Construct an instance of the Nim Game
*/
public Nim5(Scanner scanner) {
if (scanner == null) {
throw new IllegalArgumentException("Scanner must not be null");
}
this.scanner = scanner;
}
/**
* Set up the position ready to play.
*/
@Override
public void init() {
heap[0] = SZ_ROW0;
heap[1] = SZ_ROW1;
heap[2] = SZ_ROW2;
nextPlayer = COMPUTER;
}
/**
* Who has won the game? Returns one of HUMAN, COMPUTER, UNCLEAR
*
* @return the winner.
*/
@Override
public int winner() {
if (nextPlayer == HUMAN && getStarsLeft() == 0) {
return COMPUTER;
}
if (nextPlayer == COMPUTER && getStarsLeft() == 0) {
return HUMAN;
}
return UNCLEAR;
}
@Override
public int nextPlayer() {
return nextPlayer;
}
@Override
public String[] askHumanMove() {
String[] params = new String[2];
System.out.println("row: ");
params[0] = scanner.nextLine();
System.out.println("stars: ");
params[1] = scanner.nextLine();
return params;
}
/**
* Make a move
*
* @param side of player making move
* @param row to take stars from
* @param number of stars taken.
* @return false if move is illegal.
*/
@Override
public boolean makeMove(int side, int row, int number) {
if (side != nextPlayer) {
return false; // wrong player played
}
if (!isLegal(row, number)) {
return false;
} else {
nextPlayer = 2 - nextPlayer;
heap[row] = heap[row] - number;
}
return true;
}
@Override
public Best chooseMove(int side) {
Best best = null;
for (int i = 0; i < NUM_ROWS; i++) {
for (int j = 1; j <= heap[i]; j++) {
heap[i] -= j;
nextPlayer = 2 - side;
int winner = winner();
if (winner != UNCLEAR) {
heap[i] += j;
nextPlayer = side;
if (best == null) {
best = new Best(winner, i, j);
}
if (winner == side) {
return new Best(winner, i, j);
}
} else {
Best stepBest = chooseMove(2 - side);
heap[i] += j;
nextPlayer = side;
if (side == stepBest.val) {
return new Best(side, i, j);
}
best = stepBest;
}
}
}
return best;
}
/**
* This method displays current position
*/
@Override
public String position() {
StringBuilder board = new StringBuilder();
for (int i = 0; i < NUM_ROWS; i++) {
char c = (char) ((int) 'A' + i);
board.append(c).append(": ");
for (int j = heap[i]; j > 0; j--) {
board.append("* ");
}
board.append('\n');
}
return board.toString();
}
/**
* Compute the total number of stars left.
*/
private int getStarsLeft() {
return (heap[0] + heap[1] + heap[2]);
}
private boolean isLegal(int row, int stars) {
return 0 <= row && row <= 2 && stars >= 1 && stars <= heap[row];
}
}