Checking if certain value repeats 5 consecutive times in array - java

I'm attempting to write a simple m, n, k- game in Java. The game is set on a 10 by 10 "board", which is graphically represented as a grid with 10 rows and 10 columns. To win the game the player must select 5 cells either horizontally, vertically or diagonally.
I'm having issues with writing an algorithm that checks whether a certain player has won the game. The game "board" is internally represented as a two-dimensional array called matrix with 10 elements for each dimension. Since it is an array of int's, it initially is filled with zeroes. I represent the two players as the number 1 and the number 2. I've created a method called checkIfWinOrDraw which has input parameters of the x coordinate, the y coordinate, and the player who last made a move. This is run each time a cell has been selected. I'm currently at the very basic first step of checking whether there are five consecutive values corresponding to the player's number in the column of the last selected cell. I've written some logic that implements this check, but it does not work, and I find myself unable to figure out why, so I was hoping someone here could help me out. To be clear, I've searched around quite extensively, but I've only managed to find solutions which are quite vaguely related to my problem, and I was unable to derive a solution from them, as I am still quite the amateur at programming in general. So my question is this this: what am I doing wrong and what would be the proper solution to this problem?
The code in question:
public void checkIfWinOrDraw(int x, int y, int player){
// check columns
for(int i = 0; i < 9; i++) {
int counter = 1;
if (matrix[x][i] == player){
if(matrix[x][i] == matrix[x][i+1]){
counter++;
}
if (counter == 5) {
if(player == 1) {
JOptionPane.showMessageDialog(null, "Game over, RED wins!");
} else {
JOptionPane.showMessageDialog(null, "Game over, BLUE wins!");
}
}
} else {
counter = 1;
}
}
}
Note: I did not mention the 2D array in the title because I'm only operating with 1 dimension at this stage. My apologies if the omission was confusing.

You need to check 4 lines passing through the given point (horizontal, vertical and 2 diagonals). And for each line you have to go in both directions from the point. That gives you 8 consecutive checking loops:
public void checkIfWinOrDraw(int x, int y, int player){
int line = 0;
for (int i = y + 1; i < 10 && matrix[x][i] == player; i++, line++);
for (int i = y; i >= 0 && matrix[x][i] == player; i--, line++);
if (line == 5) {
win(player);
return;
}
line = 0;
for (int i = x + 1; i < 10 && matrix[i][y] == player; i++, line++);
for (int i = x; i >= 0 && matrix[i][y] == player; i--, line++);
if (line == 5) {
win(player);
return;
}
line = 0;
for (int i = x + 1, j = y + 1; i < 10 && j < 10 && matrix[i][j] == player; i++, j++, line++);
for (int i = x, j = y; i >= 0 && j >= 0 && matrix[i][j] == player; i--, j--, line++);
if (line == 5) {
win(player);
return;
}
line = 0;
for (int i = x - 1, j = y + 1; i >= 0 && j < 10 && matrix[i][j] == player; i--, j++, line++);
for (int i = x, j = y; i < 10 && j >= 0 && matrix[i][j] == player; i++, j--, line++);
if (line == 5) {
win(player);
}
}
For convenience, I've put win messages into a separate method:
private static void win(int player) {
if (player == 1) {
JOptionPane.showMessageDialog(null, "Game over, RED wins!");
} else {
JOptionPane.showMessageDialog(null, "Game over, BLUE wins!");
}
}

Your code is initializing the counter variable with 1 in every step of the for loop, so everytime you go to the next column it resets counter to 1. Remove int counter = 1 from the for body.

Related

Problem with ship overlapping in 2D-arrays for Battleships game, Java

I am creating a simple console-based Battleships in Java, for people who is unfamiliar with the game, it's played on a 2D-grid where you can put down different sized ships either horizontally or vertically. In my example it is a 10x10 grid created by using a 2D char-array. The ships are NOT allowed to overlap each other, they can't share the same 1x1 grid.
I have managed to fix so they can't overlap each other, but the problem I have is if a ship share the same column or row (depending on if the ship is placed vertically or horizontally) at the STARTING POSITION, I can't place it down.
See example picture below for better understanding.
'0' is "empty" slots, 'S' is current placed ships(3-sized). I can place (in this example) 4-sized ships at blue markers, but I can't place them like the red markers
public void placeShip(ShipType shipType, int posX, int posY, int shipSize, Placement placement) {
boolean success = true;
char tempChar = 'x';
if(shipType == ShipType.BATTLESHIP)
tempChar = 'B';
else if(shipType == ShipType.CARRIER)
tempChar = 'C';
else if(shipType == ShipType.DESTROYER)
tempChar = 'D';
else if(shipType == ShipType.SUBMARINE)
tempChar = 'S';
if(placement == Placement.HORIZONTAL) {
for(int i = 0; i < posX+shipSize; i++) {
for(int j = 0; j < posX+shipSize; j++) {
if(board[i][posX-1] != '0' || board[posY-1][i] != '0') {
System.out.println("Can't place down the ship ");
success = false;
break;
}
}
}
if(success) {
System.out.println("Got space");
for(int i = 0; i < shipSize; i++) {
board[posY-1][posX-1+i] = tempChar;
success = false;
}
}
}
if(placement == Placement.VERTICAL) {
for(int i = 0; i < posY+shipSize; i++) {
for(int j = 0; j < posX+shipSize; j++) {
if(board[posY-1][i] != '0' || board[i][posX-1] != '0') {
System.out.println("Can't place down the ship ");
success = false;
break;
}
}
}
if(success) {
System.out.println("Got space");
for(int i = 0; i < shipSize; i++) {
board[posY-1+i][posX-1] = tempChar;
success = false;
}
}
}
}
Above is the code I use to place ships, where I send in Position X and Y and the size of the ship, and the direction of the ship.
You need to re-think your loops for checking if a ship can be placed down. Let's break down one of them into plain English:
if(placement == Placement.HORIZONTAL) {
for(int i = 0; i < posX+shipSize; i++) {
for(int j = 0; j < posX+shipSize; j++) {
if(board[i][posX-1] != '0' || board[posY-1][i] != '0') {
System.out.println("Can't place down the ship ");
success = false;
break;
}
}
}
First issue:
for(int i = 0; i < posX+shipSize; i++)
Why are we iterating from 0 to posX+shipSize? we only need to check shipSize spaces. So you should be looping from posX to posX+shipSize, or from 0 to shipSize, not a combination.
Second issue:
Despite your position being horizontal or vertical, you are nesting your for loops. Which means you're doing your loop shipSize times for no reason. You only need to do it once.
Third issue:
if(board[i][posX-1] != '0' || board[posY-1][i] != '0')
The position board[i][posX-1] has no meaning in this context, and is not related to the position of your ship, because you always start at i = 0. So no matter where you're trying to place your ship, if you have one in the same row or col, we have a problem. This is what's causing the issue in your question. Instead, it should be something like: if(board[posY-1][posX-1] != '0').
Lastly, why not just set the position of posX and posY properly? So you don't have to subtract 1 and confuse yourself.
Ultimately, your new block should look something like this (but I can't be sure since you didn't post a minimum reproducible example):
if(placement == Placement.HORIZONTAL) {
for(int i = 0; i < shipSize; i++) {
if(board[posY-1][posX-1+i] != '0') {
System.out.println("Can't place down the ship ");
success = false;
break;
}
}
// your code

How to make if statements smaller and avoid using too many loops for the same cause in java

This code is for one of my assignments (connect four). I need to make this code less than 25 lines and also make the 'if' statements shorter. Also, the board has 6 rows and 7 columns. My code is trying to figure out if a person has won.
I have tried to merge all the loops into one loop, but that does not give me a correct answer.
public static boolean determineWin(String[][] board) {
boolean won = false;
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 4; j++) {
if (board[i][j] != ". ") {
if (board[i][j].equals(board[i][j+1]) && board[i][j+1].equals(board[i][j+2]) && board[i][j+2].equals(board[i][j+3])) {
won = true;
break;
}
}
}
}
for (int i = 5; i > 2; i--) {
for (int j = 6; j > 2; j--) {
if (board[i][j] != ". ") {
if (board[i][j].equals(board[i-1][j-1]) && board[i-1][j-1].equals(board[i-2][j-2]) && board[i-2][j-2].equals(board[i-3][j-3])){
won = true;
break;
}
}
}
for (int j = 0; j < 4; j++) {
if (board[i][j] != ". ") {
if (board[i][j].equals(board[i-1][j+1]) && board[i-1][j+1].equals(board[i-2][j+2]) && board[i-2][j+2].equals(board[i-3][j+3])){
won = true;
break;
}
}
}
for (int j = 0; j < 7; j++) {
if (board[i][j] != ". ") {
if (board[i][j].equals(board[i-1][j]) && board[i-1][j].equals(board[i-2][j]) && board[i-2][j].equals(board[i-3][j])){
won = true;
break;
}
}
}
}
return won;
}
The result should be the same as the code above, but I just need the code to be a bit smaller (25 lines) and the if statements to be shorter.
The code above is inefficient because it has 4 separate for loops (to track the 4 directions in which you can win: 1) Left to right, 2) Top to bottom, 3) Diagonal 4) Diagonal/other direction -AND- because the if statements must check 4 consecutive positions.
To optimize the solution you can recognize that you can maintain the state for how many consecutive same pieces have occurred at each position in the board, for each of the 4 possible directions you can win (4 unique states).
Consider as an example winning in the horizontal direction. As you move left to right along the same row, the state counter increments by 1 if the piece to the left is the same. If there is ever a '.', the counter resets to 0. If there is a different piece, the counter resets to 1. You are in a winning position if any of these 4 state counters gets to 4.
The code below is complete for the winning directions of horizontal (state variable 0), and vertical (state variable 1). It is left as an exercise to complete the two rows which represent each of the diagonal directions (state variables 2 and 3).
public static boolean determineWin(String[][] board) {
int[][][] counters = new int[board[0].length+1][board.length+1][4];
for (int y=0; y<board.length; y++) {
for (int x=0; x<board[0].length; x++) {
if (!board[y][x].equals(".")) {
counters[y][x][0] = (x>0 && board[y][x].equals(board[y][x-1])) ? counters[y][x-1][0] + 1 : 1;
counters[y][x][1] = (y>0 && board[y][x].equals(board[y-1][x])) ? counters[y-1][x][1] + 1 : 1;
// Diagonal 1 TODO: counters[y][x][2] =
// Diagonal 2 TODO: counters[y][x][3] =
if (counters[y][x][0] == 4 || counters[y][x][1] == 4 || counters[y][x][2] == 4 || counters[y][x][3] == 4)
return true;
}
}
}
return false;
}

8 Bishops to occupy whole board [Backtracking]

I have a task to write a program which sets up 8 bishops in chess board to occupy whole board. It should end up when first solution is found and print everything out. Here's my written code in Java, and I struggle with finishing it using backtracking ( that place is commented in the code).
/*
* 0 - not occupied square
* 1 - bishop standing square
* 2 - occupied square (diagonal)
*/
public class BishopsBT {
public int [][] solution;
final int N = 8; // number of squares in column and row (chess board)
final int solved = 120; //Sum of 1's and 2's in case of all occupied board
int sum; //current sum of board
public BishopsBT(){
solution = new int [N][N] ;
}
public void solve() {
if(placeBishops(0)){
//print the result
clear(); // clears all 2's
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
System.out.print(" " + solution[i][j]);
}
System.out.println();
}
} else{
System.out.println("NO SOLUTION EXISTS");
}
}
public boolean placeBishops (int bishop){
for (int row = 0; row < N; row++) {
// check if bishop can be placed
if (canPlace(solution, row, bishop)) {
// place the bishop
solution[row][bishop] = 1;
}
}
if (allSpaceOccupied()) {
return true;
} else {
// SOME BACKTRACKING CODE HERE
return false;
}
}
// check if bishop can be placed at matrix[row][column]
public boolean canPlace(int[][] matrix, int row, int column) {
// we need to check all diagonals
// whether no bishop is standing there
for (int i = row, j = column; i >= 0 && j >= 0; i--, j--) {
if (matrix[i][j] == 1) {
return false;
}
}
for (int i = row, j = column; i >= 0 && j < matrix.length; i--, j++) {
if (matrix[i][j] == 1) {
return false;
}
}
for (int i = row, j = column; i < matrix.length && j >= 0; i++, j--) {
if (matrix[i][j] == 1) {
return false;
}
}
for (int i = row, j = column; i < matrix.length && j < matrix.length; i++, j++) {
if (matrix[i][j] == 1) {
return false;
}
}
// if we are here that means we are safe to place Bishop
return true;
}
public boolean allSpaceOccupied() {
// clears previously occupied space
clear();
// occupies new space
for (int i = 0; i < solution.length; i++) {
for ( int j = 0; j < solution.length; j++) {
if (solution[i][j] == 1) diagonalOccupy(i,j);
}
}
sum = 0;
// counts sum of occupied space
for (int i = 0; i < solution.length; i++) {
for ( int j = 0; j < solution.length; j++) {
sum += solution [i][j];
}
}
if (sum == solved) return true;
// else
return false;
}
public void diagonalOccupy(int row, int column) {
// writes 2 in each bishop's occupied square
for (int i = row, j = column; i >= 0 && j >= 0; i--, j--) {
if (solution[i][j] == 0) {
solution[i][j] = 2;
}
}
for (int i = row, j = column; i >= 0 && j < solution.length; i--, j++) {
if (solution[i][j] == 0) {
solution[i][j] = 2;
}
}
for (int i = row, j = column; i < solution.length && j >= 0; i++, j--) {
if (solution[i][j] == 0) {
solution[i][j] = 2;
}
}
for (int i = row, j = column; i < solution.length && j < solution.length; i++, j++) {
if (solution[i][j] == 0) {
solution[i][j] = 2;
}
}
}
// clears all 2's on the board
public void clear() {
for (int i = 0; i < solution.length; i++) {
for ( int j = 0; j < solution.length; j++) {
if (solution[i][j] == 2) solution[i][j] = 0;
}
}
}
public static void main(String[] args) {
BishopsBT q = new BishopsBT();
q.solve();
}
}
The thing is that at the moment my program puts bishops in first column and this layout does not occupy all space. Of course, I could simply put everything in third column and problem is solved. However, I have to use backtracking and have no idea how. If you have any ideas or tips, I would be really glad to hear them.
Your solution assumes that all bishops must be placed in different rows. This is not true for all solutions. (There is a solution where all bishops are in the third or fourth column. You are not looking for all solutions, but if you were, you'd be missing out on many solutions by this assumption.)
You also don't need the canPlace check: There is no restriction that the bishops can't threaten each other. (This might be a valid technique to speed up the search, but again, you'll miss out on some solutions when you apply it. If you want to use it, there's no need to check all diagonal cells for already placed bishops; it is enough to check whether the current cell has been marked as "occupied" or threatened.)
If you are going to use a brute force approach with backtracking, you could test all possible combinations of bishops. That's C(64, 8) or 4,426,165,368 combinations.
You can cut down on the possibilities drastically, but not by assuming that bishops must be in diferent rows. Instead, note that your solution consists of two independent solutions. A bishop on a white square can only threaten white squares and a bishop on a black square can only threaten black squares. So find a solution to place four bishops on the board that threaten all white squares. Then
(If you want to find all solutions, find all k sub-solutions and combine them to k² complete solutions.)
This separation of cases cuts down the possible arrangements to test to C(32, 8), or 35,960. Your strategy to consider only configurations where there is exaclty one bishop per row checks 8^8 (about 16 million) possibilities. It misses some solutions and checks meny configurations where not four bishops are on white squares and four on black squares.
The principle of backtracking was given in the other answer. If you label the 32 white squares like this:
01 02 03 04
05 06 07 08
09 10 11 12
13 14 15 16
17 18 19 20
21 22 23 24
25 26 27 28
29 30 31 32
you can use an recursive approach like this one (in pseudo-Java):
bool place(int i, int start) {
if (i == 8) {
if (allOccupied()) {
print();
return true;
}
} else {
for (int j = start, j < 32; j++) {
int row = j / 4;
int col = 2 * (j % 4) + row % 2;
// add bishop at (col, row)
// save occupancy matrix
// add threat by (col, row) to matrix
if (place(i + 1, j + 1)) return true;
// revert matrix to saved matrix
// remove bishop from (col, row)
}
}
return false;
}
and start it with
place(0, 0);
You should do something like this :
public boolean placeBishops (int bishop){
if(bishop == 8){
if(allSpaceOccupied()){
//Print the board here, i.e found the solution
//also check the indexing of the bishop,
//i have assumed that they start from 0
return true;
}else{
return false;
}
}
for (int row = 0; row < N; row++) {
// check if bishop can be placed
if (canPlace(solution, row, bishop)) {
// place the bishop
solution[row][bishop] = 1;
boolean found = placeBishops(bishop+1);
if(found == true) return true;
solution[row][bishop] = 0;
}
}
return false;
}
we can check if a place is good for a paticular bishop or not, and accordingly increment the bishop count, if we do not find the solution going down that path, we reset the solution array for the current bishop index and the corresponding row for that bishop, so that we can look for another possible solution.

Check why index is out of bounds

I want to write a program that reads a matrix of positive int with the format txt (the matrix can be of any size). (I read the matrix from the console).
The program looks for a location in the matrix such that if a knight is positioned at that location, all possible moves will land the knight on elements which have the same value and it must have at least 2 options. The program prints the result. for example, the black places are where the knight can move to.
This is the code I wrote. the problem is that i'm getting: "Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at Knights.main(Knights.java:23)", I know it has a problem with the first row (there is no backwards value in the start of the matrix) but I don't know how can I fix it.
public static void main (String[] args) {
String size = StdIn.readLine();
int counter = 0;
int matrixSize = Integer.parseInt(size);
int [][] matrix = new int [matrixSize+1][matrixSize+1];
for (int i=0; i <= matrixSize-1; i++) {
for (int j=0; j <= matrixSize-1; j++) {
if ((matrix[i][j]) > 0)
matrix[i][j] = StdIn.readInt();
}
}
for (int k=0; k <= matrixSize-2; k++) {
for (int l=0; l <= matrixSize-2; l++) {
if (matrix[k-1][l+2] == matrix[k+1][l+2]) {
counter +=1;
StdOut.println(counter); }
else if (matrix[k-1][l+2] == matrix[k+1][l-2]) {
counter +=1;
StdOut.println(counter); }
if (counter>=2)
StdOut.println("location "+ matrix[k][l] + "is surrounded by the number " +matrix[k+1][l-2]);
}
}
if (counter < 2)
StdOut.println("no surrender by any number");
}
}
I would add an extra test here to check if k-1 is greater than 0.
As && is a short-circuit operator, the second expression is not tested if the first is false and can not throw an exception.
Solution
if (k - 1 > 0 && matrix[k - 1][l + 2] == matrix[k + 1][l + 2]) {
counter += 1;
StdOut.println(counter);
} else if (k - 1 > 0 && matrix[k - 1][l + 2] == matrix[k + 1][l - 2]) {
counter += 1;
StdOut.println(counter);
}

Drawing a sqaure on an axis in Java

I'm currently trying to write a program that draws a sqaure.
The user will enter the size (in the length of the sides), the x-coordinate, and the y-coordinate of the bottom-left corner of the square on the grid as command-line parameters to program, in that order.
So an input of "run Question2Square 5 1 1"
draws a square of side length 5 whose bottom left corner is at the position (1, 1).
I've spent a few hours trying to just get the axes to show up correctly. I'm not even on the square yet.
My current code I have is this, but it's wrong:
import java.util.Scanner;
public class Question2square {
public static void main(String[] args) {
// Axis variables
int yAxismin = 0;
int yAxismax = 15;
int xAxismin = 0;
int xAxismax = 15;
//Loop through all coordinates on plane using for loops
for(int y = yAxismin; y >= yAxismin; y++)
{
for(int x = xAxismin; x >= xAxismin; x++)
{
//Draw the axis
if (Axis(x,y) != "") {
System.out.print(Axis (x,y));
}
}
System.out.println("");
}
}
// This method draws the 15x15 axis
public static String Axis(int x, int y)
{
// Each if and else if statement dictates what symbol needs to go where for the axes
// If there is nothing to be drawn, there will simply be a blank space
if (x == 15 && y== 0) return ">";
else if(x == 0 && y == 15) return "^";
else if (x == 0 && y == 0 )return ".";
else if(x == 0 && y >= 0) return "|";
else if(x >= 0 && y==0) return "-";
else return "";
}
}
All that does is run an infinite loop of '-' and I don't know exactly what's wrong.
Also, I need to figure out how I can extend the axes in either direction should an input that is greater than the 15x15 axes is entered.
If anyone could coach me through this, I would really appreciate it. I'm not asking for it to be done for me. I really want to figure this out but I'm a bit stuck right now and very frustrated.
Thanks in advance for any help!
Presumably you want to loop from yAxismin to yAxismax (and ditto for x)? Try
for(int y = yAxismin; y <= yAxismax; y++)
{
for(int x = xAxismin; x <= xAxismax; x++)
{
As you have it, the loop for(int y = yAxismin; y >= yAxismin; y++) will just go on for a very very long time. This as your expression says "start at yAxismin; loop while y is more than yAxismin; and on each iteration add one to y". You need it to stop when y reaches yAxismax.
Also, don't compare strings with == and !=. Use s1.equals(s2). You make this mistake on the line
if (Axis(x,y) != "") {
which should be
if (!Axis(x, y).equals("")) {
To extend the axes, just pass the limits to the Axis function:
public static String Axis(int x, int y, int maxX, int maxY)
{
if (x == maxX && y== 0) return ">";
else if(x == 0 && y == maxY) return "^";
else if (x == 0 && y == 0 )return ".";
else if(x == 0 && y >= 0) return "|";
else if(x >= 0 && y==0) return "-";
else return "";
}
...
// call it with
String drawThis = Axis(x, y, xAxismax, yAxismax);

Categories

Resources