/*********************************************** * CS2510 Fall 2011 * Lecture #5 * Conditionals, Immutable Lists, Dispatch cont. ***********************************************/ /* Conditionals in Racket and Java: (define sumodd (lon) (cond [(empty? lon) 0] [(is-odd? (first lon)) (+ (first lon) (sumodd (rest lon)))] [else (sumodd (rest lon))])) int sumodd (ILoN lon) { if (emptyHuh(lon)) { return 0; } else if (isOddHuh (lon.first)) { return (lon.first + lon.rest.sumodd()); } else { return rest.sumodd(); } } */ /* * New in this file: * - Conditionals in the Train classes * - Lists of Numbers * - moveUp for shapes * - Lists of Shapes * * Note: ILoS.moveUp calls IShape.moveUp, some instances of which * call IShape.moveUp recursively, others calling the Posn.moveUp * method with the specified amount to move up. * * As a personal experiment, you can try to change the ILoS and IShape * moveUp functions to take an int for the amount by which to move * up. */ import tester.Tester; interface ITrain { // Length returns the length of the train int length(); // Biggest returns the number of passengers of the largest car int biggest(); // MaxWeight returns the largest weight of the cars in the train double maxWeight(); } class Lead implements ITrain { int hp; ITrain next; /* Fields of *this*: * ... this.hp -- int * ... this.next -- ITrain * * Methods of *this*: * ... this.length() ... -- int * ... this.biggest() ... -- int * ... this.maxWeight() ... -- double */ Lead(int hp, ITrain next) { this.hp = hp; this.next = next; } // Returns 1 plus the length of the rest of the train public int length() { if (next == null) { return 1; } else { return this.next.length() + 1; } } // Returns the biggest of the rest, as this car holds no // passengers public int biggest() { if (next == null) { return 0; } else { return next.biggest(); } } // A lead car weighs 1lb / 10 hp public double maxWeight() { if (next == null) { return 2000 + hp/10; } else { return Math.max(2000 + hp/10, next.maxWeight()); } } } class Cab implements ITrain { int passengerc; ITrain next; /* Fields of *this*: * ... passengerc -- int * ... next -- ITrain * * Methods of *this*: * ... this.length() ... -- int * ... this.biggest() ... -- int * ... this.maxWeight() ... -- double */ Cab(int passengerc, ITrain next) { this.passengerc = passengerc; this.next = next; } // Returns 1 + length of the rest of the train public int length() { return this.next.length() + 1; } // Returns the larger of this car and the rest of the cars public int biggest() { return Math.max(passengerc, next.biggest()); } public double maxWeight() { return Math.max(2000 + passengerc*150,next.maxWeight()); } } class Kaboose implements ITrain { /* Fields of *this*: * ... * * Methods of *this*: * ... this.length() ... -- int * ... this.biggest() ... -- int * ... this.maxWeight() ... -- double */ Kaboose(){ } // Length returns 1 as there are no cars after it public int length() { return 1; } // Biggest returns 0 as there are no passengers // and no cars after it public int biggest() { return 0; } public double maxWeight() { return 2000; } } class TrainExamples { // Examples of Train types Kaboose k = new Kaboose(); Cab c1 = new Cab(20,new Cab(50,new Cab(15,k))); Lead leadcar = new Lead(2500,c1); Kaboose k2 = new Kaboose(); Lead leadcar2 = new Lead(1000,k2); int trainlength = leadcar.length(); Lead onlylead = new Lead(1500,null); boolean testLength(Tester t) { return t.checkExpect(leadcar.length(),5) && t.checkExpect(leadcar2.length(),2); } boolean testBiggest(Tester t) { return t.checkExpect(leadcar.biggest(),50) && t.checkExpect(leadcar2.biggest(),0); } boolean testMaxWeight(Tester t) { return t.checkExpect(leadcar.maxWeight(),2000.0+(50*150)) && t.checkExpect(leadcar2.maxWeight(),2100.0); } boolean testLengthOne(Tester t) { return t.checkExpect(onlylead.length(), 1); } } // ILoN is a list of numbers interface ILoN { // Sum calculates the sum of all numbers in the list // [] -> int int sum(); // Find returns the number at position "index" // Find: int -> int int find(int index); } // MtLoN is the empty case for the list of numbers class MtLoN implements ILoN { /* Fields of *this*: * * Methods of *this*: * ... this.sum() ... -- int * ... this.find(int) ... -- int */ MtLoN() { } public int sum() { return 0; } public int find(int index) { throw new IndexOutOfBoundsException("You're an idiot. Index out of bounds."); } } // ConsLoN is the cons case for the list of numbers class ConsLoN implements ILoN { int first; ILoN rest; ConsLoN(int first, ILoN rest) { this.first = first; this.rest = rest; } public int sum() { return (first + rest.sum()); } public int find(int index) { if (index == 0) { return first; } else { return rest.find(index - 1); } } } class LoNExamples { MtLoN mt = new MtLoN(); ConsLoN nlist = new ConsLoN(5,new ConsLoN(6,new ConsLoN(7,mt))); boolean testSum(Tester t) { return t.checkExpect(mt.sum(), 0) && t.checkExpect(nlist.sum(),18); } boolean testFind(Tester t) { return t.checkExpect(nlist.find(0), 5) && t.checkExpect(nlist.find(2),7) && t.checkException(new IndexOutOfBoundsException("You're an idiot. Index out of bounds."), mt, "find", 1); } } // IShape represents a shape interface IShape { // shapeDistTo0 returns the distance from the shape to the origin double shapeDistTo0(); IShape moveUp(); } // A Circle (as a type of IShape) class Circle implements IShape { int rad; Posn center; Circle(int rad, Posn center) { this.rad = rad; this.center = center; } // shapeDistTo0: The distance from the center of the circle to the origin public double shapeDistTo0() { return center.distTo0(); } public IShape moveUp() { return new Circle(rad, center.moveUp(10)); } } //A Rectangle (as a type of IShape) class Rect implements IShape { int h; int w; Posn center; Rect(int h, int w, Posn center) { this.h = h; this.w = w; this.center = center; } // shapeDistTo0: The distance from the center of the rectangle to the origin public double shapeDistTo0() { return center.distTo0(); } public IShape moveUp() { return new Rect(h, w, center.moveUp(10)); } } class Overlay implements IShape{ IShape s1; IShape s2; Overlay(IShape s1, IShape s2) { this.s1 = s1; this.s2 = s2; } // shapeDistTo0: The distance from the closest sub-shape to the origin public double shapeDistTo0() { return Math.min(s1.shapeDistTo0(),s2.shapeDistTo0()); } public IShape moveUp() { return new Overlay(s1.moveUp(),s2.moveUp()); } } /* Posn template... the laundry list ** Fields of "this" class ... this.x ... -- int ... this.y ... -- int ** We also add methods that we implement (and test) ... this.moveUp(int dy) ... -- Posn ... this.distTo0() ... -- double ... this.moveUpBy(Posn p) -- Posn ** If we have methods that we can call on fields of "this" then they go HERE ... */ /* We still do purpose statements, but the contract and * header are now part of the (Java-like) language */ class Posn { int x; int y; Posn(int xcoord, int ycoord) { this.x = xcoord; this.y = ycoord; } // moveUp returns a new Posn shifted up by dy Posn moveUp(int dy) { return new Posn(this.x, this.y+dy); } // moveUpBy returns a new Posn shifted by p.x and p.y Posn moveUpBy(Posn p) { return new Posn(this.x + p.x, this.y + p.y); } // distTo0 returns the distance from this posn to 0 double distTo0() { return Math.sqrt(Math.pow(this.x,2) + Math.pow(this.y,2)); } } class Examples { //Examples of shapes Circle c = new Circle(5,new Posn(1,2)); Rect r = new Rect(2,3,new Posn(5,4)); Overlay o = new Overlay(c,r); Overlay o2 = new Overlay(o,c); // Examples of Posns and posn methods Posn p1 = new Posn(1,2); Posn p2 = p1.moveUp(10); Posn p3 = p2.moveUpBy(p1.moveUp(5)); Double p1dist = p1.distTo0(); // Examples of Shape Methods Double cdist = c.shapeDistTo0(); Double o2dist = o2.shapeDistTo0(); Examples() { } } interface ILoS { // moveUp moves up all shapes in the list by 10 points // moveUp: [] -> ILoS ILoS moveUp(); } class MtLoS implements ILoS { MtLoS() { } // moveUp: Returns an empty ILoS public ILoS moveUp() { return new MtLoS(); } } class ConsLoS implements ILoS { IShape first; ILoS rest; ConsLoS(IShape first, ILoS rest) { this.first = first; this.rest = rest; } // moveUp: returns a list of this shape moved up cons'ed with the // rest of the list moved up public ILoS moveUp() { return new ConsLoS(first.moveUp(), rest.moveUp()); } }