Retrieving data from interface returning enums - java

I have received a project to solve that uses Enums and I am a bit stuck. It's a tic tac toe game that has enums that store the locations of cells in a 3x3 grid table, and enums that store the state of the cells (empty, X, or O). Plus I have an interface for the GameBoard that returns CellState: getCellState (CellLocation cellLocation);
My task is to write the Consultant interface only and I cannot change anything in the code that was provided to me.
I am struggling to check the status of the Board before each step.
My idea was that X starts the game, I use a for loop for steps and at each step, I check if nrOfSteps%2==0. If yes, I set the cellState to player O. Check if we are at winning position, if we have won or if there's a draw. If not, I will suggest a move.
E.g.
if (nrOfSteps%2!=0){
cState =CellState.OCCUPIED_BY_X;
if (isWon(cState, board)){
throw new IllegalStateException("Player X won!");
} else if (draw(board, locations)){
throw new IllegalStateException("No more empty fields!");
} else
for (int remainingCells = 0; remainingCells <9; remainingCells++) {
if (board.equals(locations[remainingCells]) &&
cState==CellState.EMPTY){
availableCells[index] = locations[remainingCells];
index++;
}
CellLocation cellToTake = availableCells[(int)(Math.random()*
(availableCells.length-1))];
return cellToTake;
}
Now, my problem is that I have tried the following for the isWon method (partial code validating only the first row for now):
private boolean isWon(CellState player, GameBoard board){
if (board.equals(CellLocation.TOP_LEFT) && cState==player &&
board.equals(CellLocation.TOP_CENTRE) && cState==player &&
board.equals(CellLocation.TOP_RIGHT) && cState==player){
return true;
}
return false;
}
But I have realized that the current Status of the board could not be equal to only one cell as I am checking in the above code. And it obviously cannot be equal to 3 different "only one cell"-s. And I am not even sure if I could be checking if the board had only one cell occupied by player X by this:
board.equals (CellLocation.TOP_LEFT) && cState==player
Could someone please give a tip on how I can incorporate both the CellState and CellLocation into one query? Should I use arrays? e.g. CellState[][]?

You can calculate the sums of the cells in the matrix(for each column, row and diagonal). Like this:
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
public class CrossAndZeros {
private static CellState winner;
private static Enum[][] field = new Enum[3][3];
public static void main(String[] args) throws IOException {
for (int i = 0; i < field.length; i++) {
for (int j = 0; j < field[i].length; j++) {
field[i][j] = CellState.values()[new Random().nextInt(3)];
}
}
for (Enum[] enums : field) {
System.out.println(Arrays.toString(enums));
}
System.out.println();
System.out.println("Winner is found: " + isWinnerFound());
System.out.println(winner == null ? "No winner, GAME OVER" : winner);
}
private static boolean isWinnerFound() {
int[] result = calculate();
int count = 0;
for (int win : result) {
if (win == 3) {
winner = CellState.OCCUPIED_BY_X;
return true;
} else if (win == -12) {
winner = CellState.OCCUPIED_BY_O;
return true;
} else if (win == -9 || win == -2 || win == -3) { // This means that the line is spoilt
count++;
}
}
return count == 8; // If all the lines are spoilt, the game is over
}
private static int[] calculate() {
int[] result = new int[8];
for (int i = 0; i < field.length; i++) {
for (int j = 0; j < field[i].length; j++) {
result[i] += getCellOwner(field[j][i]); // a column
result[i + 3] += getCellOwner(field[i][j]); // a row
}
result[field.length * 2] += getCellOwner(field[i][i]); // diagonal
result[field.length * 2 + 1] += getCellOwner(field[i][field.length - i - 1]); // diagonal
}
System.out.println(Arrays.toString(result));
return result;
}
private static int getCellOwner(Enum cell) {
switch ((CellState) cell) {
case OCCUPIED_BY_O:
return -4;
case OCCUPIED_BY_X:
return 1;
case EMPTY:
default:
return 0;
}
}
public enum CellState {
/**
* this cell is occupied by player X
*/
OCCUPIED_BY_X,
/**
* this cell is occupied by player O
*/
OCCUPIED_BY_O,
/**
* this cell is Empty
*/
EMPTY
}
}

the CellLocation enum:
public enum CellLocation {
/** The Cell in the top row and leftmost column */
TOP_LEFT,
/** The Cell in the top row and centre column */
TOP_CENTRE,
/** The Cell in the top row and rightmost column */
TOP_RIGHT,
/** The Cell in the centre row and leftmost column */
CENTRE_LEFT,
/** The Cell in the centre row and centre column */
CENTRE_CENTRE,
/** The Cell in the centre row and rightmost column */
CENTRE_RIGHT,
/** The Cell in the bottom row and leftmost column */
BOTTOM_LEFT,
/** The Cell in the bottom row and centre column */
BOTTOM_CENTRE,
/** The Cell in the bottom row and rightmost column */
BOTTOM_RIGHT;
}
the CellState enum:
public enum CellState {
/** this cell is occupied by player X */
OCCUPIED_BY_X,
/** this cell is occupied by player O */
OCCUPIED_BY_O,
/** this cell is Empty */
EMPTY;
}

Related

if statement throws incompatible types: unexpected return value

I'm currently creating a minesweeper game, at the moment I'm just finishing up a method that counts neighboring mines, it also has parameters for the number of rows, columns and mines, I also declared a maxMines variable that doesn't allow more than 20 mines on the grid... Now, I want to make this method return true if the square was successfully mined, and false if the maximum number of mines was exceeded, or the square has already been mined.
Also I want this method to use the parameters to check whether a mine would be on those coordinates and I have no idea where to begin, if anyone can give me a starting point, it would be greatly appreciated.
Here is my code (The error lies at the very bottom of mineTile; if statement):
import java.util.Random;
public class Minefield extends Minesweeper{
boolean[][] minefield;
int[][] minedNeighbour;
Random random = new Random();//random number generator
int row;
int column;
int mines;
public int emptySpaces = column*row;
int maxMines = 20;
public Minefield(int row, int column, int mines) {
this.row = row;
this.column = column;
this.mines = mines;
int x,y;
minedNeighbour = new int[10][10];
//initializeMines(); //fill with zero's
//placeMines(); //get the random numbers and place 10 mines
//fillNoOfSurroundingNeighbours(); //based on the mines 8 boxes surronding the mine will be calculated and shown to the player
//startBoard(); //This fills the actual board
}
public void mineTile(int x, int y){
int i,j; //loop variables
if(minedNeighbour[x][y]!= -1)return; //already used
minedNeighbour[x][y] = 0;//square used
emptySpaces--;//decreases the emptyspaces counter
for (i = x-1 ;i<=x+1 ; i++)
{
for(j = y-1 ;j<=y+1 ; j++)
{
if(minedNeighbour[i][j] == 99)
{
minedNeighbour[x][y]++;
}
if(i >= 0 && j >= 0 && i < 5 && j < 5)
{
if(minedNeighbour[i][j] == 99)
{
minedNeighbour[x][y]++;
}
}
}
}
if(mines > maxMines)
{
return false;
}
else {
return true;
}
}
}
Your method is set to return a void, so that means you can't return anything. If you want to return a boolean, change your method header to reflect that, i.e. by changing it to
public boolean mineTile(int x, int y)

Play method for TicTacToe java

So we got an excercise and need to write a tictactoe class, we need to work with a 2d int array as the board and 2 players, one has a "1" as the "X" and the other one a "2" as the "O", "0" is for empty field. Now we need to write a method for the players to actually set something on the field, but all I can think about is stuff to do with a string or char board and nothing really with an int board. How do you realize this setting of a problem with a number on an int board? Thanks for any help!
I already got a method which checks if there's any free spot available on the board anyways, which should be correct.
public class TicTacToe extends BasicBoard implements Game {
int PlayerA = 1;
int PlayerB = 2;
int empty = 0;
private int row, column;
private int[][] board = new int[column][row];
public boolean isboardfull(int row, int column) {
for (int i = 0; i <= column; i++)
{
for (int j = 0; j <= row; j++)
{
if (board[i][j] == PlayerA || board[i][j] == PlayerB)
return true;
}
}
return false;
}
public void playerturn(){
if (!isboardfull(row, column))
}
}
Your TicTacToe class extends from the BasicBoard and Game classes but you have not provided them. I assume that these classes give you methods to render the board and control the game evolution but since we don't have them I have included something similar (and simple) in my example (to demonstrate how it works). You can skip the game, printBoard, resetBoard, and endGame methods if these are provided by the BasicBoard and Game classes.
Here is a list of assumptions I have made:
The players are asked for the coordinates where to play
The game ends when the board is full. A more complex version should check every iteration of the game if one of the players has won.
And here a general explanation of my approach:
The mapping between X and O to 1 and 2 is set to static constant since this will never change.
The number of rows and columns may vary between executions and its parametrized in the TicTacToe constructor.
The players fill the information through the standard input when prompted.
The game function asks for the players to move and renders the board (on the standard output) until the board is completely filled.
The isBoardFull function checks if there are empty slots on the board or not. Thus, if we find an empty slot we know it is not full, otherwise we need to keep searching for empty slots. If we search through all the board and there are no empty slots, then it is full. (in my opinion, this part is miss-written in the coded you provided)
The playerTurn function asks for the coordinates where the player wants to play and fills the board. To do so, we scan 2 lines of the standard input, convert them to int and check if the position is empty and within bounds. If so, we mark the position with the player number.
The code:
public class TicTacToe {
private static final int PLAYER_A = 1;
private static final int PLAYER_B = 2;
private static final int EMPTY = 0;
private final int numRows;
private final int numColumns;
private final int[][] board;
private final Scanner inputScanner;
public TicTacToe(int numRows, int numColumns) {
// Retrieve board sizes
this.numRows = numRows;
this.numColumns = numColumns;
// Instantiate board
this.board = new int[numRows][numColumns];
// Initialize board
resetBoard();
// Initialize the input scanner (for player choices)
this.inputScanner = new Scanner(System.in);
}
public void game() {
// Initialize the game
int numMoves = 0;
printBoard(numMoves);
// Play until the game is over
while (!isBoardFull() && !hasPlayerWon()) {
// A or B player should move
int currentPlayer = (numMoves % 2 == 0) ? PLAYER_A : PLAYER_B;
playerTurn(currentPlayer);
// We increase the number of moves
numMoves += 1;
// We render the board
printBoard(numMoves);
}
// Check winner and close game
endGame();
}
private void resetBoard() {
for (int i = 0; i < this.numRows; ++i) {
for (int j = 0; j < this.numColumns; ++j) {
this.board[i][j] = EMPTY;
}
}
}
private void printBoard(int currentMove) {
System.out.println("Move: " + currentMove);
for (int i = 0; i < this.numRows; ++i) {
for (int j = 0; j < this.numColumns; ++j) {
System.out.print(this.board[i][j] + " ");
}
System.out.println();
}
// A new line to split moves
System.out.println();
}
private boolean isBoardFull() {
for (int i = 0; i < this.numRows; ++i) {
for (int j = 0; j < this.numColumns; ++j) {
if (this.board[i][j] == EMPTY) {
// If there is an empty cell, the board is not full
return false;
}
}
}
// If there are no empty cells, the board is full
return true;
}
private boolean hasPlayerWon() {
// TODO: Return whether a player has won the game or not
return false;
}
private void playerTurn(int currentPlayer) {
// Log player information
System.out.println("Turn for player: " + currentPlayer);
// Ask the player to pick a position
boolean validPosition = false;
while (!validPosition) {
// Ask for X position
int posX = askForPosition("row", this.numRows);
// Ask for Y position
int posY = askForPosition("column", this.numColumns);
// Check position
if (posX >= 0 && posX < this.numRows) {
if (posY >= 0 && posY < this.numColumns) {
if (this.board[posX][posY] == EMPTY) {
// Mark as valid
validPosition = true;
// Mark the position
this.board[posX][posY] = currentPlayer;
} else {
System.out.println("Position is not empty. Please choose another one.");
}
} else {
System.out.println("Column position is not within bounds. Please choose another one.");
}
} else {
System.out.println("Row position is not within bounds. Please choose another one.");
}
}
}
private int askForPosition(String rc, int dimensionLimit) {
System.out.println("Select a " + rc + " position between 0 and " + dimensionLimit);
return Integer.valueOf(this.inputScanner.nextLine());
}
private void endGame() {
// Close input scanner
this.inputScanner.close();
// Log game end
System.out.println("GAME ENDED!");
// TODO: Check the board status
System.out.println("Draw");
}
public static void main(String[] args) {
TicTacToe ttt = new TicTacToe(3, 4);
ttt.game();
}
}
Example Output:
Move: 0
0 0 0 0
0 0 0 0
0 0 0 0
Turn for player: 1
Select a row position between 0 and 3
4
Select a column position between 0 and 4
1
Row position is not within bounds. Please choose another one.
Select a row position between 0 and 3
1
Select a column position between 0 and 4
1
Move: 1
0 0 0 0
0 1 0 0
0 0 0 0
Turn for player: 2
.
.
.
Move: 12
2 2 1 2
1 1 2 1
1 2 1 2
GAME ENDED!
Draw

Can i define the amount of times a specific number is displayed in math.random? (Java)

So, this is for an assignment, it's coming along quite well, i just can't seem to get
past this part where i have to set it to only add 4 X's and 5 O's. i've been trying some options but i figured i would dump the code that actually works so far on here, if anybody would like to assist that would be appreciated.
"Write a program that simulates a game of tic-tac-toe and
indicates whether a player wins, and which.
The program should:
• Declare and use an array of int of size [3,3] to represent the tic-tac-toe grid
• Fill each position in the array with either a -1 or +1 as follows
• 4 ‘X’s represented by -1
• 5 ‘O’s represented by +1
• Display the grid
• Evaluate and indicate if the player that uses ‘X’ won.
• Evaluate and indicate if the player that uses ‘O’ won.
Program must implement and use at least the following methods:
• public static void fillGridWithRandomValues(int[][] grid)
o Receives an array and fills is with -1 and 1 chosen randomly
• public static void printGrid(int[][] grid)
o Displays the grid on the screen
• public static boolean evaluateWinner(int[][] grid, int value)
o Returns true when there is at least 3 positions in the same
row, or the same column or the same diagonal that contain the
parameter ‘value’. Returns false otherwise"
And here's the actual code.
package 123456;
/**
*
* #author 123456
*/
public class 123456 {
/**
* #param args the command line arguments
*/
public static void fillGridWithRandomValues(int[][] grid) {
for (int row=0; row < grid.length; row++) {
for (int column=0; column < grid[row].length; column++) {
grid[row][column] = (int) (((Math.random()*2)*2)-2);
if (grid[row][column] == 0) grid[row][column]++;
}
};
}
public static boolean evaluateWinner(int[][] grid, int value) {
return false;
}
public static void printGrid(int[] row) {
for (int i : row) {
String str = null;
if (i == 1) str = "X";
else if (i == -1) str = "O";
else str = null ;
System.out.print(str + " ");
System.out.print(" ");
}
System.out.println();
}
public static void main(String[] args) {
// creating array for the grid
int[][] grid ;//= { { 1, -1, 1 }, { -1, 1, -1 }, { 1, -1, } };
grid = new int[3][3];
fillGridWithRandomValues(grid);
for(int[] row : grid) {
printGrid(row);
}
}
}
No, Math.random() is specifically designed to give unpredictable results.

Sudoku generator: ArrayOutOfBoundsException

In this project, I am trying to write a program that creates a 9x9 Sudoku board with 9 3x3 subgrids, along with a header row and column that lists the letters a to i. The program compiles correctly, but when I hit run, it gives the following error:
java.lang.ArrayIndexOutOfBoundsException: 0
at Sudoku.main(Sudoku.java:218)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at `enter code here`edu.rice.cs.drjava.model.compiler.JavacCompiler.runCommand(JavacCompiler.java:272)
Now, when I submitted this, the grading program stated that my print(), rowsComplete(), columnsComplete(), and isComplete() methods were incorrect, and that my main() was throwing a java.util.NoSuchElementException. I am confused as to why this is happening. Here is my code for Java, as well as notes on what exactly the methods are supposed to be doing.
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
public class Sudoku
{
public static final int SIZE = 9;
public static final int SUBGRID = 3;
public int[][] game;
public int[][] originalGame;
public Sudoku(String puzzleFile)
{
try
{
game = new int[SIZE][SIZE];
originalGame = new int[SIZE][SIZE];
File file = new File(puzzleFile);
Scanner in = new Scanner(file);
int i = 0;
int j = 0;
int k;
for (i = 0; i<SIZE; i++){
for (j = 0; j<SIZE; j++){
k = in.nextInt();
game[i][j]=k;
originalGame[i][j] = k;
}
}
}
catch (FileNotFoundException e)
{
System.out.println("FileNotFound: " + e.getMessage());
}
}
public void setZero(int[] array)
{
int i = 0;
for (i = 0; i < array.length; i++)
{
array[i] = 0;
}
}
/**
* This method determines whether the ints 1-9 are present exactly
* once in each row. Sets valSeen[i] = 1 if it sees i. If at any
* point valSeen[i] is already 1, the rows are not complete because of
* duplicate entries.
*
* If game[x][y] == -1, there is a blank entry so the row cannot be complete.
*
* #param valSeen: an array of ints that serve as flags to indicate whether
* their entry has been seen before or not.
*
* returns: true if each digit 1-9 is present in the row exactly once, else false
**/
public boolean rowsComplete(int[] valSeen)
{
int temp;
int k = 0;
for(int rows = 0; rows<SIZE; rows++){
for(int cols = 0; cols<SIZE; cols++){
if(game[rows][cols]==-1)
return false;
temp = game[rows][cols];
valSeen[temp-1]++;
}
for(k=0; k<valSeen.length; k++){
if(valSeen[k]!=1)
return false;
else return true;
}
setZero(valSeen);
}
return true;
}
/**
* This method determines whether the ints 1-9 are present exactly
* once in each column. Sets valSeen[i] = 1 if it sees i. If at any
* point valSeen[i] is already 1, the rows are not complete because of
* duplicate entries.
*
* If game[x][y] == -1, there is a blank entry so the row cannot be complete.
*
* #param valSeen: an array of ints that serve as flags to indicate whether
* their entry has been seen before or not.
*
* returns: true if each digit 1-9 is present in the column exactly once, else false
**/
public boolean columnsComplete(int[] valSeen)
{
int temp;
int k = 0;
for(int cols = 0; cols<SIZE; cols++){
for(int rows = 0; rows<SIZE; rows++){
if(game[rows][cols]==-1)
return false;
temp = game[rows][cols];
valSeen[temp-1]++;
}
for(k=0; k<valSeen.length; k++){
if(valSeen[k]!=1)
return false;
else return true;
}
setZero(valSeen);
}
return true;
}
/**
* This method determines whether the ints 1-9 are present exactly
* once in each subgrid. Sets valSeen[i] = 1 if it sees i. If at any
* point valSeen[i] is already 1, the rows are not complete because of
* duplicate entries.
*
* If game[x][y] == -1, there is a blank entry so the row cannot be complete.
*
* #param valSeen: an array of ints that serve as flags to indicate whether
* their entry has been seen before or not.
*
* returns: true if each digit 1-9 is present in each subgrid exactly once, else false
**/
public boolean subgridsComplete(int[] valSeen)
{
int temp;
for(int rows=0; rows<SIZE; rows+=3){
for (int cols=0; cols<SIZE; cols+=3){
for(int subrows=0; subrows<SUBGRID; subrows++){
for (int subcols=0; subcols<SUBGRID; subcols++){
temp= game[rows+subrows][cols+subcols];
if(temp==-1)
return false;
else
valSeen[temp-1]++;
}
}
for(int k=0; k<valSeen.length; k++){
if(valSeen[k]!=1)
return false;
else return true;
}
setZero(valSeen);
}
}
return true;
}
// Create the array valSeen here. I suggest making it = new int[SIZE+1].
// That way, it will have indexes 0-9, so the ints 1-9 can go into indexes
// 1-9 instead of mapping them to 0-8 by subtracting 1.
// Call rowsComplete(), columnsComplete(), and subgridsComplete().
// Be SURE to initialize valSeen to 0 before each method call by using setZero().
public boolean isComplete()
{
int [] valSeen = new int[SIZE+1];
setZero(valSeen);
if(rowsComplete(valSeen) && columnsComplete(valSeen) && subgridsComplete(valSeen))
return true;
else
return false;
}
public String makeHeader()
{
String header = " ";
for (int x = 97; x<106; x++)
header += ((char)x) + " | " + " ";
return header;
}
/**
* Prints out the grid. Each entry has a space to either side, columns are separated by '|'
* within the grid / between the header and the grid but not externally. See the specification
* for a detailed example. -1 is replaced with '_'.
*
* Remember that 'a' + 1 = 'b'
*
* Prints the grid to standard out.
**/
public void print()
{
System.out.println(makeHeader());
for(int rows=0; rows<SIZE; rows++){
System.out.print(" "+(char)('a'+rows));
for (int cols=0; cols<SIZE; cols++){
if (game[rows][cols]==-1)
System.out.print(" | _");
else
System.out.print(" | "+game[rows][cols]);
}
System.out.println();
}
}
public void move(String row, String col, int val)
{
int rowNumber = ((int)(row.charAt(0)-97));
int columnNumber = ((int)(col.charAt(0)-97));
if(originalGame[rowNumber][columnNumber]==-1)
game[rowNumber][columnNumber]=val;
}
public static void main(String[] args)
{
Sudoku puzzle = new Sudoku(args[0]);
Scanner s = new Scanner(System.in);
System.out.println("");
boolean gameplay = true;
while (gameplay){
puzzle.print();
if(puzzle.isComplete()){
System.out.println("Puzzle Complete!");
gameplay=false;
} else {
System.out.println("Puzzle Incomplete!");
System.out.println("Enter new value <row col val> :");
String rowv = s.next();
String colv = s.next();
int valv = s.nextInt();
puzzle.move(rowv, colv, valv);
}
}
}
}
In main method,
Sudoku puzzle = new Sudoku(args[0]);
Your program need an argument to initialize Sudoku which is being taken from user.
String[] args in main is a array of arguments for program which is given as parameters while starting program.
For you program, you'll have to start your Sudoku.class as
java Sudoku argument
You'll have to run you program with argument, else you'll get java.lang.ArrayIndexOutOfBoundsException: 0

Representing game states in Tic Tac Toe

The goal of the assignment that I'm currently working on for my Data Structures class is to create a of Quantum Tic Tac Toe with an AI that plays to win.
Currently, I'm having a bit of trouble finding the most efficient way to represent states.
Overview of current Structure:
AbstractGame
Has and manages AbstractPlayers (game.nextPlayer() returns next player by int ID)
Has and intializes AbstractBoard at the beginning of the game
Has a GameTree (Complete if called in initialization, incomplete otherwise)
AbstractBoard
Has a State, a Dimension, and a Parent Game
Is a mediator between Player and State, (Translates States from collections of rows to a Point representation
Is a StateConsumer
AbstractPlayer
Is a State Producer
Has a ConcreteEvaluationStrategy to evaluate the current board
StateTransveralPool
Precomputes possible transversals of "3-states".
Stores them in a HashMap, where the Set contains nextStates for a given "3-state"
State
Contains 3 Sets -- a Set of X-Moves, O-Moves, and the Board
Each Integer in the set is a Row. These Integer values can be used to get the next row-state from the StateTransversalPool
SO, the principle is
Each row can be represented by the binary numbers 000-111, where 0 implies an open space and 1 implies a closed space.
So, for an incomplete TTT board:
From the Set<Integer> board perspective:
X_X R1 might be: 101
OO_ R2 might be: 110
X_X R3 might be: 101, where 1 is an open space, and 0 is a closed space
From the Set<Integer> xMoves perspective:
X_X R1 might be: 101
OO_ R2 might be: 000
X_X R3 might be: 101, where 1 is an X and 0 is not
From the Set<Integer> oMoves perspective:
X_X R1 might be: 000
OO_ R2 might be: 110
X_X R3 might be: 000, where 1 is an O and 0 is not
Then we see that x{R1,R2,R3} & o{R1,R2,R3} => board{R1,R2,R3}
The problem is quickly generating next states for the GameTree. If I have player Max (x) with board{R1,R2,R3}, then getting the next row-states for R1, R2, and R3 is simple..
Set<Integer> R1nextStates = StateTransversalPool.get(R1);
The problem is that I have to combine each one of those states with R1 and R2.
Is there a better data structure besides Set that I could use? Is there a more efficient approach in general? I've also found Point<->State mediation cumbersome. Is there another approach that I could try there?
Thanks!
Here is the code for my ConcretePlayer class. It might help explain how players produce new states via moves, using the StateProducer (which might need to become StateFactory or StateBuilder).
public class ConcretePlayerGeneric extends AbstractPlayer {
#Override
public BinaryState makeMove() {
// Given a move and the current state, produce a new state
Point playerMove = super.strategy.evaluate(this);
BinaryState currentState = super.getInGame().getBoard().getState();
return StateProducer.getState(this, playerMove, currentState);
}
}
EDIT: I'm starting with normal TTT and moving to Quantum TTT. Given the framework, it should be as simple as creating several new Concrete classes and tweaking some things.
My suggestion:
Consider representing individual squares rather than rows, whereby +1 == O, -1 == X and 0 implies an empty square. This allows you to detect an end state by checking whether the sum of a horizontal, vertical or diagonal row equals +3 or -3.
Secondly "flatten" this 2D 3x3 matrix into a single array whereby elements[0-2] represent the first row, elements[3-5] represent the second row and elements[6-8] represent the third row.
Use either recursion or an iterative approach to generate subsequent game states given the current state of the board.
EDIT
I got bored and so decided to write some "toy code" to implement the game board, including methods to determine if it is in a terminal state and to generate the set of board states after the next move is made. It should generalise to any size board although I haven't tried. Enjoy ...
Sample Output
$ java Board
Creating board:
---
---
---
Initialising board:
-OX
O--
XO-
Terminal state: false
Generating next move states:
XOX
O--
XO-
-OX
OX-
XO-
-OX
O-X
XO-
-OX
O--
XOX
Code
import java.util.List;
import java.util.LinkedList;
import java.util.Random;
public class Board {
private final int[] squares;
public Board() {
this.squares = new int[9];
}
protected Board(int[] squares) {
this.squares = squares;
}
public void init() {
Random rnd = new Random();
int turn = 1; // 'O' always goes first.
for (int i=0; i<squares.length; ++i) {
double d = rnd.nextDouble();
if (d < 0.75) {
squares[i] = turn;
turn = turn == 1 ? -1 : 1; // Flip to other player's turn.
} else {
squares[i] = 0; // Empty square.
}
if (isTerminalState()) {
break;
}
}
}
public boolean isTerminalState() {
boolean ret = false;
boolean foundEmpty = false;
int hSum = 0;
int[] vSum = new int[3];
for (int i=0; i<squares.length; ++i) {
hSum += squares[i];
if (isWinningRow(hSum)) {
ret = true;
break;
} else if (i == 2 || i == 5) {
hSum = 0;
}
int col = i % 3;
vSum[col] += squares[i];
if (isWinningRow(vSum[col])) {
ret = true;
break;
}
if (squares[i] == 0) {
foundEmpty = true;
}
}
if (!ret) {
if (!foundEmpty) {
ret = true;
} else {
int diag1 = 0;
int diag2 = 0;
int rowSz = (int)Math.sqrt(squares.length);
for (int i=0; i<squares.length; ++i) {
if (i % (rowSz + 1) == 0) {
diag1 += squares[i];
if (isWinningRow(diag1)) {
ret = true;
break;
}
}
if (i > 0 && i % (rowSz - 1) == 0) {
diag2 += squares[i];
if (isWinningRow(diag2)) {
ret = true;
break;
}
}
}
}
}
return ret;
}
private boolean isWinningRow(int rowSum) {
return rowSum == 3 || rowSum == -3;
}
public List<Board> getNextStates() {
List<Board> ret = new LinkedList<Board>();
int tmp = 0;
for (int i=0; i<squares.length; ++i) {
tmp += squares[i];
}
// Next turn is 'O' (i.e. +1) if the board sums to 0.
// Otherwise it's 'X's turn.
int turn = tmp == 0 ? 1 : -1;
if (!isTerminalState()) {
for (int i=0; i<squares.length; ++i) {
if (squares[i] == 0) { // Empty square
int[] squaresA = new int[squares.length];
System.arraycopy(squares, 0, squaresA, 0, squares.length);
squaresA[i] = turn;
ret.add(new Board(squaresA));
}
}
}
return ret;
}
public String toString() {
StringBuilder sb = new StringBuilder();
for (int i=0; i<squares.length; ++i) {
if (squares[i] == 1) {
sb.append('O');
} else if (squares[i] == -1) {
sb.append('X');
} else {
assert squares[i] == 0;
sb.append('-');
}
if (i == 2 || i == 5) {
sb.append('\n');
}
}
return sb.toString();
}
public static void main(String[] args) {
System.err.println("Creating board:\n");
Board bd = new Board();
System.err.println(bd);
System.err.println("\nInitialising board:\n");
bd.init();
System.err.println(bd);
System.err.println("Terminal state: " + bd.isTerminalState() + '\n');
System.err.println("\nGenerating next move states:\n");
List<Board> nextStates = bd.getNextStates();
for (Board bd1 : nextStates) {
System.err.println(bd1.toString() + '\n');
}
}
}
Shouldn't each square have only three possible states (, X, O)?
Either store a grid of 3-state squares, or store 2 lists of moves. You don't need to store the overall board because it is defined by the moves.
Also, what do you mean by:
generating next states for the
GameTree
What is a GameTree? and what are some examples of "next states"?

Categories