Chris P, Andrew M, Yiming L, Daozhen L, Mitch W, Tyler M, Yifan Z, John K, Roy S, 
Ivy C M, Victor P M, Ingrid W, John G, Drake D, Duncan T, Sara C, Ke Z, Anthony K, 
Megan B, Longhua Z, Xinhui S, Abby S, Annette M, Domino B, Sam E, Rhys C, Kevin B,
Sergio P, Carson B, Shuanghao L, Joseph A, Timmy L, Aiyun X, Jack G, Caulin J and
Ryan Bradford

Time to approach the last two procedures for Stage Three. 

public class Point {
  int x, y; 
  public Point(int x, int y) {
    this.x = x;
    this.y = y;
  }
  public double distanceTo(Point other) {
    int dx = this.x - other.x;
    int dy = this.y - other.y; 
    return Math.sqrt( dx * dx + dy * dy ); 
  }
}

import java.awt.*; 
import java.util.*;

public class Circle {
  Point center;
  int radius;
  Color color; 
  int neighbors; // [1] 
  public Circle(Point center, int radius, Color color) {
    this.center = center;
    this.radius = radius;
    this.color = new Color((float) (Math.random()/2 + 0.5), 
                           (float) (Math.random()/2 + 0.5), 
                           (float) (Math.random()/2) + 0.5f); 
  }
  public void draw(Graphics g) {
    g.setColor(this.color); 
    g.fillOval(center.x - radius, center.y - radius, 2 * radius, 2 * radius); 
    g.setColor(Color.BLACK); 
    g.drawOval(center.x - radius, center.y - radius, 2 * radius, 2 * radius); 
    g.drawString( "" + this.neighbors, center.x, center.y ); 
  }
  public boolean contains(Point point) {
    return this.center.distanceTo(point) < this.radius; 
  }
  public void move(int x, int y) {
    this.center = new Point(x, y);  
  }
  public int neighbors(ArrayList<Circle> circles) { // [1] 
    int count = 0; 
    for (Circle c : circles)
      if (c != this)
        if (c.overlaps(this)) 
          count += 1; 
    this.neighbors = count; 
    return count; 
  }
  public boolean overlaps(Circle other) { // [1] 
    return this.radius + other.radius > other.center.distanceTo(this.center);  
  }
}

import javax.swing.*; 
import java.util.*; 
import java.awt.*;
import java.awt.event.*;

public class Screen extends JComponent implements MouseMotionListener, 
                                                  MouseListener {
  ArrayList<Circle> circles = new ArrayList<Circle>(); 
  Circle current; // = null;
  public void purgeOne() { 
    ArrayList<Circle> result = new ArrayList<Circle>(); 
    for (Circle c : this.circles) 
      if (c.neighbors >= 3) {
      
    } else {
      result.add(c);  
    }
    this.circles = result; 
  }
  public void purgeTwo() { this.circles = null; }  
  public void keyPressed(KeyEvent e) {
    int code = e.getKeyCode();
    if (code == 49) {
      this.purgeOne(); 
    } else if (code == 50) {
      this.purgeTwo();       
    } 
    // System.out.println("Ouch.");  
    this.repaint(); 
  }
  public Screen() {
    for (int i = 0; i < 16; i++)
      this.circles.add(new Circle(new Point((int)(Math.random()*390) + 5, 
                                            (int)(Math.random()*390) + 5),
                                  (int)(Math.random() * 30 + 20),
                                  Color.WHITE));
    for (Circle c : circles) // [2] 
      c.neighbors(circles);  // [2] 
    this.addMouseMotionListener(this);
    this.addMouseListener(this);
  }
  public void paintComponent(Graphics g) {
    for (Circle c : this.circles)
      c.draw(g); 
  }
  public void mouseMoved(MouseEvent e) { }
  public void mouseDragged(MouseEvent e) { 
    if (this.current != null) {
      this.current.move(e.getX(), e.getY()); 
      for (Circle c : this.circles) // [2] 
        c.neighbors(circles);       // [2] 
      this.repaint(); 
    }
  }

  public void mouseEntered(MouseEvent e) { }
  public void mouseExited(MouseEvent e) { }
  public void mousePressed(MouseEvent e) { 
    for (Circle c : this.circles) {
      if (c.contains(new Point(e.getX(), e.getY()))) {
         this.current = c;
         // break;
      }
    }
    if (this.current != null) {
      this.circles.remove( this.current ); 
      this.circles.add( this.current ); 
    }
  }
  public void mouseReleased(MouseEvent e) { // [0] 
    this.current = null; 
  }
  public void mouseClicked(MouseEvent e) { }
}

import javax.swing.*; 
import java.awt.event.*;

public class Testing extends JFrame implements KeyListener // [3] 
{
  Screen screen; // [3] 
  public Testing() {
    this.setSize(400, 400);
    this.setVisible(true); 
    this.screen = new Screen(); // [3] 
    this.addKeyListener(this); // [3]
  }
  public void keyPressed(KeyEvent e) { // [3] 
    this.screen.keyPressed(e); 
  }
  public void keyReleased(KeyEvent e) { }
  public void keyTyped(KeyEvent e) { }
  public static void main(String[] args) {
    Testing a = new Testing();  
    a.add(a.screen); // [3]  
  }
}

This takes care of the first purge. 

public class Point {
  int x, y; 
  public Point(int x, int y) {
    this.x = x;
    this.y = y;
  }
  public double distanceTo(Point other) {
    int dx = this.x - other.x;
    int dy = this.y - other.y; 
    return Math.sqrt( dx * dx + dy * dy ); 
  }
}

This class not changed. 

import java.awt.*; 
import java.util.*;

public class Circle {
  boolean safe; // false 
  Point center;
  int radius;
  Color color; 
  int neighbors; // [1] 
  public Circle(Point center, int radius, Color color) {
    this.center = center;
    this.radius = radius;
    this.color = new Color((float) (Math.random()/2 + 0.5), 
                           (float) (Math.random()/2 + 0.5), 
                           (float) (Math.random()/2) + 0.5f); 
  }
  public void draw(Graphics g) {
    g.setColor(this.color); 
    g.fillOval(center.x - radius, center.y - radius, 2 * radius, 2 * radius); 
    g.setColor(Color.BLACK); 
    g.drawOval(center.x - radius, center.y - radius, 2 * radius, 2 * radius); 
    g.drawString( "" + this.neighbors, center.x, center.y ); 
  }
  public boolean contains(Point point) {
    return this.center.distanceTo(point) < this.radius; 
  }
  public void move(int x, int y) {
    this.center = new Point(x, y);  
  }
  public int neighbors(ArrayList<Circle> circles) { // [1] 
    int count = 0; 
    for (Circle c : circles)
      if (c != this)
        if (c.overlaps(this)) 
          count += 1; 
    this.neighbors = count; 
    return count; 
  }
  public boolean overlaps(Circle other) { // [1] 
    return this.radius + other.radius > other.center.distanceTo(this.center);  
  }
}

This one changed minimally.

import javax.swing.*; 
import java.util.*; 
import java.awt.*;
import java.awt.event.*;

public class Screen extends JComponent implements MouseMotionListener, 
                                                  MouseListener {
  ArrayList<Circle> circles = new ArrayList<Circle>(); 
  Circle current; // = null;
  public void purgeOne() { 
    ArrayList<Circle> result = new ArrayList<Circle>(); 
    for (Circle c : this.circles) 
      if (c.neighbors >= 3) {
      
    } else {
      result.add(c);  
    }
    this.circles = result; 
  }
  public void purgeTwo() { 
    ArrayList<Circle> result = new ArrayList<Circle>(); 
    this.labelCircles(); 
    for (Circle c : this.circles)
      if (c.safe)
        result.add(c); 
    this.circles = result; 
  }  
  public void labelCircles() {
    for (Circle c : this.circles)
      c.safe = false; 
    // now we can start
    for (Circle c : this.circles) 
      if (c.center.y < c.radius) // directly connected to the ceiling 
        c.safe = true;
    for (int i = 0; i < this.circles.size(); i++) // no more than n steps are necessary
      for (Circle tori : this.circles)
        for (Circle molly : this.circles)
          if (tori.overlaps(molly))
            if (tori.safe || molly.safe) {
              molly.safe = true; 
              tori.safe = true; 
            }
  }
  public void keyPressed(KeyEvent e) {
    int code = e.getKeyCode();
    if (code == 49) {
      this.purgeOne(); 
    } else if (code == 50) {
      this.purgeTwo();       
    } 
    // System.out.println("Ouch.");  
    this.repaint(); 
  }
  public Screen() {
    for (int i = 0; i < 16; i++)
      this.circles.add(new Circle(new Point((int)(Math.random()*390) + 5, 
                                            (int)(Math.random()*390) + 5),
                                  (int)(Math.random() * 30 + 20),
                                  Color.WHITE));
    for (Circle c : circles) // [2] 
      c.neighbors(circles);  // [2] 
    this.addMouseMotionListener(this);
    this.addMouseListener(this);
  }
  public void paintComponent(Graphics g) {
    for (Circle c : this.circles)
      c.draw(g); 
  }
  public void mouseMoved(MouseEvent e) { }
  public void mouseDragged(MouseEvent e) { 
    if (this.current != null) {
      this.current.move(e.getX(), e.getY()); 
      for (Circle c : this.circles) // [2] 
        c.neighbors(circles);       // [2] 
      this.repaint(); 
    }
  }

  public void mouseEntered(MouseEvent e) { }
  public void mouseExited(MouseEvent e) { }
  public void mousePressed(MouseEvent e) { 
    for (Circle c : this.circles) {
      if (c.contains(new Point(e.getX(), e.getY()))) {
         this.current = c;
         // break;
      }
    }
    if (this.current != null) {
      this.circles.remove( this.current ); 
      this.circles.add( this.current ); 
    }
  }
  public void mouseReleased(MouseEvent e) { // [0] 
    this.current = null; 
  }
  public void mouseClicked(MouseEvent e) { }
}

This one contains the new purge and labeling functions

import javax.swing.*; 
import java.awt.event.*;

public class Testing extends JFrame implements KeyListener // [3] 
{
  Screen screen; // [3] 
  public Testing() {
    this.setSize(400, 400);
    this.setVisible(true); 
    this.screen = new Screen(); // [3] 
    this.addKeyListener(this); // [3]
  }
  public void keyPressed(KeyEvent e) { // [3] 
    this.screen.keyPressed(e); 
  }
  public void keyReleased(KeyEvent e) { }
  public void keyTyped(KeyEvent e) { }
  public static void main(String[] args) {
    Testing a = new Testing();  
    a.add(a.screen); // [3]  
  }
}

This last one did not change. 

--