// 2D percolating cluster,  Evgeny Demidov  22 Oct 2001
import java.awt.*;
import java.awt.event.*;
public class Cluster extends java.applet.Applet
 implements MouseListener, ItemListener, KeyListener{
  int L = 25,L1,L2, d, w, hd, hBut = 30,
    cl[], nb[], maxCl;
  double p = .5;
  Image buffImage;     Graphics buffGraphics;
  boolean painted = false;
  Choice chL;    Label  lbL, lbP;    TextField tfP;
  long generTime;

public void init() {
  w = getSize().width;
  cl = new int[(w+1)*(w+2)];  nb = new int [w*w];
  String s=getParameter("L");
  if (s != null) L = Integer.parseInt(s);
  d = w/L;  hd = w-d; L1 = L+1; L2 = L+2;
  maxCl = L1*L2;
  s=getParameter("p");
  if (s != null) p = Double.valueOf(s).doubleValue();
  buffImage = createImage(w, w);   buffGraphics = buffImage.getGraphics();
  addMouseListener(this);
  chL = new Choice();
  if (w == 400)
   for (int i = 0, l = 25; i < 5; i++){
    chL.addItem(Integer.toString(l));  l *= 2;}
  else
   for (int i = 0, l = 20; i < 6; i++){
    chL.addItem(Integer.toString(l));  l *= 2;};
  chL.select(""+L);
  chL.addItemListener(this);
  lbL = new Label("L");  add(lbL);  add(chL);
  lbP = new Label("p");  add(lbP);
  tfP = new TextField( "" + (float)p, 5);  add(tfP);
  tfP.addKeyListener(this);
}
public void destroy() {
  removeMouseListener(this);
}
public void mouseClicked(MouseEvent e){}       // event handling
public void mousePressed(MouseEvent e) {
  painted = false;
  repaint();
  e.consume();
}
public void mouseReleased(MouseEvent e){}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e)  {}
public void keyTyped(KeyEvent e){}
public void keyPressed(KeyEvent e){}
public void keyReleased(KeyEvent e){
  final int keyEnter = 10;
  if (e.getKeyCode() == keyEnter){
    try{ p = Double.valueOf(tfP.getText()).doubleValue();
    }catch(NumberFormatException ne){}
    painted = false;
    repaint();
  }
  e.consume();
}
public void itemStateChanged(ItemEvent e){
  L = Integer.parseInt(chL.getSelectedItem());
  d = w/L;  hd = w-d; L1 = L+1; L2 = L+2;
  maxCl = L1*L2;
  painted = false;
  repaint();
}

public void paint(Graphics g) {
 if ( !painted ){
  generTime = System.currentTimeMillis();
  showStatus( "growing cluster");
  buffGraphics.setColor(Color.white);
  buffGraphics.fillRect(0, 0, w, w);
  for (int i = L1; i < maxCl; i++) cl[i] = 0;
  for (int i = 0; i < L1; i++) cl[i] = cl[maxCl-1-i] = -1;
  for (int i = L1; i < maxCl; i += L1) cl[i] = -1;
  int i0 = L2*(L/2+1),  delNb[] = {1,-1,L1,-L1};
//System.out.println("=");
  cl[i0] = 1;
  for (int i = 0; i < 4; i++) nb[i] = i0 + delNb[i];
  int lastNb = 3;
  do{
   int lastCl = nb[lastNb--];
   if (cl[lastCl] == 0){
    if (Math.random() > p) cl[lastCl] = -1;
    else{
     cl[lastCl] = 1; 
     for (int i = 0; i < 4; i++){
      int k = lastCl+delNb[i];
      if (cl[k] == 0) nb[++lastNb] = k;}}}
  } while (lastNb >= 0);

  showStatus( "drawing");
  buffGraphics.setColor(Color.black);
  for (int i = 0; i < L; i++)
   for (int j = 0; j < L; j++)
    if ( cl[j+1+(i+1)*L1] > 0)
     buffGraphics.fillRect(j*d,hd-i*d, d,d);
  generTime = System.currentTimeMillis() - generTime;
  painted = true;}
 g.drawImage(buffImage, 0, hBut, this);
 showStatus( "p=" + (float)p + "  t=" + generTime + "ms");
}

public void update(Graphics g){ paint(g); }

}
