import java.util.Random; import tester.*; import draw.*; import geometry.*; import colors.*; /** * Copyright 2008 Viera K. Proulx * This program is distributed under the terms of the * GNU Lesser General Public License (LGPL) */ /** Class that represents a colored disk that moves around the Canvas */ class Blob{ Posn center; int radius; IColor col; /** The constructor */ Blob(Posn center, int radius, IColor col) { this.center = center; this.radius = radius; this.col = col; } /** draw this blob in the given World */ boolean draw(Canvas c) { return c.drawDisk(this.center, this.radius, col); } /** move this blob 20 pixels in the direction given by the ke or change its color to Green, Red or Yellow */ Blob moveBlob(String ke){ if (ke.equals("right")){ return new Blob(new Posn(this.center.x + 5, this.center.y), this.radius, this.col); } else {if (ke.equals("left")){ return new Blob(new Posn(this.center.x - 5, this.center.y), this.radius, this.col); } else {if (ke.equals("up")){ return new Blob(new Posn(this.center.x, this.center.y - 5), this.radius, this.col); } else {if (ke.equals("down")){ return new Blob(new Posn(this.center.x, this.center.y + 5), this.radius, this.col); } // change the color to Y, G, R else {if (ke.equals("Y")){ return new Blob(this.center, this.radius, new Yellow()); } else {if (ke.equals("G")){ return new Blob(this.center, this.radius, new Green()); } else {if (ke.equals("R")){ return new Blob(this.center, this.radius, new Red()); } else { return this; }}}}}}} } /** produce a new blob moved by a random distance < n pixels */ Blob randomMove(int n){ return new Blob(new Posn(this.center.x + this.randomInt(n), this.center.y + this.randomInt(n)), this.radius, this.col); } /** helper method to generate a random number in the range -n to n */ int randomInt(int n){ return -n + (new Random().nextInt(2 * n + 1)); } /** is the blob outside the bounds given by the width and height */ boolean outsideBounds(int width, int height) { return this.center.x < 0 || this.center.x > width || this.center.y < 0 || this.center.y > height; } /** is the blob near the center of area given by the width and height */ boolean nearCenter(int width, int height) { return this.center.x > width / 2 - 10 && this.center.x < width / 2 + 10 && this.center.y > height / 2 - 10 && this.center.y < height / 2 + 10; } } /** Represent the world of a Blob */ class BlobWorldFun extends World { int width = 200; int height = 300; Blob blob; /** The constructor */ BlobWorldFun(Blob blob) { super(); this.blob = blob; } /** Move the Blob when the player presses a key */ World onKeyEvent(String ke) { return new BlobWorldFun(blob.moveBlob(ke)); } /** On tick check whether the Blob is out of bounds, * or fell into the black hole in the middle. * If all is well, move the Blob in a random direction. */ World onTick() { // if the blob is outside the canvas, stop if (this.blob.outsideBounds(this.width, this.height)){ return this.endOfWorld("Blob is outside the bounds"); } // time ends is the blob falls into the black hole in the middle else {if (this.blob.nearCenter(this.width, this.height) && this.endOfTime("Black hole ate the blob")){ return this; } // else move the blob randomly at most 5 pixels in any direction else { return new BlobWorldFun(this.blob.randomMove(5)); }} } World endOfWorld(String message){ return this; } /** draw this world with a blue background */ boolean draw() { return this.theCanvas.drawRect(new Posn(0, 0), this.width, this.height, new Blue()) && this.blob.draw(this.theCanvas) && this.theCanvas.drawDisk(new Posn(100, 150), 10, new Black()) && this.theCanvas.drawCircle(new Posn(100, 150), 10, new White()) && this.theCanvas.drawRect(new Posn(95, 145), 10, 10, new White()) && this.theCanvas.drawLine(new Posn(95, 145), new Posn(105, 155), new Red()) && this.theCanvas.drawLine(new Posn(95, 155), new Posn(105, 145), new Red()); } } class BlobExamples{ // examples of data for the Blob class: Blob b1 = new Blob(new Posn(100, 100), 50, new Red()); Blob b1left = new Blob(new Posn(95, 100), 50, new Red()); Blob b1right = new Blob(new Posn(105, 100), 50, new Red()); Blob b1up = new Blob(new Posn(100, 95), 50, new Red()); Blob b1down = new Blob(new Posn(100, 105), 50, new Red()); Blob b1G = new Blob(new Posn(100, 100), 50, new Green()); Blob b1Y = new Blob(new Posn(100, 100), 50, new Yellow()); /** test the method moveBlob in the Blob class */ boolean testMoveBlob(Tester t){ return t.checkExpect(b1.moveBlob("left"), b1left, "test moveBolb - left " + "\n") && t.checkExpect(b1.moveBlob("right"), b1right, "test movelob - right " + "\n") && t.checkExpect(b1.moveBlob("up"), b1up, "test moveBlob - up " + "\n") && t.checkExpect(b1.moveBlob("down"), b1down, "test moveBlob - down " + "\n") && t.checkExpect(b1.moveBlob("G"), b1G, "test moveBlob - G " + "\n") && t.checkExpect(b1.moveBlob("Y"), b1Y, "test moveBlob - Y " + "\n") && t.checkExpect(b1G.moveBlob("R"), b1, "test moveBlob - R " + "\n"); } /** test the method outsideBounds in the Blob class */ boolean testOutsideBounds(Tester t){ return t.checkExpect(b1.outsideBounds(60, 200), true, "test outsideBounds on the right") && t.checkExpect(b1.outsideBounds(100, 90), true, "test outsideBounds below") && t.checkExpect( new Blob(new Posn(-5, 100), 50, new Red()).outsideBounds(100, 110), true, "test outsideBounds above") && t.checkExpect( new Blob(new Posn(80, -5), 50, new Blue()).outsideBounds(100, 90), true, "test outsideBounds on the left") && t.checkExpect(b1.outsideBounds(200, 400), false, "test outsideBounds - within bounds"); } /** test the method nearCenter in the Blob class */ boolean testNearCenter(Tester t){ return t.checkExpect(b1.nearCenter(200, 200), true, "test nearCenter - true") && t.checkExpect(b1.nearCenter(200, 100), false, "test nearCenter - false"); } /** the method randomInt in the Blob class */ boolean testRandomInt(Tester t){ return t.checkOneOf("test randomInt", b1.randomInt(3), -3, -2, -1, 0, 1, 2, 3) && t.checkNoneOf("test randomInt", b1.randomInt(3), -5, -4, 4, 5); } /** the method randomMove in the Blob class */ boolean testRandomMove(Tester t){ return t.checkOneOf("test randomMove", b1.randomMove(1), new Blob(new Posn( 99, 99), 50, new Red()), new Blob(new Posn( 99, 100), 50, new Red()), new Blob(new Posn( 99, 101), 50, new Red()), new Blob(new Posn(100, 99), 50, new Red()), new Blob(new Posn(100, 100), 50, new Red()), new Blob(new Posn(100, 101), 50, new Red()), new Blob(new Posn(101, 99), 50, new Red()), new Blob(new Posn(101, 100), 50, new Red()), new Blob(new Posn(101, 101), 50, new Red())); } /** run the animation */ BlobWorldFun w = new BlobWorldFun(new Blob(new Posn(100, 200), 20, new Red())); // test that we can run three different animations concurrently // with the events directed to the correct version of the world boolean runAnimation = this.w.bigBang(200, 300, 0.3); boolean runAnimation2 = this.w.bigBang(200, 300, 0.3); boolean runAnimation3 = this.w.bigBang(200, 300, 0.3); /** starting the world and running the tests: fourth instance*/ boolean testRun(Tester t){ return w.bigBang(200, 300, 0.3); } }