Back to July Calendar 

Previous Entry Next Entry→

July 31, 2005

 

Wow, that's it for July, huh?  It's been a hot month for weather and the consensus for global warming seems to be, "yeah, but who controls the weather?" 

 

The "Suggestion Box" that concludes BAJGP's chapter 2 suggests continuously varying width, height and shape (oval vs. rectangle) for the elements of Mondrian.  This led me to write the following variation on the code:

 

/**
* @(#)Mondrian5.java
* @version 1.00 05/07/31
*/


import java.applet.*;
import java.awt.*;
import java.util.Random;

public class Mondrian5 extends Applet implements Runnable {

  Thread animation;

  Graphics offscreen;
  Image image;

  static final int NUM_SHAPES = 9; // in ms
  static final int REFRESH_RATE = 100; // in ms

  static final byte RECT = 0; // direction of motion
  static final byte OVAL = 1;
  byte SHAPE_TYPE=0;

  MovingShape shape[];

  public void init() {
    System.out.println(">> init <<");
    setBackground(Color.black);
    initShapes();
    image = createImage(bounds().width,bounds().height);
    offscreen = image.getGraphics();
  }

  public void initShapes() {

    // allocate Moving shapes' memories and positions

    shape = new MovingShape[NUM_SHAPES];
    shape[0] = new MovingShape(0,0,90,90,RECT,Color.yellow);
    shape[1] = new BoogieShape(250,0,40,190,OVAL,Color.yellow);
    shape[2] = new WaltzShape(200,55,60,135,RECT,Color.yellow);
    shape[3] = new HurkyShape(80,200,220,90,OVAL,Color.blue);
    shape[4] = new WaltzShape(100,10,90,80,RECT,Color.blue);
    shape[5] = new BoogieShape(80,100,110,90,OVAL,Color.lightGray);
    shape[6] = new WaltzShape(200,0,45,45,RECT,Color.red);
    shape[7] = new HurkyShape(0,100,70,200,OVAL,Color.red);
    shape[8] = new BoogieShape(200,55,60,135,RECT,Color.magenta);

  }

  public void start() {

    System.out.println(">> start <<");
    animation = new Thread(this);
    if (animation != null) {
       animation.start();
    }
  }

  // update each rectangle's position.
  // DYNAMIC METHOD BINDING OCCURS HERE!

  public void updateShapes() {
    for (int i=0; i<NUM_SHAPES; i++) {
      shape[i].Movement(); // each rectangles Movement
    }
  }

  // override update so it doesn't erase screen
  public void update(Graphics g) {
    paint(g);
  }

  public void paint(Graphics g) {
    offscreen.setColor(Color.black);
    offscreen.fillRect(0,0,300,300); // clear buffer
    for (int i=0; i<NUM_SHAPES; i++) {
      shape[i].paint(offscreen); // paint each rectangle
    }
    g.drawImage(image,0,0,this);
  }
  public void run() {
    while (true) {
      repaint();
      updateShapes();
      try {
        Thread.sleep (REFRESH_RATE);
      } catch (Exception exc) { };
    }
  }
  public void stop() {
    System.out.println(">> stop <<");
    if (animation != null) {
      animation.stop();
      animation = null;
    }
  }
}

/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////


class MovingShape {
  int ulCornx, ulCorny; // (ulCornx,ulCornyy) are coordinates of upper
  // left corner of the shape
  int width, height; // width and height of shape
  Color shapeColor; // color of shape
  byte ShapeType;
  ////constructor///////////////////////////////////////////////////
  public MovingShape(int x,int y,int w,int h,byte s,Color c) {
    ulCornx = x;
    ulCorny = y;
    width = w;
    height = h;
    shapeColor = c;
    ShapeType = s;
  }

  public void Movement() {
    // does nothing except provide a placeholder for dynamic binding
  }

  public void paint(Graphics g) {
    g.setColor(shapeColor);
    if(ShapeType == 0)
      g.fillRect(ulCornx,ulCorny,width,height);
    else g.fillOval(ulCornx,ulCorny,width,height);
  }
}


/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
class BoogieShape extends MovingShape {
  // BoogieShape inherits all instance variables and
  // methods from MovingShape

  static final byte UP = 0; // direction of motion
  static final byte DOWN = 1;
  static final byte LEFT = 2;
  static final byte RIGHT = 3;

  byte state; // state of rectangle

  int max_x; // max x value
  int min_x; // min x value
  int max_y; // max y value
  int min_y; // min y value

  /////////////////////////////////////////////////////////////////
  public BoogieShape(int x,int y,int w,int h,byte s, Color c) {
    super(x,y,w,h,s,c); // call superclass constructor
    max_x = ulCornx + 13;
    min_x = ulCornx - 13;
    max_y = ulCorny + 13;
    min_y = ulCorny - 13;
  }

  // override Movement()
  public void Movement() {
    switch (state) {
      case DOWN:
        ulCorny += 2;
        if (ulCorny >= max_y) {
          state = UP;
        }
        width += 2;
        break;
      case UP:
        ulCorny -= 2;
        if (ulCorny <= min_y) {
          state = RIGHT;
        }
        width -= 2;
        break;
      case RIGHT:
        ulCornx += 2;
        if (ulCornx >= max_x) {
          state = LEFT;
        }
        height += 2;
        break;
      case LEFT:
        ulCornx -= 2;
        if (ulCornx <= min_x) {
          state = DOWN;
        }
        height -= 2;
        break;
     }
  }
}

/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// WaltzShape also inherits from MovingShape

class WaltzShape extends MovingShape {
  byte state;
  static final byte SE = 0; // going southeast
  static final byte NE = 1; // going northeast
  static final byte W = 2; // going west

  int bottom_x; // the x coordinate of
                // bottom pt of the waltz

  int right_x;  // the x coordinate of
                // right pt of the waltz

  int left_x;   // the x coordinate of
                // left pt of the waltz


  /////////////////////////////////////////////////////////////////

  public WaltzShape(int x,int y,int w,int h,byte s, Color c) {
    super(x,y,w,h,s,c); // call superclass constructor
    bottom_x = ulCornx + 17;
    right_x = bottom_x + 17;
    left_x = ulCornx;
  }


  // override Movement()
  public void Movement() {
    switch (state) {
      case SE:
        ulCornx++;
        ulCorny++;
        if (ulCornx == bottom_x) {
          state = NE;
        }
        break;
      case NE:
        ulCornx++;
        ulCorny--;
        if (ulCornx == right_x) {
          state = W;
        }
        break;
      case W:
        ulCornx-- ;
        if (ulCornx == left_x) {
          state = SE;
        }
        break;
    }
  }
}

/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////

class HurkyShape extends MovingShape {
  Random r1 = new Random();
  // HurkyRect inherits all instance variables and
  // methods from MovingRect

  static final byte UP = 0; // direction of motion
  static final byte DOWN = 1;
  static final byte LEFT = 2;
  static final byte RIGHT = 3;

  byte state; // state of rectangle

  int max_x; // max x value
  int min_x; // min x value
  int max_y; // max y value
  int min_y; // min y value

  /////////////////////////////////////////////////////////////////
  public HurkyShape(int x,int y,int w,int h,byte s, Color c) {
    super(x,y,w,h,s,c); // call superclass constructor
    max_x = ulCornx + 18;
    min_x = ulCornx - 12;
    max_y = ulCorny + 18;
    min_y = ulCorny - 13;
  }

  // override Movement()
  public void Movement() {
    int i = r1.nextInt()%4;
    int j = r1.nextInt()%4;
    switch (state) {
    case DOWN:
      ulCorny += i;
      if (ulCorny >= max_y) {
        state = UP;
      }
      break;
    case UP:
      ulCorny -= i;
      if (ulCorny <= min_y) {
        state = RIGHT;
      }
      break;
    case RIGHT:
      ulCornx += j;
      if (ulCornx >= max_x) {
        state = LEFT;
      }
      break;
    case LEFT:
      ulCornx -= j;
      if (ulCornx <= min_x) {
        state = DOWN;
      }
      break;
  }
}
}