Intro programming: Conways Game of Life - java

I have been working on this code for a long time and i can't seem to figure it out. The top portion of my code works to pre-populate the grid. but for some reason I cant get my image to move and to grow as its supposed to. Please Help Me!!
import java.util.Random;
public class Life {
public static void main(String []args){
//Declaring and initializing grid variables
int gridSize = 200;
int cellSize = 3;
Grid grid = new Grid(gridSize, cellSize, "The Game of Life");
grid.setDelay(10);
Random r = new Random();
int aliveColor = 1;
int deadColor= 0;
int aliveCells;
int row = 0;
int column = 0;
int val = grid.getPos(row,column);
int generation;
int aliveNeighbors;
int cell;
//loop statement pre-populating the grid
for (row = 0; row <= gridSize-1; row++){
for(column = 0; column <= gridSize-1; column++){
if (r.nextInt(100) > 49){
grid.setPos(row, column, aliveColor);
}
else
grid.setPos(row, column, deadColor);
}
}
grid.initialize();
//Loop executing the rules of the Game of Life
do
{
row = 0;
column = 0;
generation = 0;
while (row <= gridSize-1){
while (column <= gridSize-1){
cell = grid.getPos(row, column);
aliveNeighbors = grid.matchingNeighbors(row, column,aliveColor);
if (cell == aliveColor)
{
if (aliveNeighbors == 2 || aliveNeighbors == 3){
val =1;
grid.setPos(row, column,val);
}
}
else if (cell == deadColor)
{
if (aliveNeighbors == 3){
val =1;
grid.setPos(row, column,val);
}
}
else{
val = 0;
grid.setPos(row,column,val);
}
column++;
}
row++;
grid.update();
}
grid.update();
generation++;
} while (generation >= 0);
}
}
EDIT
//Loop executing the rules of the Game of Life
do
{
row = 0;
column = 0;
generation = 0;
while (row <= gridSize-1){
while (column <= gridSize-1){
cell = grid.getPos(row, column);
aliveNeighbors = grid.matchingNeighbors(row, column,aliveColor);
if (cell == aliveColor)
{
if (aliveNeighbors == 2 || aliveNeighbors == 3){
val =1;
grid.setPos(row, column,val);
}
if (aliveNeighbors ==1 || aliveNeighbors == 4){
val = 0;
grid.setPos(row,column,val);
}
}
else
{
if (cell == deadColor)
{
if (aliveNeighbors == 3){
val =1;
grid.setPos(row, column,val);
}
if (aliveNeighbors == 1 || aliveNeighbors == 2 || aliveNeighbors == 4){
val = 0;
grid.setPos(row, column, val);
}
}
}
column++;
}
row++;
}
grid.update();
generation++;
} while (generation >= 0);
}
EDIT****
do
{
row = 0;
column = 0;
generation = 0;
while (row <= gridSize-1){
while (column <= gridSize-1){
cell = grid.getPos(row, column);
aliveNeighbors = grid.matchingNeighbors(row, column,aliveColor);
if (cell == aliveColor)
{
if (aliveNeighbors == 2 || aliveNeighbors == 3){
grid.setPos(row, column, aliveColor);
} else {
grid.setPos(row,column, deadColor);
}
}
else
{
if (cell == deadColor){
if (aliveNeighbors == 3){
grid.setPos(row, column,aliveColor);
} else {
grid.setPos(row,column,deadColor);
}
}
}
column++;
}
row++;
}
grid.update();
generation++;
} while (generation >= 0);
}

Two problems that I have noticed:
You should only update the grid after you complete updating all the cells.
Your indentation was off, and there was a } misplaced. After re-formatting, it can clearly be seen that you are not covering all the cases, so there are cells that do not get a new value. For example, if a cell is alive, you only handle the case when it has 2 or 3 neighbors, but there is no else to that if, and so, a live cell with 1 or 4 or more neighbors is never updated.
You may think that somehow in that case the code falls through to the general "else", but in fact, it never gets there. All cell values are either "alive" or "dead". So a construct such as:
if ( cell == aliveColor ) {
// Handle alive cell
} else if ( cell == deadColor ) {
// Handle dead cell
} else {
// Handle all other cases - but there are none!
}
Is equivalent to:
if ( cell == aliveColor ) {
// Handle alive cell
} else {
// Handle dead cell
}
The original "else" is never reached because there is no other case than "aliveColor" and "deadColor".
Response to your edit:
if (cell == aliveColor)
{
if (aliveNeighbors == 2 || aliveNeighbors == 3){
val =1;
grid.setPos(row, column,val);
}
if (aliveNeighbors ==1 || aliveNeighbors == 4){
val = 0;
grid.setPos(row,column,val);
}
}
For some reason, you seem to think that there could be at most 4 neighbors to each cell. Look at the example cell in your lab document again:
⬜︎⬜︎⬛︎
⬛︎⬜︎⬛︎
⬛︎⬛︎⬜︎
This cell has 5 dead neighbors, and 3 live ones. In fact, each cell can have up to 8 neighbors - the diagonal neighbors also count!
But your rules were:
If x is alive and has exactly 2 or 3 live neighbors, then x survives to the next generation. Otherwise it dies.
If x is dead and has exactly 3 live neighbors, then x is alive in the next generation. Otherwise it remains dead
This otherwise translates directly to else in programming. So instead of having a second if with the complementary condition (if there are 1, 4,5,6,7 or 8 live neighbors...), just give the first if an else:
if (aliveNeighbors == 2 || aliveNeighbors == 3) {
grid.setPos(row, column, aliveColor);
} else {
grid.setPos(row, column, deadColor);
}
The same thing applies to the rules for a dead cell, of course.
(Note that I also removed the val=1 and just used the value directly, val is superfluous. Also I used the names that explain what the value is rather than 1 and 0 (what if you want to change the game to work with green and red)?).
One important thing that I didn't notice before:
do
{
row = 0;
column = 0;
generation = 0;
while (row <= gridSize-1){
while (column <= gridSize-1){
You initialize both the row and the column to zero before the row loop.
This means that at the end of the first row, column stays gridSize-1 and is not set to zero again. So in fact you are only updating one row and then only the last column of each of the other rows.
It should be:
do
{
row = 0;
generation = 0;
while (row <= gridSize-1){
column = 0;
while (column <= gridSize-1){
Or you could use a for loop:
for ( row = 0; row < gridSize; row++ ) {
for ( column = 0; column < gridSize; column++ ) {
...
If you choose to do so, don't forget to remove the row++ and column++ from inside the loop body so that they are not incremented twice.

It looks like you are using only one grid, you need a second grid where to put the cells next state ...

Related

Is there a simpler way to find a 3x3 matrix in a 11x11 matrix?

A few friends and I are creating a simulation based game using java where our "players" go out on an 11x11 matrix full of a Class called Chunk. In order for the players to be able to interact with the world around it, it requires us to see the information of the Chunks in a 3x3 surrounding the player.
Example(smaller matrix size, x=Nothing There, o=Person):
xxxxxxxxxxx
xxxxxxxxxxx
xxxxxoxxxxx
xxxxxxxxxxx
xxxxxxxxxxx
We would need to be able to collect the chunks surrounding the player(o)(in this case row's [1],[2],[3] and col's[4],[5],[6]). Of course, the 3x3 matrix cannot leave the bounds of the matrix and if it does we just ignore the ones that aren't there and collect the Chunks we can collect. Currently, we have a block of code that works for the desired task but we feel like it could be made faster, cleaner, or completely remade in another way.
fullMap is an array which is initialized to be an 11x11 full of Chunk's and
currentRow, currentCol both are integers which relate to the position in fullMap the player is currently in.
for(int row = 0; row < fullMap.length; row++) {
for (int col = 0; col < fullMap[row].length; col++) {
if (((row == currentRow-1) && (col == currentCol)) && currentRow != 0) {
//store the chunk
} else if (((row == currentRow-1) && (col == currentCol+1)) && (currentRow != 0 && currentCol != 10)) {
//store the chunk
} else if (((row == currentRow-1) && (col == currentCol-1)) && (currentRow != 0 && currentCol != 0)) {
//store the chunk
} else if (((row == currentRow) && (col == currentCol+1)) && currentCol != 10) {
//store the chunk
} else if (((row == currentRow) && (col == currentCol-1)) && currentCol != 0) {
//store the chunk
} else if (((row == currentRow+1) && (col == currentCol+1)) && (currentRow != 10 && currentCol != 10)){
//store the chunk
} else if (((row == currentRow+1) && (col == currentCol)) && currentRow != 10) {
//store the chunk
} else if (((row == currentRow+1) && (col == currentCol-1)) && (currentRow != 10 && currentCol != 0)){
//store the chunk
}
}
}
If other information is needed I am happy to post it.
You do not need to iterate over the fullMap, do you?
You know the (currentRow, currentCol) and from there you go -1/+1 in each direction. In total you will have 9 fields to check.
...
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1 ; j++) {
if (isMovePossible(currentRow + i, currentCol + j)) {
// store chunk
}
}
}
...
private static boolean isMovePossible(int row, int col) {
return row >= 0 && row <= 10 && col >= 0 && col <=10;
}

Tic-Tac-Toe display not displaying correctly

So I have created a simple tic-tac-toe console program. But for some reason my methods aren't displaying the board correctly.
The display of the code prints out like this:
Tic-Tac-Toe
------------
Player 'X', enter move (row [1-3] column [1-3]): 2
2
|
|
-----------
|
X
|
-----------
|
|
Player 'O', enter move (row [1-3] column [1-3]):
The code:
/**
* The grid represents the game board
*/
public class Grid {
int ROWS = 3; // Defines the amount of rows
int COLUMNS =3; // Defines the amount of columns
Box[][] board; // Represents the game board as a grid
int currentrow, currentcol; // Row and Column that was played last
public Grid()
{
board = new Box[ROWS][COLUMNS]; // Constructor initializes the game board
for(int row = 0; row < ROWS; row++) {
for (int col = 0; col < COLUMNS; col++) {
board[row][col] = new Box(row,col);
}
}
}
public void init()
{
for (int row = 0; row < ROWS; row++) { // Re-initializes the game board
for (int col = 0; col < COLUMNS; col++) {
board[row][col].clear();
}
}
}
public boolean isDraw()
{
for (int row = 0; row < ROWS; row++) { // Returns true if the game is a draw (no more empty boxes)
for (int col = 0; col < COLUMNS; col++) {
if (board[row][col].content == Player.EMPTY) {
return false; // An empty box found, not a draw, exits
}
}
}
return true; // No empty boxes return true is then a draw
}
public boolean hasWon(Player thePlayer) {
return (board [currentrow] [0] .content == thePlayer && board [currentrow] [1].content == thePlayer && board [currentrow] [2].content == thePlayer // 3 in a row
|| board [0] [currentcol].content == thePlayer && board [1] [currentcol].content == thePlayer && board [2] [currentcol].content == thePlayer // 3 in a column
|| currentrow == currentcol
&& board[0] [0].content == thePlayer // 3 in a diagonal
&& board[1] [1].content == thePlayer
&& board[2] [2].content == thePlayer
|| currentrow + currentcol == 2
&& board[0][2].content == thePlayer // 3 in the opposite diagonal
&& board[1][1].content == thePlayer
&& board[2][0].content == thePlayer);
}
public void paint()
{
for (int row = 0; row < ROWS; row++) { // Paints (displays) the full board
for (int col = 0; col < COLUMNS; col++) {
board[row][col].paint();
if (col < COLUMNS - 1)
System.out.println("|");
}
System.out.println();
if (row < ROWS - 1) {
System.out.println("-----------");
}
}
}
}
I want the code to print out the display in the correct way. I think there must be a simple mistake I have made either in the paint() method or when I initialized the grid. Please can someone see where I have gone wrong.
You need to modify your painting methods.
for (int row = 0; row < ROWS; row++) { // Paints (displays) the full board
for (int col = 0; col < COLUMNS; col++) {
board[row][col].paint();
if (col < COLUMNS - 1)
System.out.print("|");
}
System.out.println();
if (row < ROWS - 1) {
System.out.println("-----------");
}
}
First, you need to use println only when needed, the rest of the time just use print.
And the same is for Box.paint not visible here. But it seems to be using System.out.println instead of System.out.print.
Another thing, Box.paint should return a String instead of sending message in the console. The board is responsible of the painting, not the box.
public String paint(){
return content; //return a `String` " ", "X" or "O"
}
Tested with :
public static void main(String[] args) throws ParseException {
print(new String[][]{
{"X", " ", "O"},
{" ", " ", " "},
{"O", " ", "X"}
});
}
private static void print(String[][] board){
int ROWS = board.length;
int COLUMNS = board[0].length;
for (int row = 0; row < ROWS; row++) { // Paints (displays) the full board
for (int col = 0; col < COLUMNS; col++) {
System.out.print(board[row][col]);
if (col < COLUMNS - 1)
System.out.print("|");
}
System.out.println();
if (row < ROWS - 1) {
System.out.println("-----");
}
}
}
Giving :
X| |O
-----
| |
-----
O| |X
It's hard to give you the answer with 100% certainty if you don't post all of the code. Can you add the implementation of Box and the main method?
The problem seems to be that you are doing System.out.println("|"); when you should be doing System.out.print("|");. System.out.println("|"); will also a new line causing the next thing printed to occur on the next line. You are already handling the newline for the end of the row correctly (the System.out.println(); so System.out.print("|"); should be all you need to do.
Working example with the fix: https://repl.it/repls/DimgreyOutlandishFlashdrive

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;
}

Recursive method that searches an array doesn't work

So I have this recursive method that searches a 4x4 "board" for a word (think boggle except it only looks above, below, left, and right of the current letter). It gets passed an index (the current letter it is searching for from a given word), and the row and column to search around. The first if statement takes care of the first letter, and always works. The next else if statement doesn't work, and I'm not sure why. Any help is appreciated as to why. secondArray is used in another part of the program when it is displayed.
private boolean verifyWord(int index, int row, int column) {
System.out.println(index + " " + row + " " +column);
if (index == 0) {
for (int i = 0; i < letterArray.length; i++) {
for (int i2 = 0; i2 < letterArray[0].length; i2++) {
if (letterArray[i][i2] == wordToFind.charAt(index)) {
secondArray[i][i2] = true;
verifyWord(index+1, i, i2);
}
}
}
} else if (index > 0 && index < wordToFind.length()) {
// check above row
if (row+1 < row) {
if (letterArray[row+1][column] == wordToFind.charAt(index)) {
secondArray[row+1][column] = true;
verifyWord(index+1, row+1, column);
}
}
//check below row
if (row-1 >= 0) {
if (letterArray[row-1][column] == wordToFind.charAt(index)) {
secondArray[row-1][column] = true;
verifyWord(index+1, row-1, column);
}
}
//check left column
if (column-1 >= 0) {
if (letterArray[row][column-1] == wordToFind.charAt(index)) {
secondArray[row][column-1] = true;
verifyWord(index+1, row, column-1);
}
}
//check right column
if (column+1 < letterArray[0].length) {
if (letterArray[row][column+1] == wordToFind.charAt(index)) {
secondArray[row][column+1] = true;
verifyWord(index+1, row, column+1);
}
}
} else {
boolCheck = true;
}
return boolCheck;
}
The first condition if(row+1 < row) in your else if(index > 0 && index < wordToFind.length()) would never be evaluated to true (x+1 is always bigger than x).
You probably want it to be if(row+1 < letterArray.length)

Having trouble getting a vertical detection of connect 4 win

Right now I have a school assignment where I have to create a connect 4 game in java without a gui using arrays. So far I have been able to get the game to detect a horizontal four in a row but I can't seem to get a vertical four in a row. Originally my array was a 6x7 but I have changed it to a 5x5 just to test the concept of swapping the arrays dementions. Just to make less clutter, I only included the part of the code with the vertical detection.
for (column = 0; column < board.length; column++) {
count_piece = 0;
max = 0;
for (row = 0; row < board.length; row++) {
if (max < count_piece) {
max = count_piece;
}
if (board[column][row] == 'X') {
count_piece++;
} else {
count_piece = 0;
}
}
}
System.out.println(max);
if (max == 4) {
System.out.println("\nYou Win!");
break;
}
If you need more information or if anything is not clear please let me know and i'll be glad to provide some more info.
EDIT:
Here is the one with the inverted loop.
for (row = 0; row < board.length; row++) {
count_piece = 0;
max = 0;
for (column = 0; column < board.length; column++) {
if (max < count_piece) {
max = count_piece;
}
if (board[column][row] == 'X') {
count_piece++;
} else {
count_piece = 0;
}
}
}
How about inverting your loop that way your inner loop changing will be the column instead of the row?
Also make your inner loop take the length of the single array you are in.
So instead of using board.length use something like board[i].length
Edit
I think your logic inside your inner loop is wrong...
Try this:
if (board[row][column] == 'X') {
count_piece++;
if(count_piece == 4) {
System.out.println("you win");
return;
}
} else {
count_piece = 0;
}
Here is both checks Horizontal and Vertical with any size array
int count_piece = 0;
//Checking Vertical Win
for (int row = 0; row < board.length; row++) {
count_piece = 0;
for (int column = 0; column < board[row].length; column++) {
if (board[row][column] == 'X') {
count_piece++;
if (count_piece == 4) {
System.out.println("you win");
return;
}
} else {
count_piece = 0;
}
}
}
//Checking Horizontal Win
for (int column = 0; column < board.length; column++) {
count_piece = 0;
for (int row = 0; row < board[column].length; row++) {
if (board[row][column] == 'X') {
count_piece++;
if (count_piece == 4) {
System.out.println("you win");
return;
}
} else {
count_piece = 0;
}
}
}
The main issue I see is assigning max before incrementing count_piece (meaning you would have to get 5 in a row).
Also as others have said length might have issue (not familiar with java so you might get away with it as length would either be 5 or 25 depending if it takes all indices or just the first columns indices. regardless when you go back to 6x7 it will break.
Also what your code is currently doing is going through each column and checking if the row has 4 in a row. What you want is to check for 4 in a row on both axis (my solution would be to have a row count variable and a column count variable (unless you need diagonal)).
adding
count_piece_Col=0; max=0;
above the first for loop and incrementing it similarly to the row count
*lazy way
for(column=0;column<board.length;column++)
{
count_piece=0; max_r=0;
for(row=0;row<board.length;row++)
{
if(max_r<count_piece)
{
max_r=count_piece;
}
if(board[column][row]=='X')
{
count_piece++;
}
else
{
count_piece=0;
}
}
}
for(row=0;row<board.length;row++)
{
count_piece=0; max_c=0;
for(column=0;column<board.length;column++)
{
if(max_c<count_piece)
{
max_c=count_piece;
}
if(board[column][row]=='X')
{
count_piece++;
}
else
{
count_piece=0;
}
}
}

Categories

Resources