/* --- CSU213 Spring 2005 Lecture Notes --------- Copyright 2005 Viera K. Proulx Lecture 18: Omnia mea mecum porto Goals: - recall how to design programs with accumulators Introduction: In the last lab you worked on finding a route in a transit system that would take you from one station to anther station. You program produced a list of stations on this route. Here is a class diagram for the classes from this lab: +---------------------+ | +----------------+ | | | | | v v | | +-----------+ | | | ANextStop | | | +-----------+ | | +-----------+ | | / \ | | --- | | | | | -------------------- | | | | | | +--------+ +-----------------+ | | | MTStop | | OneStop | | | +--------+ +-----------------+ | | +--------+ +-| Route route | | | +------------+ | int minutes | | | | +------| Station station | | | | | +-----------------+ | | | v | | | +-----------------+ | | | | Station | | | | +-----------------+ | | | | String name | | | | | Posn loc | | | | | ANextStop left |-------------+ | | | ANextStop right |---------------+ | +-----------------+ +-----+ | v +-------------+ | Route | +-------------+ | String name | | Color color | +-------------+ Our program produced a list of stations. (We omit the class diagram for the classes that represent a list of Stations - it is the same as a number of other similar examples. We would like to explore now the various routings available to us. For example, we want to know how many what is the total distance traveled. To simplify the problem we will compute the distance between two points as a 'Manahattan' distance - the number of blocks a bus may need to travel from location at avenue x and street y to another location. The problem can then be stated as follows: Determine the Manhattan distance of the route represented as a list of stations. The purpose statement and the header in the class ALoS is easy: // determine the total distance of this routing abstract int totalDist(); In the class MTLoS, the only example is: boolean testTotalDist1 = (new MTLoS()).totalDist() == 0; and the method is: int totalDist(){ return 0; } So, the only interesting case is in the class ConsLoS. Let us see some examples first: Station a = new Station("A", new Posn(4, 1)); Station b = new Station("B", new Posn(2, 4)); Station g = new Station("G", new Posn(3, 6)); Station z = new Station("Z", new Posn(3, 10)); ALoS aToZ = new ConsLoS(a, new ConsLoS(b, new ConsLoS(g, new ConsLoS(z, new MTLoS())))); ALoS aToA = new ConsLoS(a, new MTLoS()); boolean testTotalDist1 = aToZ.totalDist() == 5 + 3 + 4; // Note: dist a to b is 5; dist b to g is 3; dist g to z is 4 boolean testTotalDist2 = aToA.totalDist() == 0; Let us now think about the template: TEMPLATE: ... this.first ... ... this.first.name ... ... this.first.loc ... ... this.first.loc.manhDistTo(??? Posn p ???) ... this.rest ... ... this.rest.totalDist() ... We may assume that the class Posn has a method 'manhDistTo' that computes the manhattan distance from this Posn to the given Posn - we have written such methods earlier: ---- in the class Posn ---- (new Posn(3, 5)).manhDistTo(new Posn(5, 2)) ---> should be 5 (new Posn(3, 5)).manhDistTo(new Posn(3, 5)) ---> should be 0 // compute the manhattan distance from this Posn to the given one int manhDistTo(Posn p){ return Math.abs(this.x - p.x) + Math.abs(this.y - p.y); } ---- ***************** ---- However, there is no other Posn available to us in the body of the totalDist in the class ConsLoS. When we look at the list, we only see the first station in the list, and as we move to the rest of the list, all knowledge about the first station is forgotten. We can write an auxilliary method, where the previous station will be given as an argument: // determine the total distance of this routing // starting from the given station int distFrom(Station s){...} We modify the earlier example: ALoS bToZ = new ConsLoS(b, new ConsLoS(g, new ConsLoS(z, new MTLoS()))); boolean testDistFrom1 = bToZ.distFrom(a) == 5 + 3 + 4; boolean testDistFrom2 = (new MTLoS()).distFrom(a) == 0; The template is: ... this.first ... ... this.first.name ... ... this.first.loc ... ... this.first.loc.manhDistTo(??? Posn p ???) ... this.rest ... ... this.rest.totalDist() ... ... this.rest.distFrom(Station s) ... ... s.name ... ... s.loc ... Looking at the example 'testDistFrom1', we see that the first part of the sum is the distance from station a to station b. In our method, the station a is represented by the argument s, and the station b is represented by this.first. The second part of the sum is the rest of the distance, starting from b (represented by this.first). The method then is: // determine the total distance of this routing // starting from the given station int distFrom(Station s){ return this.first.loc.manhDistTo(s.loc) + this.rest.distFrom(this.first); } The second example shows us how to design the method for the class MTLoS: int distFrom(Station s){ return 0; } Of course, we need to add an abstract method to the abstract class as well. We now can use this auxilliary method to complete the design of the method totalDist in the class ConsLoS. Recall the purpose and header: // determine the total distance of this routing int totalDist(){ ... } The template now becomes: ... this.first ... // of the type Station ... this.first.name ... ... this.first.loc ... ... this.rest ... ... this.rest.totalDist() ... ... this.rest.distFrom(this.first) ... We read aloud the purpose statement for the last part of the template: determine the total distance of this routing (for the rest of this list) starting from the first station in this list and complete the method: int totalDist(){ return this.rest.distFrom(this.first); } We run the examples to test our work. -------------------------------------------------------------------------------- We reflect on the process we followed to design our solution. We first recognized that as we proceed through the list, we need to remember some information about objects that appeared earlier in the list. That lead us to the use of an auxilliary method, that consumes as argument the necessary accumulated information. The design of this auxilliary method follows the design recipe as always. In the final step we return to the design of the original method, our template now enriched by the auxilliary method. The original method then acts as a 'set up' for the invocation of the auxilliary method. You should review the design recipe for functions with accumulator in HtDP. In some cases we have a choice whether to use this accumulator style methods, or whether to find some other way to pass the needed information along. At other times, we have no choice and have to use the accumulator style. We will see an example in the next lecture. you may want to see if you can solve the problem from this lecture without the use of an accumulator. -------------------------------------------------------------------------------- */ /* ; ; ; ; ;;;; ; ; ; ; ; ; ; ; ; ; ;;; ;; ; ;;; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ;;;; ;;; ;; ; ;;;; ; ; ; */ // to represent a station class Station { String name; Posn loc; Station(String name, Posn loc) { this.name = name; this.loc = loc; } /* // ** DRAFT TEMPLATE ** Edit as needed. ??? mmm() { ... this.name ... ... this.loc ... } */ } // to represent a list of Station-s abstract class ALoS { // determine the total distance of this routing abstract int totalDist(); // determine the total distance of this routing // starting from the given station abstract int distFrom(Station s); /* // ** DRAFT TEMPLATE ** Edit as needed. // purpose statement abstract ??? mmm(); */ } // to represent an empty list of Stations-s class MTLoS extends ALoS { MTLoS() { } int totalDist(){ return 0; } int distFrom(Station s){ return 0; } /* // ** DRAFT TEMPLATE ** Edit as needed. ??? mmm() { } */ } // to represent an nonempty list of Stations-s class ConsLoS extends ALoS { Station first; ALoS rest; ConsLoS(Station first, ALoS rest) { this.first = first; this.rest = rest; } int totalDist(){ return this.distFrom(this.first); } int distFrom(Station s){ return this.first.loc.manhDistTo(s.loc) + this.rest.distFrom(this.first); } /* // ** TEMPLATE ** ... this.first ... ... this.first.name ... ... this.first.loc ... ... this.first.loc.manhDistTo(??? Posn p ???) ... this.rest ... ... this.rest.totalDist() ... ... this.rest.distFrom(Station s) ... } */ } // to represent a location class Posn { int x; int y; Posn(int x, int y) { this.x = x; this.y = y; } // compute the manhattan distance from this Posn to the given one int manhDistTo(Posn p){ return Math.abs(this.x - p.x) + Math.abs(this.y - p.y); } /* // ** DRAFT TEMPLATE ** Edit as needed. ??? mmm() { ... this.x ... ... this.y ... } */ } class Examples{ Examples (){} Station a = new Station("A", new Posn(4, 1)); Station b = new Station("B", new Posn(2, 4)); Station g = new Station("G", new Posn(3, 6)); Station z = new Station("Z", new Posn(3, 10)); ALoS mtlos = new MTLoS(); ALoS aToZ = new ConsLoS(a, new ConsLoS(b, new ConsLoS(g, new ConsLoS(z, new MTLoS())))); ALoS aToA = new ConsLoS(a, new MTLoS()); boolean testTotalDist1 = (new MTLoS()).totalDist() == 0; boolean testTotalDist2 = aToZ.totalDist() == 5 + 3 + 4; // Note: dist a to b is 5; dist b to g is 3; dist g to z is 4 boolean testTotalDist3 = aToA.totalDist() == 0; // ---- in the class Posn ---- boolean testManhDistTo1 = (new Posn(3, 5)).manhDistTo(new Posn(5, 2)) == 5; boolean testManhDistTo2 = (new Posn(3, 5)).manhDistTo(new Posn(3, 5)) == 0; ALoS bToZ = new ConsLoS(b, new ConsLoS(g, new ConsLoS(z, new MTLoS()))); boolean testDistFrom1 = bToZ.distFrom(a) == 5 + 3 + 4; boolean testDistFrom2 = (new MTLoS()).distFrom(a) == 0; }