/* --- CSU213 Fall 2006 Lecture Notes --------- Copyright 2006 Viera K. Proulx Lecture 12: October 2, 2006 Part 2: Designing Derived Classes */ import draw.*; import colors.*; import geometry.*; import java.util.Random; /* We realize that if we had designed our own Posn class, we would have delegated to a wish list the methods that produce a Posn at a new location when the Star moves. If we are using a library class, we can design a subclass (derived class) that extends the original library class, and also defines the methods on our wish list. Here we show the new class, CartPt, that defines two new methods used to simulate the Stars --- either just falling down, or flickering. Notice that the tests are the same --- other than the class name for the data that represents the location of the Stars. */ /* +------------------------+ | LoStars |<------------------+ +------------------------+ | +------------------------+ | | LoStars move() | | | boolean draw(Canvas x) | | +------------------------+ | | | / \ | --- | | | ------------------------------- | | | | +------------------------+ +------------------------+ | | MTLoStars | | ConsLoStars | | +------------------------+ +------------------------+ | +------------------------+ +-| Star first | | | LoStars moveFixed() | | | LoStars rest |-+ | | LoStars move() | | +------------------------+ | | | boolean draw(Canvas x) | | | LoStars moveFixed() | | | +------------------------+ | | LoStars move() | | | | | boolean draw(Canvas x) | | | | +------------------------+ | | | +--+ v +------------------------+ +-------+ | Star | | Posn | +------------------------+ +-------+ +-| CartPt loc | | int x | | | int lifespan | | int y | | +------------------------+ +-------+ | | Star moveFixed() | +-------+ | | Star move() | | | | boolean draw(Canvas c) | / \ | +------------------------+ --- v | +------------------------------------------------------------------+ | CartPt | +------------------------------------------------------------------+ +------------------------------------------------------------------+ | CartPt translate(int dx, int dy) | | CartPt translateRandom(int lowX, int highX, int lowY, int highY) | | int randomRange(int low, int high) | +------------------------------------------------------------------+ */ //------------------------------------------------------------------------- //------------------------------------------------------------------------- // to represent a cartesian point class CartPt extends Posn { CartPt(int x, int y) { super(x, y); } // produce this point translated by the given dx and dy CartPt translate(int dx, int dy){ return new CartPt(this.x + dx, this.y + dy); } // produce this point translated by the random distance in each coordinate CartPt translateRandom(int lowX, int highX, int lowY, int highY){ return this.translate(this.randomRange(lowX, highX), this.randomRange(lowY, highY)); } // produce a random distance to move left or right int randomRange(int low, int high){ return low + new Random().nextInt() % (high - low); } } //------------------------------------------------------------------------- //------------------------------------------------------------------------- // to represent a shooting star class Star { CartPt loc; int lifespan; Star(CartPt loc, int lifespan) { this.loc = loc; this.lifespan = lifespan; } // move this star down 3 pixels if alive, 4 pixels if burned Star moveFixed(){ if (lifespan > 0) return new Star(this.loc.translate(0, 3), this.lifespan - 1); else return new Star(this.loc.translate(0, 4), this.lifespan); } // move this star down, flickering if alive Star move(){ if (lifespan > 0) return new Star(this.loc.translateRandom(-2, 2, 0, 3), this.lifespan - 1); else return new Star(this.loc.translate(0, 4), this.lifespan); } // draw this star on the given canvas boolean draw(Canvas c){ if (this.lifespan > 0) return c.drawDisk(this.loc, 4, new White()); else return c.drawDisk(this.loc, 3, new Black()); } } //------------------------------------------------------------------------- //------------------------------------------------------------------------- // to represent shooting stars in our world interface LoStars { // move the stars in this list down a fixed distance LoStars moveFixed(); // move the stars in this list down LoStars move(); // draw the stars in this list boolean draw(Canvas x); } //------------------------------------------------------------------------- //------------------------------------------------------------------------- // to represent an empty list of stars class MTLoStars implements LoStars { MTLoStars() { } // move the stars in this list down a fixed distance LoStars moveFixed() { return this; } // move the stars in this list down LoStars move() { return this; } // draw the stars in this list boolean draw(Canvas x) { return true; } } //------------------------------------------------------------------------- //------------------------------------------------------------------------- // to represent a nonempty list of stars class ConsLoStars implements LoStars { Star first; LoStars rest; ConsLoStars(Star first, LoStars rest) { this.first = first; this.rest = rest; } /* // TEMPLATE: LoStars move() { ... this.first ... -- CartPt ... this.first.moveFixed(int, int) ... -- CartPt ... this.first.move(int, int) ... -- CartPt ... this.first.draw(Canvas) ... -- boolean ... this.rest.move(...) ... -- LoStars ... this.rest.draw(...) ... -- boolean } */ // move the stars in this list down a fixed distance LoStars moveFixed() { return new ConsLoStars(this.first.moveFixed(), this.rest.moveFixed()); } // move the stars in this list down LoStars move() { return new ConsLoStars(this.first.move(), this.rest.move()); } // draw the stars in this list boolean draw(Canvas c) { return this.first.draw(c) && this.rest.draw(c); } } //------------------------------------------------------------------------- //------------------------------------------------------------------------- // the world of shooting stars class StarWorld extends World{ LoStars stars; StarWorld(LoStars stars){ this.stars = stars; } World onTick(){ return new StarWorld(this.stars.move()); } World onKeyEvent(String ke){ return this; } boolean draw(){ return theCanvas.drawRect(new Posn(0, 0), 200, 300, new Blue()) && this.stars.draw(this.theCanvas); } boolean erase(){ return theCanvas.drawRect(new Posn(0, 0), 200, 300, new Blue()); } } //------------------------------------------------------------------------- //------------------------------------------------------------------------- class Examples{ Examples() {} Star s1 = new Star(new CartPt(30, 0), 30); Star s2 = new Star(new CartPt(40, 10), 20); Star s3 = new Star(new CartPt(70, 20), 40); Star s4 = new Star(new CartPt(50, 60), 20); Star s5 = new Star(new CartPt(80, 30), 40); Star s6 = new Star(new CartPt(20, 20), 50); Star s7 = new Star(new CartPt(40, 40), 50); Star s8 = new Star(new CartPt(70, 30), 30); Star s9 = new Star(new CartPt(10, 40), 10); Star s10 = new Star(new CartPt(60, 40), 20); Star burned = new Star(new CartPt(60, 40), 0); LoStars mtstars = new MTLoStars(); LoStars stars = new ConsLoStars(this.s1, new ConsLoStars(this.s2, new ConsLoStars(this.s3, new ConsLoStars(this.s4, new ConsLoStars(this.s5, new ConsLoStars(this.s6, new ConsLoStars(this.s7, new ConsLoStars(this.s8, new ConsLoStars(this.s9, new ConsLoStars(this.s10, this.mtstars)))))))))); LoStars starsx = new ConsLoStars(this.s1, new ConsLoStars(this.burned, new ConsLoStars(this.s3, this.mtstars))); CartPt pt = new CartPt(100, 200); // test the method translate in the class CartPt boolean testTranslate = (check this.pt.translate(5, -4) expect new CartPt(105, 196)); // test the method move in the class Star boolean testMoveFixedStar = (check this.s1.moveFixed() expect new Star(new CartPt(30, 3), 29)) && (check this.burned.moveFixed() expect new Star(new CartPt(60, 44), 0)); // test the method move in the class LoStars boolean testMoveFixedLoStars = (check this.mtstars.moveFixed() expect this.mtstars) && (check this.starsx.moveFixed() expect new ConsLoStars(new Star(new CartPt(30, 3), 29), new ConsLoStars(new Star(new CartPt(60, 44), 0), new ConsLoStars(new Star(new CartPt(70, 23), 39), this.mtstars)))); StarWorld sw = new StarWorld(this.stars); boolean go = sw.bigBang(200, 300, 0.1); }