This is LifeView.m in view mode; [Download] [Up]
/*
* LifeView. Displays a Life Universe. Knows how too display a population.
* Also can compute the next generation.
*
* Copyright (c) 1993 Gil Rivlis
*/
#import "LifeView.h"
@implementation LifeView
+ initialize
{
static NXDefaultsVector LifeDefaults = { //Default Defaults...
{"UniverseHeight", "120"},
{"UniverseWidth", "120"},
{"Mail", "Warn"},
{"LifeSymbol", "0"},
{ NULL, NULL }
};
NXRegisterDefaults("LifeByGR",LifeDefaults);
return self;
}
- initFrame:(NXRect *)frameRect
{
int i;
zoomSize = 1.5; /* init zoom Size */
if(population) free(population);
universe.height = atoi(NXGetDefaultValue("LifeByGR","UniverseHeight"));
universe.width = atoi(NXGetDefaultValue("LifeByGR","UniverseWidth"));
population = malloc(sizeof(char)*universe.height*universe.width);
for (i = 0; i<universe.width*universe.height; i++) {
population[i] = 0;
}
/* set the life form symbol. */
theLifeChar = 'a' + atoi(NXGetDefaultValue("LifeByGR","LifeSymbol"));
[super initFrame:frameRect];
[self sizeTo:(float)(FONT_SIZE*universe.width)
:(float)(FONT_SIZE*universe.height) ];
[self setDrawSize:(float)universe.width :(float)universe.height];
[self setDrawOrigin:-0.5 :-0.5];
[self setOpaque:YES];
return [self display];
}
/* we need this method when we zoom, or change shape... */
- resetFrame
{
NXRect obounds = bounds;
[self convertRectToSuperview:&obounds];
[self sizeTo:(float)(zoomSize*universe.width*FONT_SIZE)
:(float)(zoomSize*universe.height*FONT_SIZE)];
[self setDrawSize:(float)universe.width :(float)universe.height];
[self setDrawOrigin:-0.5 :-0.5];
[self convertRectFromSuperview:&obounds];
return [self display];
}
/* doesn't work and not used..., yet */
- setScrollersTo:(float)aFloat
{
id theScrollview = [[self superview] superview];
[ [ theScrollview horizScroller] setFloatValue:aFloat ];
[ [ theScrollview vertScroller] setFloatValue:aFloat ];
return self;
}
- showGrid:sender
{
if(!gridOn) {
gridOn = YES;
[gridButton setTitle:"Hide Grid"];
}
else {
gridOn = NO;
[gridButton setTitle:"Show Grid"];
}
return [self display];
}
/* the drawing method. Note the fancy zyshow! */
- drawSelf:(const NXRect *)rects :(int)rectCount
{
float oldX = 0.0, oldY = 0.0; /* Hold the last full one */
float *xyPositions; /* pairs of positions... */
char *charString; /* put enough 'special' chars */
float firstX = 0.0, firstY = 0.0; /* hold the first for xyshow */
int i, j;
PSWDefineFont("LifeFont",1.0); /* Get the special font */
PSsetgray(NX_WHITE);
NXRectFill(&bounds); /* for the white background */
/* draw the Grid, if gridOn */
if (gridOn) {
float tmp = -0.5;
float shftHeight = (float)universe.height - 0.5;
float shftWidth = (float)universe.width - 0.5;
PSWDefs();
while(tmp < shftWidth) {
PSWMakeLineBind(tmp,-0.5,tmp,shftHeight);
tmp += 1.0;
}
tmp = -0.5;
while(tmp < shftHeight) {
PSWMakeLineBind(-0.5,tmp,shftWidth,tmp);
tmp += 1.0;
}
PSWStrokeLineBind(0.15,NX_LTGRAY);
}
/* Allocate the correct memory size */
xyPositions = calloc( 2*popSize - 1, sizeof(float) );
charString = calloc( popSize + 1, sizeof(char) );
/* Fill in the character */
for(j=0; j< popSize; j++) {
charString[j] = theLifeChar;
}
charString[popSize] = 0;
/* skip begining of population array */
i=0;
while( (population[i++] == 0) && (i<universe.width*universe.height) );
j = i - 1;
if(population[j]==10) {
firstX = (float)(j % universe.width) - oldX;
firstY = (float)(j / universe.width) - oldY;
oldY = (float)( j / universe.width );
oldX = (float)( j % universe.width );
}
/* continue the array. Now we need relative distances */
j = 0;
for(; i < universe.width*universe.height; i++) {
if(population[i] == 10) {
xyPositions[2*j] = (float)( i % universe.width ) - oldX;
xyPositions[2*j + 1] = (float)( i / universe.width ) - oldY;
oldY = (float)( i / universe.width );
oldX = (float)( i % universe.width );
j++;
}
}
/* debugging printf...
printf("drawSelf::\n");
printf("popSize = %d\n",popSize);
printf("charStrings = %s\n",charString);
for(j=universe.height-1;j>=0;j--) {
for(i=0;i<universe.width;i++) {
printf("%3d",population[j*universe.width+i]);
}
printf("\n");
}
printf("\n");
*/
/* Now we draw, at last */
PSsetgray(NX_BLACK);
PSWXYShow( firstX, firstY, charString, xyPositions, 2*popSize);
[popSizeField setIntValue:popSize];
/* free old stuff */
cfree(xyPositions);
cfree(charString);
return self;
}
/* display this population (gets called by generators...) */
- showPopulation:(char *)aPopulation
ofSize:(int)aSize
andUniverse:(IntNXSize)aUniverse
{
int i;
if(population) {
free(population);
}
universe.width = aUniverse.width;
universe.height = aUniverse.height;
population = malloc(sizeof(char)*universe.width*universe.height);
for(i=0; i< universe.width*universe.height; i++) {
population[i] = aPopulation[i];
}
popSize = aSize;
return [self resetFrame];
}
/* save as above with current universe */
- showPopulation:(char *)aPopulation ofSize:(int)aSize
{
[self showPopulation:aPopulation ofSize:aSize andUniverse:universe];
return self;
}
/* this get the population from LiveView. Note that only LifeView keeps the
* uptodate population. This gets called by save methods...
*/
- takePopulation:(char **)aPopulation andSize:(int *)aSize
{
*aPopulation = population;
*aSize = popSize;
return self;
}
/* access to variables */
- (IntNXSize)universe
{
return universe;
}
- (int)popSize
{
return popSize;
}
/* set new size */
- setUniverse:(IntNXSize)aUniverse
{
universe.width = aUniverse.width;
universe.height = aUniverse.height;
[self sizeTo:(float)(FONT_SIZE*universe.width)
:(float)(FONT_SIZE*universe.height) ];
[self setDrawSize:(float)universe.width :(float)universe.height];
[self setDrawOrigin:-0.5 :-0.5];
return self;
}
- setLifeCharTo:(char)aChar;
{
theLifeChar = aChar;
return self;
}
- (char)lifeChar
{
return theLifeChar;
}
- setZoom:(float)aSize
{
zoomSize = aSize;
return [self resetFrame];
}
- takeFloatSize:sender
{
[self setZoom:[sender floatValue] ];
return self;
}
/* draws a new cell, or deletes old cell. this should get highly modified */
- mouseDown:(NXEvent *)theEvent
{
int tmp;
NXPoint center = theEvent->location; /* get mouse location */
[self convertPoint:¢er fromView:nil]; /* convert to view coords */
tmp = ((int)(center.y+0.5)) * universe.height + ((int) (center.x+0.5));
if(population[tmp] == 10) {
population[tmp] = 0;
popSize--;
}
else {
population[tmp] = 10;
popSize++;
}
return [self display];
}
/* calculate new population. This algorithm was lifted from another Life
* program by Peter ?, peter_oleski@hh.maus.de.
*/
- (void)calculate:(char *)aPopulation
{
register int i,j;
int newPopSize=0;
register char *rp = aPopulation+universe.width+1,*ws;
for(j=1; j< universe.height-1; j++) {
for(i=1; i< universe.width-1; i++) {
if(*rp > 9) {
ws=rp-universe.width-1;
*ws+=1; ws++;
*ws+=1; ws++;
*ws+=1; ws+=universe.width-2;
*ws+=1; ws+=2;
*ws+=1; ws+=universe.width-2;
*ws+=1; ws++;
*ws+=1; ws++;
*ws+=1;
}
rp++;
}
rp+=2;
}
rp = aPopulation;
for(i=0; i<universe.width*universe.height; i++) {
if(*rp) {
if((*rp==12) || (*rp==13) || (*rp==3)) {
*rp=10;
newPopSize++;
}
else {
*rp=0;
}
}
rp++;
}
popSize = newPopSize;
}
- calculate
{
[self calculate:population];
return self;
}
- free
{
free(population);
[super free];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.