I am working on a Connect Four project, but am struggling with the win check. I think it has something to do with how I am looping over the grid. It works horizontally but not vertically, and it kinda works diagonally.
public boolean gameStatus(MyBoard gameBoard, int columnPosition, CellState gameToken) {
int rowPosition = 0;
for (int i = 0; i < gameBoard.getWidth(); i++)
for (int j = 0; j < gameBoard.getHeight(); j++)
if (gameBoard.get(i, columnPosition) != CellState.FREE)
rowPosition = i;
if (checkColumn(gameBoard, columnPosition, gameToken, rowPosition))
return true;
}
public boolean checkColumn(MyBoard gameBoard, int columnPosition, CellState gameToken, int rowPosition) {
int tokenCounter = 1;
if ((rowPosition + 4) <= 6)
for (int i = rowPosition + 1; i <= rowPosition + 3; i++)
if (gameToken == gameBoard.get(i, columnPosition))
tokenCounter++;
else
break;
if (tokenCounter == 4)
return true;
return false;
}
I think this only checks the last row which is non-empty.
Java doesn't care about indentation, so without braces, if and for only use the statement after them. This means your if (checkColumn... only runs once, not once for each column.
You might want to try something like
public boolean gameStatus(MyBoard gameBoard, int columnPosition, CellState gameToken) {
int rowPosition = 0;
for (int i = 0; i < gameBoard.getWidth(); i++) {
for (int j = 0; j < gameBoard.getHeight(); j++) {
if (gameBoard.get(i, columnPosition) != CellState.FREE) {
rowPosition = i;
}
}
if (checkColumn(gameBoard, columnPosition, gameToken, rowPosition)) {
return true;
}
}
In general. I'd advise against writing if, for and while statements without braces. The two characters it saves is not worth the bugs you may accidentally introduce
Related
I have to write a method that returns the count of 'a' chars in the matrix but I have to do it with using recursion and it must be O(n.log(n)).
This is the my non-recursive code:
public static int acount(char[][] mat) {
int result = 0;
int i = 0;
int j = 0;
while (i <= 4) {
if (mat[i][j] == 'a') {
result++;
j++;
}
if (mat[i][j] == 'b') {
i++;
j = 0;
}
}
return result;
}
This is what i have tried but there was an error: "Exception in thread "main" java.lang.StackOverflowError":
public static int acount(char[][] mat) {
int result = 0;
int i = 0;
int j = 0;
while (mat[i][j] == 'a') {
result++;
j++;
}
if (i < 5) {
i++;
j = 0;
} else {
return result;
}
return acount(mat);
}
This is the main code:
public static void main(String[] args) {
int n = 5;
Random rand = new Random();
char[][] input = new char[n][n];
for (int i = 0; i < n; i++) {
int a_num = rand.nextInt(n);
for (int j = 0; j < a_num; j++) {
input[i][j] = 'a';
}
for (int j = a_num; j < n; j++) {
input[i][j] = 'b';
}
}
System.out.println(Arrays.deepToString(input));
System.out.println(acount(input));
}
}
How can it resolved?
Okay, let's start with your original version.
public static int acount(char[][] mat) {
int result = 0;
int i = 0;
int j = 0;
while (i <= 4) {
if (mat[i][j] == 'a') {
result++;
j++;
}
if (mat[i][j] == 'b') {
i++;
j = 0;
}
}
return result;
}
This code looks problematic. First, it assumes that your input only contains a or b. If you include other data, you'll never increment either i or j and you loop forever. It also looks like you're assuming that each row in the matrix is a-a-b-who-cares. That is, all a's, but you stop looking at the first b. Is that what you really want? Maybe it is.
I would have written this as:
for (int index1 = 0; index1 < 5; ++index1) {
for (int index2 = 0; index2 < 5; ++index2) {
if (mat[index1][index2] == 'a') {
++result;
}
}
}
And actually, i wouldn't hard-code 5 but would instead use mat.length and mat[index1].length respectively.
As for your stack overflow -- this is because your recursion never ends. You do this:
return acount(mat);
That is, you call acount with the same array again, which calls acount again, which calls acount again...
The only way that doesn't fail is if your code above returns early, which it probably won't. I think what you're missing is that each time you enter acount, you get fresh variables, so i and j start out freshly as zeros again.
You could partially solve this by passing i into acount, and when you recurse:
return acount(mat, i+1);
That will fix some of the problem, although I think you're complexity is still O(n^2).
Then let's look at this:
while (mat[i][j] == 'a') {
result++;
j++;
}
What happens if the row never has any a's in it? It looks past the end of the array. You're making assumptions about the input data, which is going to bite you.
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.
I recently completed the code for a Four in a Row Game with 7 columns (represented by i below) and 6 rows (represented by j below), however, I keep getting out of bounds errors and I'm not sure why. If anyone can help spot and fix the errors, that would be awesome. Below is the code I have (the issues lie in the play, isGameOver and winner functions):
package hw4;
public class CFGame {
//state[i][j]= 0 means the i,j slot is empty
//state[i][j]= 1 means the i,j slot has red
//state[i][j]=-1 means the i,j slot has black
private final int[][] state;
private boolean isRedTurn;
{
state = new int[7][6];
for (int i=0; i<7; i++)
for (int j=0; j<6; j++)
state[i][j] = 0;
isRedTurn = true; //red goes first
}
public int[][] getState() {
int[][] ret_arr = new int[7][6];
for (int i=0; i<7; i++)
for (int j=0; j<6; j++)
ret_arr[i][j] = state[i][j];
return ret_arr;
}
public boolean isRedTurn() {
return isRedTurn;
}
public boolean play(int column) {
for(int j = 0; j < state[column].length; j++) {
if(state[column][j] != 0 || state[column][j] < 0 || state[column][j] > 6 ) {
return false;
}
}
return true;
}
public boolean isGameOver() {
for(int j = 0; j < state.length; j++) {
for(int i = 0; i < state[j].length; i++) {
if (state[i][j] != 0) {
return true;
}
}
}
return false;
}
public int winner() {
//Checking horizontal win
for(int j = 0; j < state.length; j++) {
for(int i = 0; i < state[j].length-3; i++) {
if(state[i][j] == state[i+1][j] && state[i][j] == state[i+2][j] &&
state[i][j] == state[i+3][j]) {
return state[i][j];
}
}
}
//Checking vertical win
for(int j = 0; j < state.length-3; j++) {
for(int i = 0; i < state[0].length; i++) {
if(state[i][j] == state[i][j+1] && state[i][j] == state[i][j+2] &&
state[i][j] == state[i][j+3]) {
return state[i][j];
}
}
}
//Checking diagonal(s) win
for(int j = 0; j < state.length - 3; j++) {
for(int i = 0; i < state[j].length - 3; i++) {
if(state[i][j] == state[i+1][j+1] && state[i][j] == state[i+2][j+2] &&
state[i][j] == state[i+3][j+3]) {
return state[i][j];
}
}
}
for(int j = 0; j < state.length - 3; j++) {
for(int i = 3; i <= state[j].length; i++) {
if(state[j][i] == state[j+1][i-1] && state[j][i] == state[j+2][i-2] &&
state[j][i] == state[j-3][i+3]) {
return state[i][j];
}
}
}
return 0;
}
}
To me, the code seems fine but when I run it, it brings up the error.
If you spot any other mistakes, kindly let me know too.
Any help is much appreciated.
You use index j and i differently in different loops. It looks like j should be the index for the first dimension and i is for the second, but you have state[i][j] in some places. That will definitely cause outofbound error because j can go as high as 6 but i is capped at 5 based on your code.
This is an N Queens problem where the board has been given and you must use methods to check where the rows, the columns and diagonally. My method for checking the row is here:It works if you were counting the Queens as a whole but I only want to check row by row, resetting the count and rowcount.
private boolean oneQueenPerRow() //ensures that there is only 1 queen in each row
{
int count = 0;
int rowcount = 0;
for (int i = 0; i < board.length; i++)
{
//count = 0;
for (int j = 0; j < board.length; j++)
{
//rowcount = 0;
while (rowcount <= size-1)
{
if (board[i][j] == QUEEN)
{
count++;
rowcount++;
}
if (board[i][j] == BLANK)
{
rowcount++;
}
}
if (count != 1) // if size replaces 1 then it works, but counts Q's as a whole
{
return false;
}
}
}
return true;
}
The idea is that all the methods return true or false and then are called by final boolean method. If all are true than the board is a valid solution. If one is false, the board is not a valid solution. Here is a text file example I was given:
4
BQBB
BBBQ
QBBB
BBQB
(They should be stacked..)
I don't have enough knowledge about arrays and for loops to tell if this is going all the way through the whole file or just a row at a time, although trust me when I say I have exhausted all resources.
I have been working on this for days and I can't figure it out and connection with my Prof is spotty because of this virus! I desperately need help!
private boolean noDiagonalAttacks() //makes sure that Queens cannot attack diagonally
{
for (int i = 0; i < board.length; i++)
{
int count = 0;
for (int j = 0; j < board.length; j++)
{
if (board[i][j] == QUEEN)
{
if(this.toRight() == false || this.toLeft() == false)
{
return false;
}
count++;
}
}
}
return true;
}
private boolean toRight()
{
for (int i = 0; i < board.length; i++)
{
for (int j = 0; j < board.length; j++)
{
while (board[i][j] != board[i][size-1] || board[i][j] != board[size-1][j]) //add a count to this?
{
if (board[i][j] == QUEEN)
{
return false;
}
}
}
}
return true;
}
private boolean toLeft()
{
for (int i = 0; i < board.length; i++)
{
for (int j = 0; j < board.length; j++)
{
while (board[i][j] != board[i][0] || board[i][j] != board[size-1][j])
{
if (board[i][j] == QUEEN)
{
return false;
}
}
}
}
return true;
}
I tried it once ago and it worked, Hope it help you.
private boolean oneQueenPerRow() {
int foundQueens;
for (int i = 0; i < board.length; i++) {
foundQueens = 0;//each loop is a checked row
for (int j = 0; j < board.length; j++) {
if (board[i][j] == QUEEN)
foundQueens++;
}
if (foundQueens > 1) return false;
}
return true;
}
private boolean oneQueenPerDiagonal() {
int inLeftRight = 0;
int inRightLeft = 0;
for (int i = 0; i < board.length; i++) {
if (board[i][i] == QUEEN)
inLeftRight++;
if (board[i][board.length-i-1] == QUEEN)
inRightLeft++;
}
return inLeftRight < 1 && inRightLeft < 1;
}
I'm new to this forum so I hope I'm posting this question in the right way - otherwise, please let me know.
I'm trying to write the code for a simple Game of Life animation in Java, and most of it seems to work as intended.
However, there is a problem with one of the neighbour 'rules' that is supposed to "kill" a cell if it has less than 2 neighbours, meaning that cells can have one or no neighbours and still survive - can be seen here: http://peecee.dk/upload/view/435109. All other rules seem to work fine.
Can anyone help me figure out why it ignores the rule (Live cells are equal to '1', dead to '0'.):
if (this.state[i][j] == 1 &&
liveNeighbours(i, j) > 3 || liveNeighbours(i, j) < 2) {
this.tempState[i][j] = 0;
Thanks a ton in advance!
The code is as follows:
import java.util.*;
public class GameOfLife {
private int[][] state;
private int[][] tempState;
//Constructor that creates n x n grid of randomly placed live cells
public GameOfLife(int n) {
this.state = new int[n+2][n+2];
this.tempState = new int[n+2][n+2];
createRandomBoard(n);
}
//Sets up the initial state
public void createRandomBoard(int n) {
//Creates (n+2) x (n+2) grid of dead cells
for (int i = 0; i < n+2; i++) {
for (int j = 0; j < n+2; j++) {
this.state[i][j] = 0;
}
}
//Creates n x n grid of randomly placed live cells. Live cells are equal to '1', dead to '0'.
for (int i = 1; i < n + 1; i++) {
for (int j = 1; j < n + 1; j++) {
int a = (int)Math.round(Math.random());
this.state[i][j] = a;
}
}
drawBoard();
}
//Draws the live cells as dots based on current state
public void drawBoard() {
StdDraw.show(50);
StdDraw.clear();
for (int i = 1; i < this.state.length-2; i++) {
for (int j = 1; j < this.state.length-2; j++) {
StdDraw.setXscale(1,this.state.length-3);
StdDraw.setYscale(1,this.state.length-3);
StdDraw.setPenRadius((double)1/this.state.length);
if (this.state[i][j] == 1) {
StdDraw.point(i, j);
}
}
}
StdDraw.show(50);
}
//Determines which cells live or die in the next state
public void nextState() {
//Copies the state array to a temporary state(array) during killing/reviving
for (int i = 1; i < this.state.length-2; i++) {
for (int j = 1; j < this.state.length-2; j++) {
this.tempState[i][j] = this.state[i][j];
}
}
//Kills cells with more than 3 or less than 2 neighbours and revives dead cells with 3 neighbours
for (int i = 1; i < this.state.length-2; i++) {
for (int j = 1; j < this.state.length-2; j++) {
if (this.state[i][j] == 1 && liveNeighbours(i, j) > 3 || liveNeighbours(i, j) < 2) {
this.tempState[i][j] = 0;
}
else if (this.state[i][j] == 0 && liveNeighbours(i, j) == 3) {
this.tempState[i][j] = 1;
}
}
}
//Copies the modified temporary state array to the original state(array) again
for (int i = 1; i < this.state.length-2; i++) {
for (int j = 1; j < this.state.length-2; j++) {
this.state[i][j] = this.tempState[i][j];
}
}
drawBoard();
}
//Counts the number of live neighbours to a cell
private int liveNeighbours(int x, int y) {
int numLiveNeighbours = 0;
for (int i = x-1; i < x+2; i++) {
for (int j = y-1; j < y+2; j++) {
if (this.state[i][j] == 1) {
numLiveNeighbours++;
}
}
}
numLiveNeighbours --;
return numLiveNeighbours;
}
public String toString() {
return Arrays.deepToString(this.state);
}
public int[][] getState() {
return this.state;
}
}
Your condition doesn't seem to express what you want. You need to change it to:
if (this.state[i][j] == 1 && (liveNeighbours(i, j) > 3 || liveNeighbours(i, j) < 2))
Check operators precedence rules in Java. You were killing those cells being alive and having more than 3 neighbours or those cells with less than two of them.
With this change you will be killing those cells alive and with more than 3 or less than 2 neighbours.
I think your liveNeighbours has a little flaw too: Your are counting (x,y) neighbours and (x,y) itself. You should change it for:
private int liveNeighbours(int x, int y) {
int numLiveNeighbours = 0;
for (int i = x-1; i < x+2; i++) {
for (int j = y-1; j < y+2; j++) {
if (this.state[i][j] == 1 && (x != i || j != y)) {
numLiveNeighbours++;
}
}
}
return numLiveNeighbours;
}