currently working on a tic tac toe game in java, and I have a checkWin() method that works correctly for 3 out of the 4 possible winning conditions. The one I am having an issue with is the right diagonal.
Code:
public boolean checkWin(String player){
int row = 0; // Holder to count number of player spots in row
int d1 = 0; // Holder to count number of player spots in right diag.
int d2 = 0; // Holder to count number of player spots in left diag.
int[] column = new int[squares[0].length]; /* Holder to count number
of player spots in column */
for(int i = 0; i < size; i++){
row = 0;
for(int j = 0; j < size; j++){
if(null == squares[i][j]){
continue;
}
if(squares[i][j].getText().equals(player)){
row++; /* If spot at [i][j] equals player, increase row */
column[j]++; /* If spot at [i][j] equals player, increase
col */
if(i == j){ /* If spot at i is equal to j, increase left
diag */
d1++;
} else if ((size - 1) == i + j){ /* If spot at i + j
equals board size - 1, increase right diag. */
d2++;
}
}
}
if(row == size){
/*
if spots in row is equal to size (otherwise, if it fills
the row, return win
*/
return true;
}
}
if(size == d1 || size == d2){
/*
if spots in either diag is equal to size, return win
*/
return true;
}
for(int i = 0; i < column.length; i++){
if(column[i] == size){
/*
if column is full of the same player character, return win
*/
return true;
}
}
/*
otherwise, return false
*/
return false;
}
The problem part is:
else if ((size - 1) == i + j){ /* If spot at i + j
equals board size - 1, increase right diag. */
d2++;
}
Reason for setting it up this way, is how a 2D Array works, so for a 3x3 board:
[00][01][02]
[10][11][12]
[20][21][22]
And with i + j = size - 1, it would evaluate 2 + 0, 1 + 1, 0 + 2 all equal 2, which is size - 1 if size = 3, but when I run the program and perform the right diagonal move, it doesn't return a true value for win.
Any suggestions for how to fix this will be greatly appreciated.
else if ((size - 1) == i + j)
^ This is only evaluated if the if condition above it is false.
if(i == j)
When i == 1 and j == 1, then i == j is true, and thus (size - 1) == i + j is not evaluated.
TLDR: Get rid of your else.
So I am currently coding Connect 4 on Netbeans. I have the vertical and horizontal check already made but I am having trouble with the diagonal check, specifially the for loops. Currently my code for this,
public static boolean checkDiagnol(String[][] board, int counter, String playerMoving, int lastPlacedTileRow, int col) {
for (int i = lastPlacedTileRow-1; q = col-1; i >= 0, q >=0; i--,q--){
if (board[i][q] == playerMoving) {
counter += 1;
} else {
break;
}
if (counter > 4) {
return true;
}
}
for (int i = lastPlacedTileRow + 1, q = col +1; i < board.length, q < board[0].length; i++,q++) {
if (board[i][q] == playerMoving) {
counter += 1;
} else {
break;
}
if (counter > 4) {
return true;
}
}
return false;
}
lastPlacedTileRow is the row of the last placed tile, col is the column chosen by the user, counter is a counter used to check if there are 4 tiles in a row, and playerMoving is the current players tile.
The current problem I have is that my for loops give errors. This is my first time using two variables in a single for loop so I am not sure how it is supose to be arranged.
Thanks for the help
Syntax
You have put a semicolon instead of a comma in the first for loop.
for (int i = lastPlacedTileRow-1; q = col-1; i >= 0, q >=0; i--,q--){
this should be
for (int i = lastPlacedTileRow-1, q = col-1; i >= 0, q >=0; i--,q--){
Logic
I think variable i should be counted down (or up) in both the loops because we have to check below the lastPlacedTileRow in both cases.
I have an assignment to have a knight move around the chessboard until it either completes a full tour or has no where else to go.
im having a problem figuring out how to have it actually stop after there are no more moves. I have the algorithm for the movement down, as well as bounds checking on the chessboard.
setting the loop count to 64 just times out, because the program will try to continually find a spot that doesn't exist if a perfect tour isn't created.
two ideas I have had to fix this is to either increment a variable every time a certain position is checked around a certain spot, and if all possible moves are taken by a previous move, terminate the program. Problem is I have no idea how to actually do this.
A second idea I had is to have the program quit the for loop after 2 seconds(during which the for loop will check each position way more than once) but I feel like my professor would crucify me upside down if I did that
here is my code:
import apcslib.*; //this is only for Format()
public class ktour
{
int[][] kboard = new int[9][9];
int[] vert = new int[9];
int[] horiz = new int[9];
ktour()
{
vert[1] = -2;vert[2] = -1;vert[3] = 1;vert[4] = 2;vert[5] = 2;vert[6] = 1;vert[7] = -1;vert[8] = -2;
horiz[1] = 1;horiz[2] = 2;horiz[3] = 2;horiz[4] = 1;horiz[5] = -1;horiz[6] = -2;horiz[7] = -2;horiz[8] = -1;
path();
}
public void path()
{
int row = 1;
int col = 1;
int loops = 10; //i have this set to 10 for now
int col2 = 1;
int row2 = 1;
int r = (int)(Math.random() * (8) +1); //returns a random from 1 to 9
//System.out.println(r);
kboard[col][row] = 1;
for(int x = 2; x < loops; x++) //this runs the bounds check and places each number for the amount that loops is
{
r = (int)(Math.random() * (8) +1);
col = col2;
row = row2;
col = col + vert[r];
row = row + horiz[r];
while(col <= 0 || col > 8 || row <= 0 || row > 8) //bounds check, will keep running until both row and columb is in the board
{
r = (int)(Math.random() * (8) + 1);
col = col2;
row = row2;
col = col + vert[r];
row = row + horiz[r];
}
if(kboard[col][row] == 0)
{
kboard[col][row] = x;
row2 = row;
col2 = col;
}
else
{
x--; //if the above if is false and a number already occupies the generated spot, x is decremented and the program tries again
}
}
printboard();
}
public void printboard()
{
for(int y = 1; y < 9; y++)
{
System.out.println();
for(int x = 1; x < 9; x++)
{
System.out.print(Format.right(kboard[y][x],3));
}
}
}
}
I was able to fix my lab with the following code. I created a variable called count which I used to check if at any move there were no more moves left. As there are only 8 moves, when the variable reached 9 the code terminated, and printed up to the point it got to.
I had to put multiple if statements excluding r = math.random if count was not 0, meaning I was checking r 1-9, aka every possible move. Therefore, I couldn't use a randomizer, I had to traverse all 8 possible moves.
I also ran into problems when I reached the line where it checks if kboard[col][row] == 0. if you were running through a loop with count greater than 1, it was possible that col or row could be out of bounds, due to lack of a randomizer in the bounds checker. If left without a break, the bounds checker would run forever without a random number generated every time. I fixed this by adding an if statement that allowed the program to proceed if col and row were inside the board. if they were not, x was decremented and count was increased again, signifying a failed attempt.
This way I was able to check all possible moves, disregarding whether or not they were inside the board.
public void path()
{
int row = 1;
int col = 1;
int loops = 64; //i have this set to 10 for now
int col2 = 1;
int row2 = 1;
int count = 0;
boolean end = false;
int r = (int)(Math.random() * (8) +1); //returns a random from 1 to 9
//System.out.println(r);
kboard[col][row] = 1;
for(int x = 2; x < loops; x++) //this runs the bounds check and places each number for the amount that loops is
{
if(count == 0)
r = (int)(Math.random() * (8) +1);
if(count >= 1 && r != 8)
r++;
col = col2;
row = row2;
col = col + vert[r];
row = row + horiz[r];
while(col <= 0 || col > 8 || row <= 0 || row > 8) //bounds check, will keep running until both row and columb is in the board
{
if(count == 0)
r = (int)(Math.random() * (8) + 1);
col = col2;
row = row2;
col = col + vert[r];
row = row + horiz[r];
if(count >= 1)
break;
}
end = false;
if(r == 8 || r == 9)
r = 1;
if(count >= 9)
{
System.out.println("Halting... no where else to go");
loops = 0;
}
if(!(col <= 0 || row <= 0 || row > 8 || col > 8))
{
if(kboard[col][row] == 0)
{
kboard[col][row] = x;
row2 = row;
col2 = col;
count = 0;
}
else
{
count++;
x--; //if the above if is false and a number already occupies the generated spot, x is decremented and the program tries again
}
}
else
{
count++;
x--;
}
}
printboard();
}
I'm working on a Connect Four game for the console in Java. I have problems with the winning conditions, as I don't know how to program them. Here is my code my Main:
public class Main {
public static char[] playerNumber = new char[]{'1', '2'};
public static char[] Badge = new char[]{'X', 'O'};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int moves = 7 * 6;
int whichPlayer = 0;
for (int i = 0; i < 10; i++) {
System.out.println(" FOUR IN A ROW");
System.out.println("-------------------------------------------------------");
System.out.println("Welcome to the amazing game Four In A Row:");
System.out.println("Enter a number between 0 and 6 for choosing a column.");
System.out.println();
Board board = new Board();
board.fillBoard();
board.presentBoard();
do {
// 1. get a badge
char Player = playerNumber[whichPlayer];
char badge = Badge[whichPlayer];
// 2. make a turn
board.makeTurn(badge, Player);
board.presentBoard();
// 3. Tjek om der er vinder
if (board.checkWinHorizontal() || board.checkWinVertical()) {
System.out.println("Player " + Player + " has won!");
break;
}
// 4. change the player
whichPlayer = 1 - whichPlayer;
// 5. decrease moves
--moves;
if (moves == 0) {
System.out.println("Game over, nobody has won.");
System.out.println("Do you want to play again? 'Y' or 'N':");
String newGame = scanner.nextLine();
if (newGame.equals("Y") || newGame.equals("y")) {
break;
}
if (newGame.equals("N") || newGame.equals("n")) {
System.out.println("Thanks for the game!");
return;
}
}
// 6. repeat
} while (true);
}
}
And here is my code for my Board class:
public class Board {
char[][] board = new char[6][7];
int column;
// Fills the empty spaces
public void fillBoard() {
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 7; j++) {
board[i][j] = ' ';
}
}
}
// Prints the board
public void presentBoard() {
for (int i = 0; i < 6; i++) {
System.out.print(" | ");
for (int j = 0; j < 7; j++) {
System.out.print(board[i][j] + " | ");
}
System.out.println();
System.out.print(" -----------------------------");
System.out.println();
}
}
// Turn
public void makeTurn(char badge, char Player) {
Scanner scanner = new Scanner(System.in);
do {
// 1. Ask for a column
System.out.println("Player " + Player + " turn: ");
column = scanner.nextInt();
// 2. Check if it's between 0 and 6
if (column > 6) {
System.out.println("That is not a valid number. Please enter a number between 0 and 6: ");
continue;
}
// 3. Place a badge
for (int i = 6 - 1; i >= 0; i--) {
if (board[i][column] == ' ') {
board[i][column] = badge;
return;
}
}
// If column is full
System.out.println("Column " + column + " is full. Try another column:");
} while (true);
}
// Check for vertical win
public boolean checkWinVertical() {
return verticalWin(5, column);
}
// Check for horizontal win
public boolean checkWinHorizontal() {
return horizontalWin(5,column);
}
// Conditions for vertical win
private boolean verticalWin(int x, int y) {
char charToCheck = board[x][y];
if (board[x-1][y] == charToCheck &&
board[x-2][y] == charToCheck &&
board[x-3][y] == charToCheck) {
return true;
}
return false;
}
// Conditions for horizontal win
private boolean horizontalWin(int x, int y) {
char charToCheck = board[x][y];
if (board[x][y+1] == charToCheck &&
board[x][y+2] == charToCheck &&
board[x][y+3] == charToCheck) {
return true;
}
return false;
}
I have succeeded in getting the game recognize a win horizontally and vertically at the bottom row of my array, but I don't know how to make the game recognize for the whole array. I'm only concentrating about the horizontal and vertical, as the diagonal is too complicated for me. And I don't know if this is the right approach or there is a better one.
Thanks!
Here's another solution. It's the same general idea as previously mentioned: loop through each row/column, checking for a streak of 4 in a row. Maybe this implementation will provide some other insight. Below, I've shown an example method checking the horizontal streaks. For vertical, you would iterate over the rows in the inner for loop instead.
public boolean checkWin(char badge) {
return checkHorizontalStreaks(board, badge)
|| checkVerticalStreaks(board, badge);
}
private boolean checkHorizontalStreaks(char[][] board, char badge) {
for (int row = 0; row < board.length; row++) {
// loop throught each row
int currentStreak = 0;
for (int col = 0; col < board[row].length; col++) {
// loop through each column in the row
if (board[row][col] == badge) {
// keep the streak of 'badge' going
currentStreak++;
if (currentStreak == 4) {
// winner
return true;
}
} else {
// restart the streak
currentStreak = 0;
}
}
}
return false;
}
And then update your Main class with
if (board.checkWin(badge)) {
System.out.println("Player " + Player + " has won!");
break;
}
I'd wager there is a more efficient way to determine a winner (perhaps by treating the grid as a graph and traversing it with some special logic). However, I suspect this may be enough for what you need. I'll spare you the output, but it worked with a few different test cases.
Possibly you could check all the adjacent fields around the last played field, so after the user did his turn. So for checking upwards you could do this:
public boolean checkUp(int rowPlayed, int columnPlayed){
boolean checked = false;
if(rowplayed + 1 <= maxrows){ //Checks if you didn't hit the top
if(board[rowPlayed+1][columnPlayed] != null){
if(board[rowPlayed+1][columnPlayed].getPlayer() == currentPlayer){
checked = true;
}
}
}
return checked;
}
and for example implemented like this:
public void checkWin(int rowPlayed, int columnPlayed){
boolean checkingWin = true;
int countWin = 0;
while(checkingWin){
if(checkUp(rowPlayed + countWin, columnPlayed)){
countWin++;
}
else{
checkingWin = false;
}
if(countWin == 4){
checkinWin = false;
//Insert win confirmation here
}
}
}
It's partially pseudo code because I don't know exactly how you handle things in your code, nor do I know if this is the best way to do it. But I hope it was of help for you.
This is a long answer and I'll go around the houses a bit so you can see how I reached my solution (which also expands to diagonal checking at the end).
I would use the last piece added as a starting point and work from there since checking all combinations is exhaustive and unnecessary.
Given the row and column of the last piece added I need to decide what I need to achieve.
I already know that the current row and column has the piece of the colour I'm looking for so I can ignore that.
For horizontal matching, I want to check I want to checking pieces to left and right in the same row have the same colour, and stop if the colour is different or there is no piece.
So imagine the following board (# = empty, R = Red piece, Y = Yellow piece:
6 # # # # # # # #
5 # # # # # # # #
4 # # # # # # # #
3 # # # # # # # #
2 # # # # # # # #
1 # # # # # # # #
0 Y R R R Y Y Y R
0 1 2 3 4 5 6 7
The last move was Yellow, row 0, col 4.
So I want to check left and right from [0][4] and see if the total number of consecutive pieces of the colour is 3, (not 4) since I know [0][4] is Yellow and can be discounted.
Based on this I can take a recursive approach where I check the adjacent to one side, then recursively do the same thing as long as I keep matching pieces of the same colour or do not encounter an empty slot.
I'll start of with a check to the right (to demonstrate):
private static final int COLS = 7;
private static final int ROWS = 6;
public enum Piece {RED, YELLOW}; // null is empty
private Piece[][] board = new Piece[ROWS][COLS]; // the board
private int checkRight(Piece piece, int row, int col) {
// assume valid row for now
col++; // moving col to the right
if (col >= COLS || board[row][col] != piece) {
// We're outside the limits of the column or the Piece doesn't match
return 0; // So return 0, nothing to add
} else {
// otherwise return 1 + the result of checkRight for the next col
return 1 + checkRight(piece, row, col);
}
}
Now I can perform the same to the left.
private int checkLeft(Piece piece, int row, int col) {
// assume valid row for now
col--; // moving col to the left
if (col < 0 || board[row][col] != piece) {
// We're outside the limits of the column or the Piece doesn't match
return 0; // So return 0, nothing to add
} else {
// otherwise return 1 + the result of checkLeft for the next col
return 1 + checkLeft(piece, row, col);
}
}
And to check a winner for horizontal, I could do this:
public boolean checkWinner(Piece piece, int row, int col) {
// if the sum is 3, we have a winner (horizontal only).
return checkRight(piece, row, col) + checkLeft(piece, row, col) == 3;
}
Ugh, there's a lot of repetition isn't there?
We can condense the two methods into one by introducing a new parameter direction which can change if we move col positive or negative through the values 1 and -1 respectively:
private int check(Piece piece, int row, int col, int direction) {
col += direction; // direction is either 1 (right) or -1 (left)
if (col < 0 || col >= COLS || board[row][col] != piece) {
return 0;
} else {
return 1 + check(piece, row, col);
}
}
Update checkWinner() for this new parameter:
private static final int POSITIVE = 1; // right at the moment
private static final int NEGATIVE = -1; // left at the moment
public boolean checkWinner(Piece piece, int row, int col) {
// if the sum is 3, we have a winner (horizontal only).
return check(piece, row, col, POSITIVE) + check(piece, row, col, NEGATIVE) == 3;
}
Now I could implement the same sort of logic for vertical, but instead stay on the same col and change the row. I will skip this part in detail and move onto a solution which includes this and diagonal checking.
This has been done using an enum called CheckType storing values for which row and col should change and is used by the check() method. e.g. for HORIZONTAL the column changes by 1 or -1 (depending upon the direction specified when check() is called) and the row remains 0.
public class Board {
public enum Piece {
RED, YELLOW
};
private enum CheckType {
HORIZONTAL(0, 1), VERTICAL(1, 0), DIAGNONAL_UP(1, 1), DIAGNONAL_DOWN(-1, 1);
int row;
int col;
CheckType(int row, int col) {
this.row = row;
this.col = col;
}
}
private static final int POSITIVE = 1;
private static final int NEGATIVE = -1;
private static final int ROWS = 6;
private static final int COLS = 7;
private Piece[][] board = new Piece[ROWS][COLS];
private boolean hasWinner = false;
public boolean hasWinner() {
return hasWinner;
}
private void checkWinner(Piece piece, int row, int col) {
// check all values of enum CheckType for a winner
// so HORIZONTAL, VERTICAL, etc..
int enumIndex = 0;
while (!hasWinner && enumIndex < CheckType.values().length) {
hasWinner = check(piece, row, col, POSITIVE, CheckType.values()[enumIndex])
+ check(piece, row, col, NEGATIVE, CheckType.values()[enumIndex]) == 3;
enumIndex++;
}
}
private int check(Piece piece, int row, int col, int direction, CheckType type) {
row += type.row * direction;
col += type.col * direction;
if (row >= ROWS || row < 0 || col >= COLS || col < 0 || board[row][col] != piece) {
return 0;
} else {
return 1 + check(piece, row, col, direction, type);
}
}
// for completeness, adding a Piece
public boolean add(Piece piece, int col) {
int row = 0;
while (row < ROWS && board[row][col] != null) {
row++;
}
if (row < ROWS) {
board[row][col] = piece;
// check for winner after successful add
checkWinner(piece, row, col);
}
return row < ROWS;
}
}
Hope this helps.
I have to modify the below method:
private final static int NUM = 6;
public void fun(int[][] grid) {
for(int row = 0; row < NUM; row++) {
for(int col = 0; col < NUM; col++) {
if((grid[row][col] % 2) == 0) {
grid[row][col] = 0;
}
}
}
}
This method checks if it's a even number and if so it replaces its value with 0. Simple.
I now need to modify it so that it directs each cell to simultaneously replace its value with its number of diagonal neighbors that hold a value of 0.
I've thought about this for about an hour and tried many different solutions, most of which resulted in an out of bounds exception. I'm stumped and don't know how to accomplish this.
If the code is right, using the integers for the grid array below, it will reproduce the numbers shown in the bottom of the picture.
What is the problem, you just need to put if statements, like there can be maximum 4 possible neighbors so check that how many are equal to 0. But this is not enough you just need to add one more condition in each of the if statements. The condition would be that the neighbor you are trying to check is possible or not.
That is: Total 4 neighbors. If the coordinates of your main cell are x, y then:
1st Diagonal neighbor: x-1, y-1
2nd Diagonal neighbor: x-1, y+1
3rd Diagonal neighbor: x+1, y+1
4th Diagonal neighbor: x+1, y-1
These are all the 4 diagonal neighbors' coordinates but the last thing you need to check is whether they go out of bonds or not. For example for checking the 1st Diagonal neighbor I would do:
if((x-1)>0 && (y-1)>0){
//and then check here if that block is = `0`
}
and for other having say x+1 or y+1 you will need to check whether or not they are less than the NUM. Like if I want to check the 3rd Diagonal Neighbor:
if((x+1)<NUM && (y+1)<NUM){
//and then check here if that block is = `0`
}
Update: What do you mean by check here if that block is = 0?
If you want to check that is the diagonal neighboring blocks are equal to 0 or not then you will need to do it in a loop. Here is how:
public void fun(int[][] grid) {
for(int row = 0; row < NUM; row++) {
for(int col = 0; col < NUM; col++) {
if((grid[row][col] % 2) == 0) {
grid[row][col] = 0;
}
}
}
for(row = 0; row< NUM; row++){
for(int col = 0; col < NUM; col++) {
int count = 0;
// To check for the 1st Diagonal Neighbor
if((row-1)>0 && (col-1)>0){
if(grid[row-1][col-1]==0){
count++;
}
}
//Similarly for 2nd, 3rd and 4th Diagonal Neighbors
//and then
grid[row][col]=count;
}
}
}
Update 2:
For say the 3rd diagonal neighbor the code block would be like this:
if((row+1)<NUM && (col+1)<NUM){
if(grid[row+1][col+1]==0){
count++;
}
}
Answer
final private static int NUM = 6;
public void fun(int[][] grid) {
for(int row = 0; row < NUM; row++) {
for(int col = 0; col < NUM; col++) {
int counter = 0;
if((row - 1) > 0 && (col - 1) > 0) {
if(grid[row - 1][col - 1] == 0) {
counter++;
}
}
if((row - 1) > 0 && (col + 1) < NUM) {
if(grid[row - 1][col + 1] == 0) {
counter++;
}
}
if((row + 1) < NUM && (col - 1) > 0) {
if(grid[row + 1][col - 1] == 0) {
counter++;
}
}
if((row + 1) < NUM && (col + 1) < NUM) {
if(grid[row + 1][col + 1] == 0) {
counter++;
}
}
grid[row][col] = counter;
}
}
}