import javalib.funworld.*; import javalib.worldimages.*; import javalib.worldcanvas.*; import javalib.colors.*; import tester.*; import java.awt.Color; import java.util.*; /* --- THE OCEAN WORLD ----------------------------------------------- Fish swim across the screen from right to left. There may be one fish, or a whole school of fish, or none at a time. A hungry shark swims in place at the left side, moving only up and down, controlled by the \scheme{"up"} and \scheme{"down"} keys. It tries to catch and eat the fish. It gets bigger with each fish it eats, it keeps getting hungrier and hungrier as the time goes on between the catches. It dies of starvation, if not fed in time. --------------------------------------------------------------------*/ /* +--------+ | CartPt | +--------+ | int x | | int y | +--------+ */ //to represent a location in the graphics window class CartPt extends Posn{ // a random number generator Random rand = new Random(); CartPt(int x, int y){ super(x, y); } /* Template: Fields: ... this.x ... -- int ... this.y ... -- int Methods: ... this.distTo(CartPt) ... -- double */ // compute the distance from this posn to the given one int distTo(CartPt that){ return Math.abs(this.x - that.x) + Math.abs(this.y - that.y); } // move randomly left or right CartPt moveRand(){ return new CartPt(this.x, this.y + rand.nextInt(5) - 2); } } // to represent one fish swimming in the ocean class Fish{ // the image of this fish WorldImage fishImage = new FromFileImage(new Posn(0, 0), "small-red-fish.png"); // the location of this fish CartPt loc; // the constructor Fish(CartPt loc){ this.loc = loc; fishImage = this.fishImage.getMovedTo(this.loc); } /* Template: Fields: ... this.loc ... -- CartPt ... this.fishImage ... -- WorldImage Methods: ... this.move() ... -- Fish ... this.isFood(Shark) ... -- boolean Methods for fields: ... this.loc.distTo(CartPt) ... -- double ... this.fishImage.getMovedImage(int dx, int dy) ... -- WorldImage ... this.fishImage.getMovedTo(CartPt) ... -- WorldImage ... this.fishImage.overlayImages(WorldImage) ... -- WorldImage */ // move this fish on tick Fish move(){ if (this.loc.x < 0) return new Fish(new CartPt(400 - 3, this.loc.y)); else return new Fish(new CartPt(this.loc.x - 3, this.loc.y)); } // is this fish a shark food? boolean isFood(Shark shark){ return this.loc.distTo(shark.loc) < 10; } } /* +------------+ | Shark | +------------+ | CartPt loc | | int life | +------------+ */ // to represent a shark in an ocean world class Shark { // the image of this fish WorldImage sharkImage = new FromFileImage(new Posn(0, 0), "small-shark.png"); // the location of this shark CartPt loc; // the number of lives left for this shark int life; // the constructor Shark(CartPt loc, int life) { this.loc = loc; this.life = life; } /* Template: Fields: ... this.loc ... -- CartPt ... this.sharkImage ... -- WorldImage Methods: ... this.???() ... -- ??? Methods for fields: ... this.loc.distTo(CartPt) ... -- double ... this.sharkImage.getMovedImage(int dx, int dy) ... -- WorldImage ... this.sharkImage.getMovedTo(CartPt) ... -- WorldImage ... this.sharkImage.overlayImages(WorldImage) ... -- WorldImage */ } /* +-------------+ | OceanWorld | +-------------+ | Shark shark | | Fish fish | +-------------+ */ // to represent an ocean world class OceanWorld extends World{ Shark shark; Fish fish; // the width of the world int WIDTH = 400; // the height of the world int HEIGHT = 400; // the color of the ocean Color oceanColor = new Color(50, 150, 255); // the background image of the ocean WorldImage oceanImage = new RectangleImage(new Posn(WIDTH/2, HEIGHT/2), WIDTH, HEIGHT, oceanColor); OceanWorld(Shark shark, Fish fish) { this.shark = shark; this.fish = fish; } /* Template: Fields: ... this.shark ... -- Shark ... this.fish ... -- Fish Methods: ... this.makeImage() ... -- WorldImage ... this.onTick() ... -- Ocean ... this.onKeyEvent(String) ... -- Ocean ... this.caughtFish() ... -- boolean Methods for fields: ... this.shark.???() ... -- ??? ... this.fish.move() ... -- double ... this.fish.isFood(Shark) ... -- boolean */ // show just the great blue yonder public WorldImage makeImage(){ return oceanImage; } // do nothing on tick public OceanWorld onTick(){ return this; } // do nothing in response to the key events public OceanWorld onKeyEvent(String ke){ return this; } // figure out whether the shark caught a fish in this world boolean caughtFish(){ return this.fish.isFood(this.shark); } } // Examples of the classes Fish, Shark, OceanWorld and tests for all methods class ExamplesOceanWorld{ ExamplesOceanWorld(){} // the width of the world int WIDTH = 400; // the height of the world int HEIGHT = 400; Shark mac = new Shark(new CartPt(10, 100), 200); Shark mac2 = new Shark(new CartPt(10, 100), 100); Shark mac3 = new Shark(new CartPt(10, 100), -1); Fish fishy = new Fish(new CartPt(190, 100)); Fish yummy = new Fish(new CartPt(15, 98)); Fish gone = new Fish(new CartPt(15, 98)); Fish gone2 = new Fish(new CartPt(WIDTH - 2, 98)); Fish fishyClone = new Fish(new CartPt(190, 100)); Fish yummyClone = new Fish(new CartPt(15, 98)); Fish goneClone = new Fish(new CartPt(15, 98)); Fish gone2Clone = new Fish(new CartPt(-2, 98)); Fish fishy1 = new Fish(new CartPt(0, 0)); Fish fishy2 = new Fish(new CartPt(0, 0)); Fish fishy3 = new Fish(new CartPt(0, 0)); Fish fishy4 = new Fish(new CartPt(0, 0)); Fish fishy5 = new Fish(new CartPt(0, 0)); OceanWorld sfw = new OceanWorld(this.mac, this.yummy); // test that the expected value is one of several possible values public void testRandomMove(Tester t){ t.checkRange((new CartPt(10, 20).moveRand()).y, 18, 23); t.checkOneOf(new CartPt(5, 20).moveRand(), new CartPt(5, 18), new CartPt(5, 19), new CartPt(5, 20), new CartPt(5, 21), new CartPt(5, 22)); } // test the move methods boolean testMove(Tester t){ return t.checkExpect(this.fishy.move(), new Fish(new CartPt(187, 100))) && sfw.bigBang(400, 400, 0.07); } }