int cycle()
{
	/* find number of contacts/bonds*/
	int contacts = NUM_XY_BONDS + NUM_Z_BONDS;

	/* touching a wall counts as two contacts*/
	if (X == 0 || X == substrate_width)
	{
		contacts += 2;
	}
	if (Y == 0 || Y == substrate_width)
	{
		contacts += 2;
	}

	if (contacts <= get_max_num_bonds(calcium_level))
	{ 
		/* cell comes out of G0*/
		CYCLE++;
		CONTACT_INHIBITED_TICKS = 0;
	}
	else
	{
		/* cell enters G0*/
		CONTACT_INHIBITED_TICKS++;
	}
	
	/* check to see if enough time has elapsed as to whether cell can divide*/
	if (can_divide(TYPE,CYCLE))
	{
		add_ask_id_message(ID, 1000.0, X, Y, Z);
	}
	
	return 0;
}
예제 #2
0
/* all this is rather expensive :( */
static void tick( State *st )
{
  int new_num_cells, num_cells=0;
  int b, j;
  int x, y, w4=st->width/4, h4=st->height/4, offset;
  double min_dist;
  int min_index;
  int num_living = 0;
  const double check_dist = 0.75*st->move_dist;
  const double grow_dist = 0.75*st->radius;
  const double adult_radius = st->radius;
  
  /* find number of cells capable of division 
     and count living cells
  */
  for (b=0; b<st->num_cells; ++b) {
    if (st->cell[b].energy > 0) num_living++;
    if (can_divide( st, &st->cell[b] )) num_cells++;
  }
  new_num_cells = st->num_cells + num_cells;
  
  /* end of simulation ? */
  if (0 == num_living || new_num_cells >= st->max_cells) {
    if (st->pause_counter > 0) st->pause_counter--;
    if (st->pause_counter > 0) return;
    create_cells( st );
    st->pause_counter = st->pause;
  } else if (num_cells) { /* any fertile candidates ? */
    for (b=0, j=st->num_cells; b<st->num_cells; ++b) {
      if (can_divide( st, &st->cell[b] )) {
        st->cell[b].vx      = random_interval( -50, 50 ) * 0.01;
        st->cell[b].vy      = random_interval( -50, 50 ) * 0.01;
        st->cell[b].age     = random_max( 0x0f );
        /* half energy for both plus some bonus for forking */
        st->cell[b].energy  = 
            st->cell[b].energy/2 + random_max( 0x0f );
        /* forking makes me shrink */
        st->cell[b].growth  = 0.995;
        
        /* this one initially goes into the oposite direction */
        st->cell[j].vx       = -st->cell[b].vx;
        st->cell[j].vy       = -st->cell[b].vy;
        /* same center */
        st->cell[j].x        = st->cell[b].x;
        st->cell[j].y        = st->cell[b].y;
        st->cell[j].age      = random_max( 0x0f );
        st->cell[j].energy   = (st->cell[b].energy);
        st->cell[j].rotation =
            ((double)random()/(double)RAND_MAX)*360.0;
        st->cell[j].growth   = st->cell[b].growth;
        st->cell[j].radius   = st->cell[b].radius;
        ++j;
      } else {
        st->cell[b].vx = 0.0;
        st->cell[b].vy = 0.0;
      }
    }
    
    st->num_cells = new_num_cells;
  }

  /* for each find a direction to escape */
  if (st->num_cells > 1) {
    for (b=0; b<st->num_cells; ++b) {
      if (st->cell[b].energy > 0) {
        double vx;
        double vy;
        double len;
        
        /* grow or shrink */
        st->cell[b].radius *= st->cell[b].growth;
        /* find closest neighbour */
        min_dist = 100000.0;
        min_index = 0;
        for (j=0; j<st->num_cells; ++j) {
          if (j!=b) {
            const double dx = st->cell[b].x - st->cell[j].x;
            const double dy = st->cell[b].y - st->cell[j].y;
            
            if (fabs(dx) < check_dist || fabs(dy) < check_dist) {
              const double dist = dx*dx+dy*dy;
              /*const double dist = sqrt( dx*dx+dy*dy );*/
              if (dist<min_dist) {
                min_dist = dist;
                min_index = j;
              }
            }
          }
        }
        /* escape step is away from closest normalized with distance */
        vx = st->cell[b].x - st->cell[min_index].x;
        vy = st->cell[b].y - st->cell[min_index].y;
        len = sqrt( vx*vx + vy*vy );
        if (len > 0.0001) {
          st->cell[b].vx = vx/len;
          st->cell[b].vy = vy/len;
        }
        st->cell[b].min_dist = len;
        /* if not adult (radius too small) */
        if (st->cell[b].radius < adult_radius) {
          /* if too small 60% stop shrinking */
          if (st->cell[b].radius < adult_radius * 0.6) {
            st->cell[b].growth = 1.0;
          }
          /* at safe distance we start growing again */
          if (len > grow_dist) {
            if (st->cell[b].energy > 30) {
              st->cell[b].growth = 1.005;
            } 
          }
        } else {  /* else keep size */
          st->cell[b].growth = 1.0;
        }
      }
    }
  } else {
    st->cell[0].min_dist = 2*st->move_dist;
  }
    
  /* now move em, snack and burn energy */
  for (b=0; b<st->num_cells; ++b) {
    /* if still alive */
    if (st->cell[b].energy > 0) {
      /* agility depends on amount of energy */
      double fac = (double)st->cell[b].energy / 50.0;
      if (fac < 0.0) fac = 0.0;
      if (fac > 1.0) fac = 1.0;
      
      st->cell[b].x += fac*(2.0 - 
          (4.0*(double)random() / (double)RAND_MAX) + 
          st->cell[b].vx);
      st->cell[b].y += fac*(2.0 - 
          (4.0*(double)random() / (double)RAND_MAX) + 
          st->cell[b].vy);
      
      /* get older and burn energy */
      if (st->cell[b].energy > 0) {
        st->cell[b].age++;
        st->cell[b].energy--;
      }
      
      /* have a snack */
      x = ((int)st->cell[b].x)/4;
      if (x<0) x=0; if (x>=w4) x = w4-1;
      y = ((int)st->cell[b].y)/4;
      if (y<0) y=0; if (y>=h4) y = h4-1;
    
      offset = x+y*w4;
    
      /* don't eat if already satisfied */
      if (st->cell[b].energy < 100 &&
          st->food[offset] > 0) {
        st->food[offset]--;
        st->cell[b].energy++;
        /* if you are hungry, eat more */
        if (st->cell[b].energy < 50 && 
            st->food[offset] > 0) {
          st->food[offset]--;
          st->cell[b].energy++;
        }
      }
    }
  }
}