internal int CompareTo(LifeRow rowTarget , int ixBegin, int ixEnd) { // Overloaded version. Specifies a // begin and end for the range of // cells to compare. if (rowTarget == null) { return(1); } for (int j = ixBegin; j <= ixEnd; j++) { if (cellsRow[j] == rowTarget.cellsRow[j]) { continue; } if (cellsRow[j] < rowTarget.cellsRow[j]) { return(-1); } if (cellsRow[j] > rowTarget.cellsRow[j]) { return(+1); } } return(0); }
internal int CompareTo(LifeRow rowTarget) { // CompareTo tradionally returns three // possible values, 0 (==), -1 (<) // and +1 (>); and we wish to // maintain that convention. But, // for a row, only "==" and "!=" // is meaningful. So the definition // of "<" and ">" is somewhat arbitrary // here. // The definition of "<" and ">" in // this code sequence is optimized // for performance, given that // most CompareTo calls will be // comparing the Nth row of one // generation to the Nth row of // an adjacent generation. // "Equal" means identical values in // cells of equal index values for // all possible index values. if (rowTarget == null) { return(1); } if (this.noofLive == 0 && rowTarget.noofLive == 0) { return(0); } if (this.noofLive < rowTarget.noofLive) { return(-1); } if (this.noofLive > rowTarget.noofLive) { return(1); } for (int j = lo; j <= hi; j++) { if (cellsRow[j] == rowTarget.cellsRow[j]) { continue; } if (cellsRow[j] < rowTarget.cellsRow[j]) { return(-1); } if (cellsRow[j] > rowTarget.cellsRow[j]) { return(+1); } } return(0); }
internal void Clear() { // Clear this generation. for (int j = lo; j <= hi; j++) { Rows[j] = new LifeRow(); } countGeneration = 0; }
internal void CopyTo(LifeRow rowTarget) { // Check for null reference. if (rowTarget == null) { return; } // Copy the relevant info from row to row. this.cellsRow.CopyTo(rowTarget.cellsRow, 0); rowTarget.noofLive = this.noofLive; }
// Constructor. internal LifeGeneration() { // Set the convenience fields. lo = Rows.GetLowerBound(0); hi = Rows.GetUpperBound(0); middle = lo + ((hi - lo) / 2); // Create the rows. for (int j = lo; j <= hi; j++) { Rows[j] = new LifeRow(); } }
internal LifeRow CalcNextGen(LifeRow rowAbove, LifeRow rowBelow) { // Create an empty row. LifeRow rowNextGen = new LifeRow(); // If this row and the row above // and the row below are all // empty, then the next generation // will be an empty row. if (this.noofLive == 0 && rowAbove.noofLive == 0 && rowBelow.noofLive == 0) { return(rowNextGen); } // For each cell in the row: // (Leave the end cells blank.) int workSum; for (int j = lo + 1; j <= hi - 1; j++) { // Sum the number of adjacent live cells. workSum = +cellsRow[j - 1] + cellsRow[j + 1] + rowAbove.cellsRow[j - 1] + rowAbove.cellsRow[j] + rowAbove.cellsRow[j + 1] + rowBelow.cellsRow[j - 1] + rowBelow.cellsRow[j] + rowBelow.cellsRow[j + 1]; // Any cell with three live neighbors // will become/remain a live cell. // Any live cell with two live // neighbors will remain a live cell. rowNextGen.cellsRow[j] = (byte) ((workSum == 3 || (cellsRow[j] == 1 && workSum == 2)) ? 1 : 0); // Increment the live cell count, // as appropriate. rowNextGen.noofLive += rowNextGen.cellsRow[j]; } return(rowNextGen); }
// Draw the current row. internal void DrawRow( LifeRow rowCurr, LifeRow rowPrev, int ixRow, Graphics graphLifeGame) { // Calculate the range of rows to display. int displaySpan = LifeMain.noofDisplay; int displayLo = rowCurr.middle - ((displaySpan - 1) / 2); int displayHi = displayLo + (displaySpan - 1); // Drawing tools int xUnit = (int)(this.ClientRectangle.Width / displaySpan); int yUnit = (int)(this.ClientRectangle.Height / displaySpan); SolidBrush brshLive = new SolidBrush(Color.Black); SolidBrush brshDead = new SolidBrush(Color.Tan); // This routine attemps to optimize the // drawing of rows. Rows are drawn // using FillRect. The three primary // optimizations are: // 1. Do not erase the background. // 2. Draw contiguous cells of the same // state (color) in a single FillRect // call. // 3. Do not call FillRect if the rectangle // specified is already the correct // color. That is, if there is no // change in the range of cells since // the previous generation. int ixStart = displayLo // The left cell of the rect. , ixEnd = displayHi // The right cell of the rect. , j = displayLo; // The current cell. byte byteCurrent = rowCurr.cellsRow[displayLo]; // Force the last cell of a row to end a rectangle. byte cellTemp = rowCurr.cellsRow[displayHi]; rowCurr.cellsRow[displayHi] = 2; // Scan from the end of the previous rectangle until // a change in cell value occurs, indicating the // need for a new rectangle. for (j = displayLo; j <= displayHi; j++) { if (rowCurr.cellsRow[j] != byteCurrent) { // Note the end of the rectangle. ixEnd = j - 1; // Only call FillRect if nexessary. if (LifeMain.boolPaintAll || rowCurr.CompareTo(rowPrev, ixStart, ixEnd) != 0) { graphLifeGame.FillRectangle( byteCurrent == 1 ? brshLive : brshDead, (ixStart - displayLo) * xUnit, (ixRow - displayLo) * yUnit, ((ixEnd - ixStart) + 1) * xUnit, 1 * yUnit); } // Note the start of the next rectangle. ixStart = j; // Note the value of the new rectangle's // starting cell. byteCurrent = rowCurr.cellsRow[j]; } } // Restore the last cell to its origional value. rowCurr.cellsRow[displayHi] = cellTemp; }