I am creating a scalable TicTacToe program, and I am running into an issue when trying to check the diagonals for a string.
I was able to check the rows by using this method:
public boolean checkRowsForWin(String b){
//Check all the rows for a winner
for(int y = 0; y < size; y++){
for (int x = 0; x < size; x++){
if (globalGrid[y][x].equals(b)){
inRow++;
if (inRow >= neededToWin){
return true;
}
}else{
inRow = 0;
}
}
inRow = 0;
}
inRow = 0;
return false;
}
I have tried a combination of for loops and if statements, and my last modification is this below. This worked if the diagonal included the top right corner only, when I need it to check even if the diagonal isn't in a corner.
public boolean checkDiagForWin(String b, int c, int d){
for (int x = c, y = d; x < size && y < size; x++, y++){
if (globalGrid[y][x].equals(b)){
inRow++;
if (inRow >= neededToWin){
return true;
}
}
else{
inRow = 0;
}
inRow = 0;
for (int x2 = size - 1, y2 = 0; x2 >=0 && y2 < size; x2--, y2++){
if (globalGrid[y2][x2].equals(b)){
inRow++;
if (inRow >= neededToWin){
return true;
}
}
else{
inRow = 0;
}
}
inRow = 0;
}
inRow = 0;
return false;
}
The amount in a row and the size of the board can change, so it isn't as simple as checking just two adjacent to the position.
You need to start the process starting at every possible position, one possible implementation could be:
A function to start the check process at every position:
public boolean checkDiagonals(String b) {
/* Check the diagonals starting in every position */
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (checkDiagonalForWin(b, i, j) || checkOtherDiagonalForWin(b, i, j)) {
return true;
}
}
}
return false;
}
There are the functions to check the diagonals starting in some position:
public boolean checkDiagonalForWin(String b, int row, int col){
for (int inRow = 0; row < size && col < size; row++, col++) {
//Check all the rows for a winner
if (globalGrid[row][col].equals(b)){
inRow++;
if (inRow >= neededToWin){
return true;
}
}else{
inRow = 0;
}
}
return false;
}
public boolean checkOtherDiagonalForWin(String b, int row, int col){
for (int inRow = 0; row < size && col >= 0; row++, col--) {
//Check all the rows for a winner
if (globalGrid[row][col].equals(b)){
inRow++;
if (inRow >= neededToWin){
return true;
}
}else{
inRow = 0;
}
}
return false;
}
Related
I have no idea what the problem is .I printed the moveVal all the time it prints 0 and its going in a horizontal order.
The I have been editing a changing the code by using Google and YouTube but, there was no good
static class Move {
int row, col;
}
private boolean equals(JButton a, JButton b, JButton c){
return a.getText().equals(b.getText()) && b.getText().equals(c.getText()) && !a.getText().equals("");
}
private boolean isGameOver() {
for (int i = 0; i < 3; i++) {
if (equals(board[i][0], board[i][1], board[i][2])) {
return true;
}
}
for (int i = 0; i < 3; i++) {
if (equals(board[0][i], board[1][i], board[2][i])) {
return true;
}
}
if (equals(board[0][0], board[1][1], board[2][2])) {
return true;
}
else if (equals(board[2][0], board[1][1], board[0][2])) {
return true;
}
int openSpots = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[i][j].getText().equals("")) {
openSpots++;
}
}
}
return openSpots == 0;
}
private int evaluate(JButton[][] b) {
for (int row = 0; row < 3; row++)
{
if (b[row][0] == b[row][1] &&
b[row][1] == b[row][2])
{
if (b[row][0].getText().equals(ai))
return 20;
else if (b[row][0].getText().equals(human))
return -10;
}
}
for (int col = 0; col < 3; col++)
{
if (b[0][col] == b[1][col] &&
b[1][col] == b[2][col])
{
if (b[0][col].getText().equals(ai))
return 20;
else if (b[0][col].getText().equals(human))
return -10;
}
}
if (b[0][0] == b[1][1] && b[1][1] == b[2][2])
{
if (b[0][0].getText().equals(ai))
return 20;
else if (b[0][0].getText().equals(human))
return -10;
}
if (b[0][2] == b[1][1] && b[1][1] == b[2][0])
{
if (b[0][2].getText().equals(ai))
return 20;
else if (b[0][2].getText().equals(human))
return -10;
}
return 0;
}
private int minimax(JButton[][] position, int depth, boolean isMax) {
if (isGameOver() || depth == 0){
return evaluate(position);
}
else if (isMax)
{
int best = -1000000000;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (position[i][j].getText().equals(""))
{
position[i][j].setText(ai);
JButton[][] position1 = position;
best = Math.max(best, minimax(position1, depth - 1, false));
System.out.println(best);
position[i][j].setText("");
}
}
}
return best;
}
else
{
int best1 = 1000000000;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (position[i][j].getText().equals(""))
{
position[i][j].setText(human);
JButton[][] position1 = position;
best1 = Math.min(best1, minimax(position1, depth - 1, true));
position[i][j].setText("");
}
}
}
return best1;
}
}
private void BestMove(JButton[][] board) {
int bestVal = -1000000000;
Move bestMove = new Move();
bestMove.row = -1;
bestMove.col = -1;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (board[i][j].getText().equals(""))
{
board[i][j].setText(ai);
int moveVal = minimax(board, 3, false);
board[i][j].setText("");
if (moveVal > bestVal)
{
bestVal = moveVal;
bestMove.row = i;
bestMove.col = j;
}
}
}
}
board[bestMove.row][bestMove.col].setText(ai);
playersTurn = true;
CheckWinner();
}
Any ideas & please help is needed
past 3 days I have been debugging I know this code is not the best in fact this code might be the worst you have ever seen.
Blockquote
You have only 3 possible evaluations:
20, if the AI wins
-10, if the human wins
0, in all other cases
As you only look at 4 turns (ai, human, ai, human), it's impossible to find a winning position, so the evaluation is always 0.
There is no obvious issue with your implementation of the minimax, however your evaluation function is too simple.
You can, for example:
Give more points to playing in a position that creates a row of 2
Give more points to playing in a position that creates multiple rows of 2
Give less points to a position that is already blocked
However, there is only so much you can do. This game is obviously solved, and a perfect player can always get a draw playing either sides.
This question already has answers here:
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Closed 3 years ago.
My sudoku solver replaces "-" with zeros, then solves the puzzle. It works for most puzzles that I've tried, but throws an ArrayIndexOutOfBoundsException for puzzles with a full row of dashes. I've tried tweeking different things to get it to work, but I'm a little lost.
This is what the puzzle looks like.
public static int[][] theArray = new int [9][9];
public static int SIZE = 9;
private static boolean isCompletePuzzle() {
// checks for 0 in rows/cols
for (int i = 0; i <= SIZE; i++) {
for (int j = 0; j <= SIZE; j++) {
if (theArray[i][j] != 0) {
return true;
}
}
}
return false;
}
private static boolean isValidPuzzle(int row, int col, int number) {
// checks rows
for (int i = 0; i < SIZE; i++) {
if (theArray[row][i] == number) {
return true;
}
}
// checks columns
for (int i = 0; i < SIZE; i++) {
if (theArray[i][col] == number) {
return true;
}
}
// checks 3x3
int r = row - row % 3;
int c = col - col % 3;
for (int i = r; i < r + 3; i++)
for (int j = c; j < c + 3; j++)
if (theArray[i][j] == number)
return true;
return false;
}
private static boolean isSolvedPuzzle(int row, int col, int number) {
if (isValidPuzzle(row, col, number) == true && isCompletePuzzle() == true) {
return true;
}
return false;
}
public static boolean solvePuzzle() {
for (int row = 0; row < SIZE; row++) {
for (int col = 0; col < SIZE; col++) {
if (theArray[row][col] == 0) {
for (int number = 1; number <= SIZE; number++) {
if (!isSolvedPuzzle(row, col, number)) {
theArray[row][col] = number;
if (solvePuzzle()) {
return true;
}
else {
theArray[row][col] = 0;
}
}
}
return false;
}
}
}
return true;
}
in ur isCompletePuzzle() function ur loop conditions i <= SIZE and j <= SIZE cause ArrayIndexOutOfBoundsException
when i is 9 the if (theArray[i][j] != 0) throw ArrayIndexOutOfBoundsException
I'm trying to code a method which checks for duplicates on my Sudoku board. Currently, my method getFrontier() always returns true, and I've come to learn that it's because it's only checking for one value rather than an array or values. I use the method 3 times in squareCheck(), rowCheck() and columnCheck(). Is there any way to code the method so it would retain the previous value which was input and then check it against the new value?
My current code:
public class validCheck {
public boolean isSolved(int[][][] board)
{
for(int index = 0; index < board.length;index++)
{
for(int r = 0; r < board[0].length; r++)
{
for(int c = 0; c < board[0].length;c++)
{
if(board[index][r][c] == 0)
return false;
}
}
}
return true;
}
public boolean getFrontier(int value)
{
Set<Integer> reserve = new HashSet<>();
for(int n = 1; n < 10; n++)
{
if(value == n && reserve.contains(n))
return false;
else if(value == n) reserve.add(n);
}
return true;
}
public boolean squareCheck(int[][][] board, int index)
{
for(int r = 0; r < board[0].length; r++)
{
for(int c = 0; c < board[0].length; c++)
{
if(!getFrontier(board[index][r][c]))
{
System.out.println("Square error at ["+index + r + c +"]");
return false;
}
}
}
return true;
}
public boolean isValid(int[][][] board)
{
if(isSolved(board))
{
for(int i = 0; i < board.length; i++)
{
for(int r = 0; r < board[0].length;r++)
{
for(int c = 0; c < board[0].length;c++)
{
if(!rowCheck(board,i,r) || !columnCheck(board,i,c) || !squareCheck(board,i))
{
return false;
}
}
}
}
}
return true;
}
public boolean columnCheck(int[][][] board, int index, int col)
{
int target = 0;
if(index <=2)
{
target = index + 6;
}
else if(index > 2 && index < 6)
{
target = index +3;
index = index - 3;
}
else if (index > 5)
{
target = index;
index = index - 6;
}
while(index <= target)
{
for(int r = 0; r < board[0].length;r++)
{
if(!getFrontier(board[index][r][col]))
{
System.out.println("Column error at " + index + r + col);
return false;
}
}
index = index + 3;
}
return true;
}
public boolean rowCheck(int[][][] board, int index, int row)
{
int target = 0;
if(index <= 2)
{
index = 0;
target = 2;
}
else if (index <= 5)
{
index = 3;
target = 5;
}
else if(index <= 8)
{
index = 6;
target = 8;
}
while(index <= target)
{
for(int c = 0; c < board[0].length; c++)
{
if(!getFrontier(board[index][row][c]))
{
System.out.println("Row error at "+index+row+c);
return false;
}
}
index++;
}
return true;
}
}
Usage:
public static void main(String[] args) {
int[][][] solved = {{{5,3,4},{6,7,2},{1,9,8}},
{{6,7,8},{1,9,5},{3,4,2}},
{{9,1,2},{3,4,8},{5,6,7}},
{{8,5,9},{4,2,6},{7,1,3}},
{{7,6,1},{8,5,3},{9,2,4}},
{{4,2,3},{7,9,1},{8,5,6}},
{{9,6,1},{2,8,7},{3,4,5}},
{{5,3,7},{4,1,9},{2,8,6}},
{{2,8,4},{6,3,5},{1,7,9}}};
validCheck checker = new validCheck();
if(checker.isValid(solved))
System.out.println(true);
else System.out.println(false);
}
Any help will be greatly be appreciated!!!
Here is what I would do to find a valid board config in a 2D sudoku board. I would use a HashSet for a row and another for the column, as long as we never encounter repeats and the values contain 1 to the length of the array we know the board is valid.
int [][] board = {{1,2,3},
{2,3,1},
{3,1,2}
};
HashSet<Integer> rowDuplicates = new HashSet<>();
HashSet<Integer> colDuplicates = new HashSet<>();
boolean invalidBoard = false;
for(int i = 0 ; i < board.length; i++)
{
for(int j = 0; j < board[i].length; j++)
{
if(rowDuplicates.contains(board[i][j]) || colDuplicates.contains(board[j][i]))
{
//this board is not valid
invalidBoard = true;
}
else
{
rowDuplicates.add(board[i][j]);
colDuplicates.add(board[j][i]);
}
}
//now check they contain the correct numbers from 1 to the size of the array
if(colDuplicates.size() == rowDuplicates.size())
{
for(int index = 0; index < colDuplicates.size(); index++)
{
if(!(colDuplicates.contains(index + 1) && rowDuplicates.contains(index + 1)))
{
invalidBoard = true;
break;
}
}
}
else
{
invalidBoard = true;
}
colDuplicates.clear();
rowDuplicates.clear();
}
System.out.println("invalid board: " + invalidBoard);
You should be able to expand this to your 3D array but you can see how much easier it is to use HashSets to verify a valid 2D array Sudoku board.
I'm trying to make a program that does Eight Queens with recursion but I keep on getting an array out of bounds error. I've been having problems with this for awhile now and I can't really seem to pinpoint the problem. Here's my code:
public class Queens {
public int currColumn = 0;
public static final int BOARD_SIZE = 8;
public static final int EMPTY = 0;
public static final int QUEEN = 1;
private int board[][];
public Queens() {
board = new int[BOARD_SIZE][BOARD_SIZE];
}
public void clearBoard() {
for (int x = 0; x <= BOARD_SIZE; x++) {
for (int y = 0; y <= BOARD_SIZE; y++) {
board[x][y] = 0;
}
}
}
public void displayBoard() {
for (int x = 0; x < BOARD_SIZE; x++) {
System.out.print("\n");
for (int y = 0; y < BOARD_SIZE; y++) {
System.out.print(board[x][y]);
}
}
}
public boolean placeQueens(int column) {
if (column > BOARD_SIZE) {
return true;
} else {
boolean queenPlaced = false;
int row = 1;
while (!queenPlaced && (row <= BOARD_SIZE)) {
if (isUnderAttack(row, column)) {
++row;
} else {
setQueen(row, column);
queenPlaced = placeQueens(column + 1);
if (!queenPlaced) {
removeQueen(row, column);
++row;
}
}
}
return queenPlaced;
}
}
public void setQueen(int row, int column) //SET BACK TO PRIVATE
{
board[row][column] = 1;
}
private void removeQueen(int row, int column) {
board[row][column] = 0;
}
private boolean isUnderAttack(int row, int column) {
if (column == 0) {
return false;
}
int prevColumn = column - 1;
int prevRow = index(prevColumn);
while (prevColumn >= 0) {
prevRow = index(prevColumn);
for (int i = 0; i > BOARD_SIZE; i++) {
if (prevRow == row && prevColumn + i == column) //Going right
{
return true;
}
if (prevRow + i == row && prevColumn + i == column) //Going up/right
{
return true;
}
if (prevRow - i == row && prevColumn + i == column) //Going down/right
{
return true;
}
}
prevColumn--;
}
return false;
}
public int index(int column) //BACK TO PRIVATE
{
for (int i = 0; i < 8; i++) {
if (board[i][column] == 1) {
return i;
}
}
return 0;
}
public static void main(String[] args) {
Queens x = new Queens();
if (x.placeQueens(1) == true) {
x.displayBoard();
} else {
System.out.println("No solution found");
}
}
}
First Problem:
public void clearBoard()
{
for(int x = 0; x < BOARD_SIZE; x++) // changed from x <= BOARD_SIZE
{
for(int y = 0; y < BOARD_SIZE; y++) // changed from y <= BOARD_SIZE
{
board[x][y] = 0;
}
}
}
Array index counting starts from 0 upto size-1. There is nothing in board[8][8].
Another Problem
/* ... */
while(prevColumn >= 0)
{
prevRow = index(prevColumn);
for(int i = 0; i > BOARD_SIZE; i++) // i=0; i> BOARD_SIZE is always false, so no looping mechanism
{ /* ... */ }
Change it to
for(int i = 0; i < BOARD_SIZE; i++) // corrected
Another Problem ?
if(column > BOARD_SIZE) when `column = 8`
Make it
if(column >= BOARD_SIZE)
Another Problem:
while(!queenPlaced && (row <= BOARD_SIZE))
Make it
row < BOARD_SIZE
Yet Another ?
queenPlaced = placeQueens(column + 1); // What if column = 7
for(int x = 0; x <= BOARD_SIZE; x++)
Change that to:
for(int x = 0; x < BOARD_SIZE; x++)
Since arrays are 0-indexed.
You try to access more elements than the declared array actually has:
// this means you can access index in [0, BOARD_SIZE - 1].
board = new int[BOARD_SIZE][BOARD_SIZE];
// this means you access index in [0, BOARD_SIZE].
for(int x = 0; x <= BOARD_SIZE; x++)
So, a good practice is to always use < when referring to the declared size of the array.
In java array indexes starts from zero.
for(int x = 0; x <= BOARD_SIZE; x++)
should be
for(int x = 0; x < BOARD_SIZE; x++)
{
for(int y = 0; y < BOARD_SIZE; y++)
{
board[x][y] = 0;
}
Your BOARD_SIZE is 8 .so array initialized for 8 elelements. So avaliable indexes are 0 to 7.
in loop
for(int x = 0; x <= BOARD_SIZE; x++)
when x=8 ArrayIndexOutOfBound Exception throws.
Check this point in all your arrays,where you are looping.
I am working on Conway's game of life java code and I am having a struggle with my update method also known as the next generation creator. I will post my code I have written so far and please let me know what I can do to fix the update method.
A cell is born if there was none at time T
1 and exactly three of its neighbors were alive.
An existing cell remains alive if at time T
1 there were either two or three neighbors
A cell dies from isolation if at time T
1 there were fewer than two neighbors.
A cell dies from overcrowding if at time T
1 there were more than three neighbors.
public class GameOfLife {
private char [][] grid;
private int rows;
private int columns;
public GameOfLife(int rows, int columns) {
grid=new char[rows][columns];
for(int i=0;i<grid.length;i++)
{
for(int j=0;j<grid[i].length;j++)
grid[i][j]=' ';
}
}
public int numberOfRows() {
int countRows=0;
for(int i=0;i<grid.length;i++){
countRows++;
rows=countRows;
}
return rows;
}
public int numberOfColumns() {
int countColumns=0;
for(int i=0;i<1;i++){
for(int j=0;j<grid[i].length;j++)
countColumns++;
columns=countColumns;
}
return columns;
}
public void growCellAt(int row, int col) {
for(int i=0;i<grid.length;i++){
for(int j=0;j<grid[i].length;j++)
grid[row][col]='O';
}
}
public boolean cellAt(int row, int col) {
for(int i=0;i<grid.length;i++){
for(int j=0;j<grid[i].length;j++)
if(grid[row][col]=='O')
return true;
}
return false;
}
public String toString() {
String result="";
for(int i=0;i<rows;i++){
for(int j=0;j<columns;j++)
result+=grid[i][j];
}
return result;
}
public int neighborCount(int row, int col) {
int count=0;
int i=row;
int j=col;
int left;
int right;
int up;
int down;
if(i > 0)
up = i-1;
else
up = grid.length-1;
if(i < (grid.length-1))
down = i+1;
else
down = 0;
if(j > 0)
left = j-1;
else
left = grid[i].length - 1;
if(j < (grid[i].length-1))
right = j+1;
else
right = 0;
if(grid[up][left] == 'O')
count++;
if(grid[up][j] == 'O')
count++;
if(grid[up][right] == 'O')
count++;
if(grid[i][left] == 'O')
count++;
if(grid[i][right] == 'O')
count++;
if(grid[down][left] == 'O')
count++;
if(grid[down][j] == 'O')
count++;
if(grid[down][right] == 'O')
count++;
return count;
}
public void update() {
for(int i=0;i<grid.length;i++){
for(int j=0;j<grid[i].length;j++){
if(grid[i][j]==' ' && neighborCount(i,j)==3)
grid[i][j]='O';
if(neighborCount(i,j)<2 || neighborCount(i,j)>3)
grid[i][j]= ' ';
if(grid[i][j]=='O' && neighborCount(i,j)==2 || neighborCount(i,j)==3)
grid[i][j]='O';
}
}
}
}
Ok regarding making a new array in the update method, is this all that needs to be done? Also, how would I go about making assertion tests for the update method?
public void update() {
char[][] newGrid = new char[grid.length][grid[0].length];
for(int i=0;i<grid.length;i++){
for(int j=0;j<grid[i].length;j++){
if(grid[i][j]==' ' && neighborCount(i,j)==3)
newGrid[i][j]='O';
if(neighborCount(i,j)<2 || neighborCount(i,j)>3)
newGrid[i][j]= ' ';
if(grid[i][j]=='O' && neighborCount(i,j)==2 || neighborCount(i,j)==3)
newGrid[i][j]='O';
}
}
}
It looks like you are trying to modify the same grid you are looping through. As you loop through your grid, changes should be made based on the previous state of the grid. Try constructing a new grid instead of writing over the old one.
That's how I would go about it.
Note that this is C++11 implementation
template<std::size_t X, std::size_t Y>
class GameOfLife {
private:
std::pair<int, int> neighbors[8];
public:
typedef std::array<std::array<uint16_t,Y>,X> Grid;
private:
uint16_t getCellStatus(Grid const& conway, int x, int y) {
uint16_t liveCount = 0;
for(auto&& neighbor: neighbors) {
int nX = x + neighbor.first;
int nY = y + neighbor.second;
if(nX>=0 && nX<X && nY>=0 && nY<Y){
if(conway[nX][nY]>0) liveCount++;
}
}
if(conway[x][y]>0){
if(liveCount==2 ||liveCount == 3) return 1;
}
else {
if(liveCount==3) return 1;
}
return 0;
}
public:
GameOfLife() {
size_t index = 0;
for(int i=-1; i<=1; ++i) {
for(int j=-1; j<=1; ++j){
if((i|j)==0) continue;
neighbors[index].first = i;
neighbors[index++].second = j;
}
}
}
Grid getNextConway(Grid const& conway) {
Grid output;
for(size_t i=0; i<X; ++i)
for(size_t j=0; j<Y; ++j) output[i][j]=getCellStatus(conway,i,j);
return output;
}
Grid printGrid(Grid const& conway) {
for (int i = 0; i < X; ++i){
for (int j = 0; j < Y; ++j) {
if(conway[i][j]==0) std::cout<<"0";
else std::cout<<"1";
}
std::cout<<std::endl;
}
std::cout<<std::endl;
}
};
int main() {
size_t const DIM = 8;
size_t const NUM_GENS = 10;
typedef GameOfLife<DIM,DIM> Game;
typename Game::Grid gameGrid;
for (int i = 0; i < DIM; ++i) {
for (int j = 0; j < DIM; ++j) {
gameGrid[i][j] = rand()%2;
}
}
Game conway;
conway.printGrid(gameGrid);
for (int i = 0; i < NUM_GENS; ++i) {
gameGrid = conway.getNextConway(gameGrid);
conway.printGrid(gameGrid);
}
return 0;
}