So, I've been working on this Game of Life (http://www.bitstorm.or g/gameoflife/) project, and all the code has been written. However, it will not run. First, I will post the error message and the fragment of code I think to be the cause of the problem. Then, I will post the code to all 3 of my java files in their entirety should you wish to reference them. Any help would be much appreciated.
Also, if it would help fix my error, I would like guidance as to make these cells live on a toroid, meaning that any cells that hit the bottom pop up at the top and any cells that hit the left edge come out on the right.
Here's the error message:
Here's the code fragment I believe to be the problem:
Here's my Cell.java File:
Here's my starter file, GameStart.java:
And finally, here's the class that handles the display, Display.java:
Thanks in advance for your help!
Also, if it would help fix my error, I would like guidance as to make these cells live on a toroid, meaning that any cells that hit the bottom pop up at the top and any cells that hit the left edge come out on the right.
Here's the error message:
Code:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: -1 at Cell.prepareNextTurn(Cell.java:82) at GameStart.runastep(GameStart.java:42) at Display.paint(Display.java:57) at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source) at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source) at javax.swing.RepaintManager.seqPaintDirtyRegions(Unknown Source) at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(Unknown Source) at java.awt.event.InvocationEvent.dispatch(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source)
Here's the code fragment I believe to be the problem:
Code:
int[][] adjacent = {{1,1},{1,0},{0,1},{1,-1},{-1,1},{0,-1},{-1,0},{-1,-1}}; for(int i = 0; i < adjacent.length; i++) { //System.out.println("myX" + myX + " myY" + myY + " context" + context.length); if(context[myY + adjacent[i][0]][myX + adjacent[i][1]].getAlive()) { myNeighbors++; }
Here's my Cell.java File:
Code:
import java.awt.Color; import java.awt.Graphics; /** * @author administrator * * TODO To change the template for this generated type comment go to * Window - Preferences - Java - Code Style - Code Templates */ public class Cell { public static int cellCounter = 0; // Each time a new cell is created, this is incremented private int myX, myY; // x,y position on grid private boolean myAlive; // alive (true) or dead (false) private int myNeighbors; // count of neighbors with respect to x,y private boolean myAliveNextTurn; // Used for figuring out state in next iteration private Color myColor; // Based on alive/dead rules private final Color DEFAULT_ALIVE = Color.ORANGE; private final Color DEFAULT_DEAD = Color.GRAY; private Cell[][] context; // this is how we can check our neighbors! public Cell(Cell[][] thegrid) { // Object() is called by default myAlive = false; // dead myColor = Color.GRAY; context = thegrid; } public Cell(int x, int y, boolean alive, Color color, Cell[][] thegrid) { myAlive = alive; myColor = color; myX = x; myY = y; cellCounter++; context = thegrid; } public boolean getAlive() { return myAlive; } public int getX() { return myX; } public int getY() { return myY; } public Color getColor() { return myColor; } public void setAlive (boolean alive, Color color) { myColor = color; myAlive = alive; } public void setAlive (boolean alive) { if (alive) { setAlive(true, DEFAULT_ALIVE); } else { setAlive(false, DEFAULT_DEAD); } } public void toggle(){ //System.out.println("ok, what do you want to happen to cell[" + myX +"][" + myY +"]?"); if(context[myY][myX].getAlive()) { context[myY][myX].setAlive(false); } else { context[myY][myX].setAlive(true); } } /**************this method has to check all the neighbors to * count how many are living cells. Depending on the answer, * and whether or not the cell is CURRENTLY alive, it will * determine whether it will be alive or not NEXT turn */ public void prepareNextTurn() { //System.out.println("you need to fill this in!"); int[][] adjacent = {{1,1},{1,0},{0,1},{1,-1},{-1,1},{0,-1},{-1,0},{-1,-1}}; for(int i = 0; i < adjacent.length; i++) { //System.out.println("myX" + myX + " myY" + myY + " context" + context.length); if(context[myY + adjacent[i][0]][myX + adjacent[i][1]].getAlive()) { myNeighbors++; } } System.out.println(myX); System.out.println(myY); if(context[myX][myY].getAlive()) { if(myNeighbors < 2 || myNeighbors > 3) { context[myY-1][myX-1].toggle(); } else { //stay alive } } else { if(myNeighbors == 3) { context[myY][myX].toggle(); } else { //stay dead } } } /**********************bookkeeping * this method updates the turn, */ public void setNextTurn() { //System.out.println("you also need to fill this in!"); } public void setColor (Color color) { myColor = color; } /****maybe I should have the method for drawing a cell in the Display class! but this is ok and needs no modification **************/ public void draw (int x_offset, int y_offset, int width, int height, Graphics g) { // I leave this understanding to the reader int xleft = x_offset + 1 + (myX*(width+1)); int xright = x_offset + width + (myX*(width+1)); int ytop = y_offset + 1 + (myY*(height+1)); int ybottom = y_offset + height + (myY*(height+1)); Color temp = g.getColor(); g.setColor(myColor); g.fillRect(xleft, ytop, width, height); } }
Code:
import java.awt.Color; import javax.swing.JFrame; import java.util.Random; public class GameStart { public static final int ROWS = 80, COLS = 100; public static Cell[][] cell = new Cell[ROWS][COLS]; public static Display display = new Display(cell); public static void main(String[] args) { initialize(); // Bring up a JFrame with squares to represent the cells display.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); display.setVisible(true); } public static void initialize() { for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { cell[i][j] = new Cell(j, i, false, Color.GRAY, cell); if (java.lang.Math.random() < 0.25){ cell[i][j].setAlive(true); } /*****one way to seed the Grid with some random data: if (java.lang.Math.random() < 0.25){ cell[i][j].setAlive(true); } ********************but you could do many other things, too! **/ } } System.out.println(Cell.cellCounter); // demonstrates use of a class variable } public static void runastep(){ //first run through grid calculating what next turn status will be for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { // what do you think should be here? cell[i][j].prepareNextTurn(); } } //then go back and run grid, moving next turn status into place for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { //what do you think should be here? cell[i][j].setNextTurn(); } } } }
And finally, here's the class that handles the display, Display.java:
Code:
import java.awt.*; import java.awt.event.*; import javax.swing.*; // Note that the JFrame is set up to listen for mouse clicks // and mouse movement. To achieve this, the MouseListener and // MousMotionListener interfaces are implemented and there is additional // code in init() to attach those interfaces to the JFrame. public class Display extends JFrame implements MouseListener, MouseMotionListener { private final int DISPLAY_WIDTH = 750; private final int DISPLAY_HEIGHT = 600; private final int X_GRID_OFFSET = 25; // 10 pixels from left private final int Y_GRID_OFFSET = 40; // 10 pixels from top private final int CELL_WIDTH = 5; private final int CELL_HEIGHT = 5; private final Cell[][] myCell; private StartButton startStop = new StartButton(); private boolean paintloop = false; public Display(Cell[][] cell) { myCell = cell; init(); } public void init() { setBackground(Color.WHITE); setSize(DISPLAY_WIDTH, DISPLAY_HEIGHT); getContentPane().setLayout(null); // Example of setting up a button. // See the StartButton class nested below. add(startStop); startStop.setBounds(100,500,72,36); startStop.setVisible(true); addMouseListener(this); addMouseMotionListener(this); repaint(); } public void paint(Graphics g) { g.setColor(Color.BLACK); drawGrid(g); drawCells(g); drawComponents(); // buttons, etc., go here if (paintloop) { try { Thread.sleep(50); //you can change this value! } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //nextGeneration(); GameStart.runastep(); //this method will run one generation repaint(); } } void drawComponents() { startStop.repaint(); } void drawGrid(Graphics g) { for (int i = 0; i <= GameStart.ROWS; i++) { g.drawLine(X_GRID_OFFSET, Y_GRID_OFFSET + (i*(CELL_HEIGHT+1)), X_GRID_OFFSET + GameStart.COLS*(CELL_WIDTH+1), Y_GRID_OFFSET + (i*(CELL_HEIGHT+1))); } for (int i = 0; i <= GameStart.COLS; i++) { g.drawLine(X_GRID_OFFSET + (i*(CELL_WIDTH+1)), Y_GRID_OFFSET, X_GRID_OFFSET + (i*(CELL_WIDTH+1)), Y_GRID_OFFSET + GameStart.ROWS*(CELL_HEIGHT+1)); } } void drawCells(Graphics g) { // Have each cell draw itself for (int i = 0; i < GameStart.ROWS; i++) { for (int j = 0; j < GameStart.COLS; j++) { // The cell cannot know for certain the offsets nor the height // and width; it has been set up to know its own position, so // that need not be passed as an argument to the draw method myCell[i][j].draw(X_GRID_OFFSET,Y_GRID_OFFSET,CELL_WIDTH,CELL_HEIGHT,g); } } } void painter() { repaint(); } /*************************THIS IS AN INNER CLASS************************* * that is, a class defined within a class, all it does is run the start * button. When start is clicked, the "paintloop" variable in the * Display object is set to true; when stop is clicked, it's set to false. * when paintloop is true, the game will be running, when it's false * it won't (and perhaps the board may be edited) */ class StartButton extends JButton implements ActionListener { StartButton() { super("Start"); addActionListener(this); } public void actionPerformed(ActionEvent arg0) { if (this.getText().equals("Start")) { paintloop = true; setText("Stop"); } else { paintloop = false; setText("Start"); } painter(); } } /********************************************************* * Note that the Display is ALSO listening for mouse clicks! * there is a MouseEvent class that contains information about * MouseClicks; all we need to know is the locaton of the click * IF IT HAPPENS WHEN THE START BUTTON HAS NOT BEEN PRESSED, * THIS WILL ALLOW THE USER TO set cells to be ALIVE or DEAD */ public void mouseClicked(MouseEvent me) { if (paintloop==false){ //CONVERTS THE LOCATION OF THE CLICK IN PIXELS TO THE //CORRECT ROW AND COLUMN IN THE GRID int x = (me.getX() - X_GRID_OFFSET-1)/(CELL_WIDTH+1); int y = (me.getY() - Y_GRID_OFFSET - 1)/(CELL_HEIGHT+1); //be sure the click is actually IN the grid //to avoid ArrayIndexOutOfBounds Exception if ((0<=x)&& (x< myCell.length)&& (0<=y)&&(y<myCell[0].length)){ myCell[y][x].toggle(); repaint(); } //System.out.println("clicked on (" + x + ","+ y + ") element"); } } /************************* * a MouseListener must include ALL the methods for the MouseListener * interface; but we don't actually need to do anything for these: */ public void mouseEntered(MouseEvent arg0) { } public void mouseExited(MouseEvent arg0) { } public void mousePressed(MouseEvent arg0) { } public void mouseReleased(MouseEvent arg0) { } public void mouseDragged(MouseEvent arg0) { } public void mouseMoved(MouseEvent arg0) { } }
Thanks in advance for your help!
Comment