import java.applet.*; 
import java.awt.*; 
import java.awt.image.*; 
import java.awt.event.*; 
import java.io.*; 
import java.net.*; 
import java.text.*; 
import java.util.*; 
import java.util.zip.*; 

public class microCells extends BApplet {
// microCells
// by ::grumo <http://www.grama.com.ve/before.htm>
// Single cells move randomly through the space. 
// Lines connects them. Some mouse interaction allowed.
// March 19, 2002

int num=24; // number of cells

MonoCell[] m = new MonoCell[num];
MonoCell queen = new MonoCell();

void setup()
{
  size(500,250);
  ellipseMode(CENTER_DIAMETER);
  background(20,20,20);

  // cells constructor
  for(int i=0; i<num; i++) {
    m[i] = new MonoCell(); 
  }
  // queen = new MonoCell (100, 100, 50, 2, 5, 1, 80, 200, 15);
}

void loop() {
  for(int i=0; i<num; i++) {
    m[i].Live();
    if ((i+1)<num) {
      stroke(60);
      line (m[i].posx,m[i].posy,m[i+1].posx,m[i+1].posy);
    }
    else {
      line (m[i].posx,m[i].posy,m[0].posx,m[0].posy);
    }
  }
  //queen.Live();
  
}

class MonoCell
{
  float direc;    // direction
  float posx;     // x position
  float posy;     // y position
  float d;        // direction
  float diameter; // diameter
  float shrink;   // shrink|stretch factor
  float step;     // length of step
  float dcell;    // current diameter
  float speed;    // speed
  float cellhue;  // fillcolor
  float borderhue;// bordercolor  
  float erraticness;  // factor of shrink/change of direction

  MonoCell () // default constructor 
  {
    direc=0;
    posx=100;
    posy=100;
    d=0;
    diameter=random(3,35);
    shrink=random(10);
    step=random(10);
    dcell=0;
    speed=random(0);
    cellhue= random(5,10)*15;
    borderhue = random(5,10)*10;
    erraticness= random(10,25);
  }
  
  MonoCell (float x, float y, float diam, float sh, float st, float sp, float chue, float border, float e) // constructor with parameters
  {
    direc=0;
    posx=x;
    posy=y;
    d=0;
    diameter=diam;
    shrink=sh;
    step=st;
    dcell=0;
    speed=sp;
    cellhue= chue;
    borderhue = border;
    erraticness= e;
  }

  void Live (){

    if (FeelsThatWay()) { // if feels so, change color and shrink or stretch cell..
      stroke (borderhue,borderhue,borderhue);
      fill(cellhue+200,160,120,75);
      dcell=diameter+shrink;
    }
    else { // else draw with normal color and size
      stroke (borderhue,borderhue,borderhue);
      fill(cellhue+50,160,120,75);
      dcell=diameter;
    }

    //if feels so, change direction
    if (FeelsThatWay()) {
      d=(int)(random(8));
    }

    // move
    if (d==0) {posx+=step;} // E
    else if (d==1) {posx-=step;} // W
    else if (d==2) {posy+=step;} // S
    else if (d==3) {posy-=step;} // N
    else if (d==4) {posx+=step;posy-=step;} // NE
    else if (d==5) {posx-=step;posy-=step;} // NW
    else if (d==6) {posy+=step;posx+=step;} // SE
    else if (d==7) {posy+=step;posx-=step;} // SW


    // if pressed, cells follow the mouse (searching for food?)
    if (mousePressed) {
    if (posx<mouseX) {posx+=step;} 
    else if (posx>mouseX) {posx-=step;} 
    else if (posy<mouseY) {posy-=step;} 
    else if (posy>mouseY) {posy+=step;}     
    }
    else {
    // if not, cells avoid the mouse pointer
     if (posx>=mouseX) {posx+=step/1.5f;} 
    else if (posx<=mouseX) {posx-=step/1.5f;} 
    else if (posy>=mouseY) {posy+=step/1.5f;} 
    else if (posy<=mouseY) {posy-=step/1.5f;} 
    }

    // constrain movements to the edge of screen
    if (posx<10) {posx=10;}
    if (posy<10) {posy=10;}
    if (posx>width-10) {posx=width-10;}
    if (posy>height-10) {posy=height-10;}

    //draw ellipse
    ellipse(posx, posy, dcell, dcell);
    // if diameter>25 pixels then put a nucleus
    if (diameter>20) {
      stroke (borderhue-50);
      ellipse(posx, posy, dcell-7,dcell-7);
    }

    // wait some -random- amount of milliseconds
    delay((int)(speed));
  }

  boolean FeelsThatWay() // returns true randomly using erractiness as parameter
  {
    if ((int)(random(erraticness))==5) {
      return true;
    }
    else return false;
  }

}

}