/*********************************************** * CS2510 Spring 2011 * Lecture #8+ (Chadwick) * Designing the Snake Game ***********************************************/ import tester.*; import image.*; import world.*; // Represents the SnakeGame World class SnakeWorld extends World{ Snake sammy; Food hb; SnakeWorld(Snake sammy, Food hb){ this.sammy = sammy; this.hb = hb; } /* Template * Fields: * ... this.sammy ... -- Snake * ... this.hb ... -- Food * * Methods: * ... this.onDraw() ... -- Scene * ... this.tickRate() ... -- double * ... this.onTick() ... -- SnakeWorld * ... this.onKey(String) ... -- SnakeWorld * ... this.moveSnake() ... -- SnakeWorld * * Methods of Fields: */ // Draw this SnakeWorld public Scene onDraw(){ return this.hb.drawScene(this.sammy .drawScene(new EmptyScene(this.hb.WIDTH, this.hb.HEIGHT))); } // Set the tick rate for the world... 1/3 of a second public double tickRate(){ return 0.3; } // On a tick, move the Snake public SnakeWorld onTick(){ return this.moveSnake(); } // On a key, set the Snake's direction public SnakeWorld onKey(String ke){ // A valid direction? if(ke.equals("up") || ke.equals("down") || ke.equals("left") || ke.equals("right")){ return new SnakeWorld(this.sammy.changeDir(ke), this.hb); }else{ return this; } } // Helper to move the snake SnakeWorld moveSnake(){ return new SnakeWorld(this.sammy.move(), this.hb); } } // Represents a Snake class Snake{ ALoS segs; String dir; Snake(ALoS segs, String dir) { this.segs = segs; this.dir = dir; } /* Template * Fields: * ... this.segs ... -- ALoS * ... this.dir ... -- String * * Methods: * ... this.drawScene(Scene) ... -- Scene * ... this.move() ... -- Snake * ... this.changeDir(String) ... -- Snake * * Methods of Fields: * ... this.segs.drawScene(Scene) ... -- Scene * ... this.segs.move(String) ... -- ALoS * ... this.equals(String) ... -- boolean */ // Draw this snake into the scene Scene drawScene(Scene scn){ return this.segs.drawScene(scn); } // Move this snake == Move the segs Snake move(){ return new Snake(this.segs.move(this.dir), this.dir); } // Change/set the direction of this Snake Snake changeDir(String dir){ return new Snake(this.segs, dir); } } // Represents a Grid Position abstract class AGrid extends Posn{ int CELL_SIZE = 20; int WIDTH_CELLS = 20; int HEIGHT_CELLS = 20; int WIDTH = this.WIDTH_CELLS * this.CELL_SIZE; int HEIGHT = this.HEIGHT_CELLS * this.CELL_SIZE; AGrid(int x, int y){ super(x,y); } /* Template * Fields: * ... this.x ... -- int * ... this.y ... -- int * * Methods: * ... this.cell2Pixel() ... -- Posn */ // Calculate the pixel-coords from cell-coord Posn cell2Pixel(){ return new Posn(this.CELL_SIZE * this.x + this.CELL_SIZE/2, this.CELL_SIZE * this.y + this.CELL_SIZE/2); } } // Represents a List of Segs abstract class ALoS{ // Draw this LoS into the given Scene abstract Scene drawScene(Scene scn); // Drop the last segment from this List abstract ALoS dropLast(); // Is this a single list? abstract boolean oneHuh(); // "Move" this list in the given direction abstract ALoS move(String dir); } // Represents an single-segment List class OneLoS extends ALoS{ Seg first; OneLoS(Seg first){ this.first = first; } /* Template * Fields: * ... this.first ... -- Seg * * Methods: * ... this.drawScene(Scene) ... -- Scene * ... this.dropLast() ... -- ALoS * ... this.oneHuh() ... -- boolean * ... this.move(String) ... -- ALoS * * Methods of Fields: * ... this.first.drawScene(Scene) ... -- Scene * ... this.first.move(String) ... -- Seg */ // Draw this Single LoS into the Scene Scene drawScene(Scene scn){ return this.first.drawScene(scn); } // Drop the last element from this list of Segs ALoS dropLast(){ throw new RuntimeException("Can't Have an Empty Snake!"); } // Is this a single list? Yes! boolean oneHuh(){ return true; } // "Move" this one-seg list in the given direction ALoS move(String dir){ return new OneLoS(this.first.move(dir)); } } // Represents a List of Segs with 2 or more elements class ConsLoS extends ALoS{ Seg first; ALoS rest; ConsLoS(Seg first, ALoS rest){ this.first = first; this.rest = rest; } /* Template * Fields: * ... this.first ... -- Seg * * Methods: * ... this.drawScene(Scene) ... -- Scene * ... this.dropLast() ... -- ALoS * ... this.oneHuh() ... -- boolean * ... this.move(String) ... -- ALoS * * Methods of Fields: * ... this.first.drawScene(Scene) ... -- Scene * ... this.first.move(String) ... -- Seg * ... this.rest.drawScene(Scene) ... -- Scene * ... this.rest.dropLast() ... -- ALoS * ... this.rest.oneHuh() ... -- boolean * ... this.rest.move(String) ... -- Seg */ // Draw this Cons LoS into the given Scene public Scene drawScene(Scene scn){ return this.first.drawScene(this.rest.drawScene(scn)); } // Drop the last segment from this Cons List ALoS dropLast(){ // Rest is the last segment... if(rest.oneHuh()){ // Leave it off the end return new OneLoS(this.first); }else{ // Include our first, and drop the last of the rest return new ConsLoS(this.first, this.rest.dropLast()); } } // Is this a single list? No! boolean oneHuh(){ return false; } // "Move" this list of segs in the given direction ALoS move(String dir){ return new ConsLoS(this.first.move(dir), this.dropLast()); } } // Represents a Segment of the snake class Seg extends AGrid{ Seg(int x, int y){ super(x,y); } /* Template * Fields: * ... this.x ... -- int * ... this.y ... -- int * * Methods: * ... this.cell2Pixel() ... -- Posn * ... this.drawScene(Scene) ... -- Scene * ... this.move(String) ... -- Seg */ // Draw this Segment into the scene Scene drawScene(Scene scn){ return scn.placeImage(new Circle(this.CELL_SIZE/2, "solid", "green"), this.cell2Pixel()); } // Is this a single list? Seg move(String dir){ if(dir.equals("up")){ return new Seg(this.x, this.y-1); }else{ if(dir.equals("down")){ return new Seg(this.x, this.y+1); }else{ if(dir.equals("left")){ return new Seg(this.x-1, this.y); }else{ return new Seg(this.x+1, this.y); } } } } } // Represents a Food class Food extends AGrid{ Food(int x, int y){ super(x,y); } /* Template * Fields: * ... this.x ... -- int * ... this.y ... -- int * * Methods: * ... this.cell2Pixel() ... -- Posn * ... this.drawScene(Scene) ... -- Scene */ // Draw this Food into the scene Scene drawScene(Scene scn){ return scn.placeImage(new Circle(this.CELL_SIZE/2-1, "solid", "red"), this.cell2Pixel()); } } // Examples and Tests for the Snake Game... class SnakeExamples{ SnakeExamples(){} Food g1 = new Food(3,2); Food g2 = new Food(10,10); Seg s1 = new Seg(5,5); Seg s2 = new Seg(5,6); Seg s3 = new Seg(5,7); Scene mtscene = new EmptyScene(100, 100); ALoS los1 = new OneLoS(this.s1); ALoS los2 = new ConsLoS(this.s2, this.los1); ALoS los3 = new ConsLoS(this.s3, this.los2); Snake sammy1 = new Snake(this.los3, "down"); boolean testCells(Tester t){ return (t.checkExpect(g1.cell2Pixel(), new Posn(70,50)) && t.checkExpect(g2.cell2Pixel(), new Posn(210,210))); } boolean testDraw(Tester t){ return (t.checkExpect(g1.drawScene(mtscene), mtscene.placeImage(new Circle(g1.CELL_SIZE/2-1, "solid", "red"), g1.cell2Pixel())) && t.checkExpect(s1.drawScene(mtscene), mtscene.placeImage(new Circle(s1.CELL_SIZE/2, "solid", "green"), s1.cell2Pixel()))); } SnakeWorld sw = new SnakeWorld(this.sammy1, this.g1); World last = sw.bigBang(); }