/******************************** * CS2510 Fall 2011 * Lecture #9.1 * Finishing Snake and Simple API ********************************/ import tester.*; import image.*; import world.*; // Represents the SnakeGame world class SnakeWorld extends World { Snake snake; Food food; /** * Template * * Fields * snake -- Snake * food -- Food * * Methods * onTick -- SnakeWorld * onDraw -- Scene * onKey -- SnakeWorld */ SnakeWorld(Snake snake, Food food) { this.snake = snake; this.food = food; } SnakeWorld() { this.food = new Food(3,3); Seg seg1 = new Seg(10,10); Seg seg2 = new Seg(10,11); Seg seg3 = new Seg(10,12); OneLoS onelos = new OneLoS(seg3); ILoS segs = new ConsLoS(seg1, new ConsLoS(seg2,onelos)); this.snake = new Snake(segs,"up"); } // Sets the speed of the world public double tickRate() { return 0.25; } // Draws the world with the snake and food public Scene onDraw() { return snake.draw(food.draw(new EmptyScene(food.WIDTH,food.HEIGHT))); } // Makes our snake move each tick public SnakeWorld onTick() { if(snake.wouldEatP(food)) { return new SnakeWorld(snake.grow(),new Food((int)(Math.random()*20),(int)(Math.random()*20))); } else { return new SnakeWorld(snake.move(),food); } } // Sets the direction of the snake based on key presses public SnakeWorld onKey(String str) { return new SnakeWorld(snake.changeDir(str),food); } } // Represents a grid position in our world abstract class AGrid extends Posn { // Some constants about our grid int CELL_SIZE = 20; int WIDTH_INCELLS = 20; int HEIGHT_INCELLS = 20; int WIDTH = WIDTH_INCELLS * CELL_SIZE; int HEIGHT = HEIGHT_INCELLS * CELL_SIZE; AGrid(int x, int y) { super(x, y); } /** * Template * Fields: * this.x -- int * this.y -- int * Methods: * this.cell2Pixel() -- Posn */ // Converts a cell to its pixel position Posn cell2Pixel() { return new Posn(CELL_SIZE * x + CELL_SIZE/2, CELL_SIZE * y + CELL_SIZE/2); } } // Represents a food object in our SnakeWorld class Food extends AGrid { Food(int x, int y) { super(x, y); } /** * Template * * Fields: * this.x -- int * this.y -- int * Methods: * this.draw(Scene) -- Scene */ // Draws the Food in the scene Scene draw(Scene s) { return s.placeImage(new Circle(CELL_SIZE/2-1, "solid", "purple"), this.cell2Pixel()); } } // Represents a Segment in our SnakeWorld class Seg extends AGrid { Seg(int x, int y) { super(x, y); } /** * Template * * Fields: * this.x -- int * this.y -- int * Methods: * this.draw(Scene) -- Scene * this.move(String) -- Seg */ // Draws the segment into the scene Scene draw(Scene s) { return s.placeImage(new Circle(CELL_SIZE/2-1, "solid", "black"), this.cell2Pixel()); } // Returns a moved segment based on key presses Seg move(String dir) { if(dir.equals("up")) { return new Seg(x,y-1); } else if(dir.equals("down")) { return new Seg(x,y+1); } else if(dir.equals("left")) { return new Seg(x-1,y); } else if(dir.equals("right")) { return new Seg(x+1,y); } else { return this; } } } // List of Segments interface ILoS { /** * Template * * Methods: * this.draw(Scene) -- Scene * this.move(dir) -- ILoS * this.dropLast() -- ILoS * this.onlyOne() -- boolean * this.grow(String) -- ILoS * this.samePos(Food) -- boolean */ Scene draw(Scene s); ILoS move(String dir); ILoS dropLast(); boolean onlyOne(); ILoS grow(String dir); boolean samePos(Food f); } abstract class ALoS implements ILoS { Seg first; ALoS(Seg first) { this.first = first; } /** * Template * * Fields: * this.first -- Seg * Methods: * this.grow(String) -- boolean * this.samePos(Food) -- boolean */ // Grows the list by one in the direction dir public ILoS grow(String dir) { return new ConsLoS(first.move(dir),this); } // Is the head in the same position as the food public boolean samePos(Food f) { return ((first.x == f.x) && (first.y == f.y)); } } // A one segment list item class OneLoS extends ALoS { OneLoS(Seg first) { super(first); } /** * Template * * Fields: * this.first -- Seg * Methods: * this.draw(Scene) -- Scene * this.dropLast() -- ILoS * this.move(String) -- ILoS * this.grow(String) -- ILoS * this.onlyOne() -- boolean */ // Draws the only segment in the list public Scene draw(Scene s) { return first.draw(s); } // Moves the only segment public ILoS move(String dir) { return new OneLoS(first.move(dir)); } // This list has only 1 element public boolean onlyOne() { return true; } // Can not drop last, only one element public ILoS dropLast() { throw new RuntimeException("No last to drop"); } } // A cons list item for segments class ConsLoS extends ALoS { ILoS rest; ConsLoS(Seg first, ILoS rest) { super(first); this.rest = rest; } /** * Template * * Fields: * this.first -- Seg * this.rest -- ILoS * Methods: * this.draw(Scene) -- Scene * this.dropLast() -- ILoS * this.move(String) -- ILoS * this.grow(String) -- ILoS * this.onlyOne() -- boolean */ // Draws this segment with the rest of the segments public Scene draw(Scene s) { return rest.draw(first.draw(s)); } // Adds a moved segment and drops the last segment public ILoS move(String dir) { return new ConsLoS(first.move(dir),this.dropLast()); } // Removes the last segment from the list public ILoS dropLast() { if (rest.onlyOne()) { return new OneLoS(first); } else { return new ConsLoS(first,rest.dropLast()); } } // This list has more than 1 element public boolean onlyOne() { return false; } } // Our Snake with its list of segments class Snake { ILoS segs; String dir; Snake(ILoS segs, String dir) { super(); this.segs = segs; this.dir = dir; } /** * Template * * Fields: * this.segs -- ILoS * this.dir -- String * * Methods * this.draw(s) -- Scene * this.changeDir(String) -- Snake * this.move() -- Snake * this.grow() -- Snake */ // Draws the snake segments Scene draw(Scene s) { return segs.draw(s); } // Sets a new direction for the snake Snake changeDir(String dir) { return new Snake(segs, dir); } // Moves the snake one step in current direction Snake move() { return new Snake(segs.move(dir),dir); } Snake grow() { return new Snake(segs.grow(dir),dir); } boolean wouldEatP(Food f) { return move().segs.samePos(f); } } // Examples and tests of our SnakeWorld objects class SnakeWorldExamples { Food f1 = new Food(3,3); Food f2 = new Food(10,10); Seg seg1 = new Seg(10,10); Seg seg2 = new Seg(10,11); Seg seg3 = new Seg(10,12); OneLoS onelos = new OneLoS(seg2); ILoS segs = new ConsLoS(seg1, onelos); Snake snake = new Snake(segs,"up"); //SnakeWorld world = new SnakeWorld(snake,f1); //World bang = world.bigBang(); SnakeWorld world = new SnakeWorld(); World bang = world.bigBang(); boolean testCells(Tester t) { return(t.checkExpect(f1.cell2Pixel(),new Posn(70,70)) && t.checkExpect(seg1.cell2Pixel(),new Posn(210,210))); } boolean testILoS(Tester t) { return t.checkException(new RuntimeException("No last to drop"), onelos, "dropLast"); } }