/** * Main class for life application * Interface center **/ import java.awt.*; import java.util.Vector; import java.applet.*; public class Life extends Applet { Grid grid; // The life grid data thingy Image imgOffScreen; // Double buffer stuff Graphics gOffScreen; // Image imgDots[] = new Image[2]; Image imgTitle; MediaTracker tracker; // Check when dots are loaded. public void init() { super.init(); //{{INIT_CONTROLS setLayout(null); resize(238,285); button1=new Button("Random"); button1.setFont(new Font("Dialog",Font.PLAIN,10)); add(button1); button1.reshape(91,247,42,30); button2=new Button("Next"); button2.setFont(new Font("Dialog",Font.PLAIN,10)); add(button2); button2.reshape(7,247,35,30); button3=new Button("Clear"); button3.setFont(new Font("Dialog",Font.PLAIN,10)); add(button3); button3.reshape(49,247,35,30); //}} // Offscreen stuff imgOffScreen = createImage(this.size().width, this.size().height); gOffScreen = imgOffScreen.getGraphics(); // Load the dot .GIF files imgDots[0] = getImage(getCodeBase(), "images/b.gif"); imgDots[1] = getImage(getCodeBase(), "images/g.gif"); // Mediatracker stuff tracker = new MediaTracker(this); tracker.addImage(imgDots[0],0); tracker.addImage(imgDots[1],0); // Load title image (TODO) imgTitle = getImage(getCodeBase(), "images/title.gif"); // Init and clear the grid grid = new Grid(); grid.setAll(0); } /** * Get rid of that dang flicker! **/ public void update(Graphics g) { paint(g); } /** * Paint the life screen * Only redraw the dots that are in the dirty list **/ public void paint(Graphics g) { // Get the dirty list Vector vDirty = grid.getDirty(); Point pCell; // Draw dots that are in the grid's dirty list for (int iCount = 0; iCount < vDirty.size(); iCount++) { // Get the grid location that is dirty pCell = (Point) vDirty.elementAt(iCount); // Draw the dot gOffScreen.drawImage(imgDots[ grid.getGrid(pCell.x, pCell.y) ], pCell.x*12, pCell.y*12, this); } // Blit the pretty javalife image gOffScreen.drawImage(imgTitle, 0, 243, this); // Blit double buffer g.drawImage(imgOffScreen, 0, 0, this); // Print the generation # (TODO) // System.out.print("Generation: " + grid.getGeneration() ); if ( (tracker.statusID(0, true ) & MediaTracker.COMPLETE) == 0 ) { g.setColor( Color.black ); g.fillRect( 30, 50, 200, 90 ); g.setFont(new Font("Dialog",Font.PLAIN,18)); g.setColor( Color.cyan ); g.drawString("Loading Images...", 40, 70 ); g.drawString("Please Wait", 40, 90 ); repaint(); } else // We've repainted, so dirty list should be cleared grid.clearDirty(); } public boolean handleEvent(Event event) { if (event.id == Event.MOUSE_DOWN && event.target == this) { mouseDownThis(event); return true; } else if (event.id == Event.ACTION_EVENT && event.target == button1) { clickedRandom(); return true; } else if (event.id == Event.ACTION_EVENT && event.target == button3) { clickedClear(); return true; } else if (event.id == Event.ACTION_EVENT && event.target == button2) { clickedNext(); return true; } return super.handleEvent(event); } //{{DECLARE_CONTROLS Button button1; Button button2; Button button3; //}} /** * 'Next' button pressed - Do a generation **/ public void clickedNext() { grid.calcGeneration(); repaint(0); } /** * 'Clear' button pressed - Clear the grid **/ public void clickedClear() { grid.setAll(0); repaint(0); } /** * 'Random' button pressed - Randomize grid **/ public void clickedRandom() { grid.randomize(); repaint(0); } /** * Mouse was pressed down * change the value of the location pressed **/ public void mouseDownThis(Event ev) { // Mouse -- grid conversion float fDistMod = (float)20 / (float)238; // Get the opposite value of clicked location int val = grid.getGrid( (int)(ev.x * fDistMod), (int)(ev.y * fDistMod) ); val++; val %= 2; // Change it! grid.setGrid( (int)(ev.x * fDistMod), (int)(ev.y*fDistMod), val); // Show it! repaint(0); } } /** * The grid class * This serves as the logic area for the life program, * which handles the data of the life grid and generating * new generations and such. **/ import java.util.Vector; import java.awt.Point; class Grid { int iSize; // Size of one side of data (2-d) int iData[]; // The data itself int iTData[]; // Temp data for copying Vector vDirty; // Dirty list int iGeneration; // Generation count /** * Allocate mem for grid, etc **/ Grid() { iSize = 20; iGeneration = 0; // Alloc for main grid iData = new int[iSize * iSize]; // Alloc for temporary grid iTData = new int[iSize * iSize]; // Create the vector vDirty = new Vector(5,5); } /** * Deallocate for the grid **/ /*~Grid() { delete iData; delete iTData; delete vDirty; }*/ /** * @return The size of the grid... X and Y dim are same **/ int getSize() { return iSize; } /** * Find out what value is at this location * This is better since it doesn't allow OOB errors * @param x Location on grid * @return The value at this location **/ int getGrid(int x, int y) { x+=iSize; x%=iSize; y+=iSize; y%=iSize; return iData[ x + y*iSize ]; } /** * Set the value of a location of the grid * @param x The location * @param value The value to set it **/ void setGrid(int x, int y, int value) { iData[ x + y*iSize ] = value; vDirty.addElement( new Point(x,y) ); } /** * @return The generation value **/ int getGeneration() { return iGeneration; } /** * The dirty list is used to determine if the grid has changed * since the last update. This is done to save time, so that * we don't need to redraw the same dot image over itself. * @return List of dirty spots **/ Vector getDirty() { return vDirty; } /** * Clear the dirty list * This should be done when the implementation has redrawn screen **/ void clearDirty() { vDirty.removeAllElements(); } /** * @param x The location on the grid to test * @return The number of neighbors for this grid **/ private int numNeighbors(int x, int y) { int iCount = 0; for (int iY = -1; iY < 2; iY++) { for (int iX = -1; iX < 2; iX++) { iCount+= getGrid( iX + x, iY + y); } } // Be sure to exclude where you are iCount-= getGrid( x, y ); return iCount; } /** * Determine the next generation of the grid * Modifies the iGrid array of locations * Also updates the gOffScreen member to display new grid **/ void calcGeneration() { int iNumNeighbors; for (int iY = 0; iY < iSize; iY++) { for (int iX = 0; iX < iSize; iX++) { iNumNeighbors = numNeighbors(iX, iY); // Determine life status of piece if (iNumNeighbors <= 1) iTData[iX + iY*iSize] = 0; if (iNumNeighbors == 2) iTData[iX + iY*iSize] = getGrid(iX, iY); if (iNumNeighbors == 3) iTData[iX + iY*iSize] = 1; if (iNumNeighbors >= 4) iTData[iX + iY*iSize] = 0; // Do dirty check -- Draw only what has changed to board // What about when an area is covered??? if ( getGrid( iX, iY ) != iTData[ iX + iY*iSize] ) vDirty.addElement( new Point(iX, iY) ); } } // Now copy temporary grid into new one System.arraycopy(iTData, 0, iData, 0, iSize*iSize); // Tada. It's now the next generation! iGeneration++; } /** * Flush the current grid with one value * @param value The value to make the entire grid **/ void setAll(int value) { for (int iY = 0; iY < iSize; iY++) { for (int iX = 0; iX < iSize; iX++) { iData[iX + iY*iSize] = value; vDirty.addElement( new Point(iX, iY) ); } } iGeneration = 0; } /** * Fill the grid with random 0's and 1's **/ void randomize() { for (int iY = 0; iY < 20; iY++) { for (int iX = 0; iX < 20; iX++) { // Set the grid iData[iX + iY*20] = (int) Math.round(Math.random() * 1); vDirty.addElement( new Point(iX, iY) ); } } iGeneration = 0; } }