Example #1
0
// take a step in the simulation
// Move all of the critters and handle collisions.
void CritterModel::step() {
    moveCount++;

    std::cout << "\n Beginning simulation move #" << moveCount << std::endl;

    // it's not quite fair to the critters in the lower right section
    // of the map, but it's easy to track the progress, iterate
    // through the map moving each critter
    for(unsigned int x = 0; x < width; x++) {
	for(unsigned int y = 0; y < height; y++) {
	    Critter *currCritter = grid[x][y];

	    // if there's no critter here, move on
	    if(currCritter == NULL ||
	       currCritter->hasGone()) {
		continue;
	    }

	    //update the critter about some state of it's world that
	    //it may care about:
	    currCritter->setAlive(true);
	    currCritter->setX(x);
	    currCritter->setY(y);
	    currCritter->setWidth(width);
	    currCritter->setHeight(height);
	    
	    Critter *neighbor = discoverNeighbor(NORTH, x, y, NULL, NULL);
	    currCritter->setNeighbor(NORTH, neighbor == NULL ? EMPTY_NEIGHBOR : neighbor->getChar());
	    neighbor = discoverNeighbor(SOUTH, x, y, NULL, NULL);
	    currCritter->setNeighbor(SOUTH, neighbor == NULL ? EMPTY_NEIGHBOR : neighbor->getChar());
	    neighbor = discoverNeighbor(EAST, x, y, NULL, NULL);
	    currCritter->setNeighbor(EAST, neighbor == NULL ? EMPTY_NEIGHBOR : neighbor->getChar());
	    neighbor = discoverNeighbor(WEST, x, y, NULL, NULL);
	    currCritter->setNeighbor(WEST, neighbor == NULL ? EMPTY_NEIGHBOR : neighbor->getChar());

	    currCritter->beginTurn();

	    // move the critter!
	    grid[x][y] = NULL;
	    
	    Direction move = currCritter->getMove();
	    unsigned int newX, newY;
	    neighbor = discoverNeighbor(move, x, y, &newX, &newY);
	    if(neighbor == NULL) {
		grid[newX][newY] = currCritter;
		currCritter->setX(newX);
		currCritter->setY(newY);
	    } else if(currCritter->getChar() != neighbor->getChar()) {
		// two critters of different kinds, fight!

		// Note: we use the getChar method of your critters to
		// determine if your critters are "the same".  This
		// models the idea that the critter looks at the other
		// critter to determine whether it should fight.  Also
		// as a bonus, you could try to be sneaky about hiding
		// from your neighbors!

		currCritter->setX(newX);
		currCritter->setY(newY);
		
		if(DEBUG) {
		    std::cout << currCritter->getChar() << " versus " <<
			neighbor->getChar() << ": ";
		}

		Attack attack = currCritter->fight(neighbor->getChar());
		Attack defend = neighbor->fight(currCritter->getChar());

		Critter *winner;
		
		// do rock paper scissors here
		if(attack == defend) {
		    // coin flip for tie
		    winner = rand() % 2 == 0 ? currCritter : neighbor;
		} else {
		    switch(attack) {
		    case ROAR:
			// only a POUNCE defense wins (SCRATCH or FORFEIT will be a win)
			winner = defend == POUNCE ? neighbor : currCritter;
			break;
		    case POUNCE:
			// only a SCRATCH defense wins (ROAR or FORFEIT will be a win)
			winner = defend == SCRATCH ? neighbor : currCritter;
			break;
		    case SCRATCH:
			// only a ROAR defense loses (POUNCE or FORFEIT will be a win)
			winner = defend == ROAR ? neighbor : currCritter;
			break;
		    default: // FORFEIT
			// dead
			winner = neighbor;
			break;
		    }
		}

		Critter *loser = currCritter == winner ? neighbor : currCritter;

		if(DEBUG) {
		    std::cout << winner->getChar() << " wins!" << std::endl;
		}

		winner->win();
		loser->lose();

		loser->setAlive(false);
		delete loser;
		
		grid[newX][newY] = winner;
	    } else { // don't move onto your sibling!
		newX = x;
		newY = y;
		grid[newX][newY] = currCritter;
	    }

	    // make sure that currCritter isn't dead, and if not, mark it and
	    // let it know that its turn is over.
	    if(grid[newX][newY] == currCritter) {
		currCritter->setMark();
		currCritter->endTurn();
	    }
	}
    }

    for(unsigned int x = 0; x < width; x++) {
	for(unsigned int y = 0; y < height; y++) {
	    Critter *currCritter = grid[x][y];
	    
	    // if there's no critter here, move on
	    if(currCritter == NULL) {
		continue;
	    }

	    currCritter->clearMark();
	}
    }
}