On this page:
2.1 Instructions
Practice Problems
Problem 1: Webpages
Problem 2: Avoiding repetition
Problem 3: Completing list-of-string methods for other representations
Problem 4: Lighting up the night
Using the javalib library
8.12

Assignment 2: Designing methods for complex data🔗

Goals: Learn to design methods for complex class hierarchies. Practice designing the representation of complex data.

2.1 Instructions🔗

This homework should be done with your lab partner.

Be very, very careful with naming! Again, the solution files expect your submissions to be named a certain way, so that they can define their own Examples class with which to test your code. Therefore, whenever the assignment specifies:
  • the names of classes,

  • the names and types of the fields within classes,

  • the names, types and order of the arguments to the constructor,

  • the names, types and order of arguments to methods, or

  • filenames,

...be sure that your submission uses exactly those names. Additionally, make sure you follow the style guidelines that Bottlenose enforces. For now the most important ones are: using spaces instead of tabs, indenting by 2 characters, following the naming conventions (data type names start with a capital letter, names of fields and methods start with a lower case letter), and having spaces before curly braces.

You will submit this assignment by the deadlines using the course handin server. Follow A Complete Guide to the Handin Server for information on how to use the handin server. You may submit as many times as you wish. Be aware of the fact that close to the deadline the server may slow down to handle many submissions, so try to finish early. There will be a separate submission for each problem - it makes it easier to grade each problem, and to provide you with the feedback for each problem you work on.

Your submissions for this homework will be organized as follows:

Due Date: Tuesday, January 23th, 9:00 pm

Practice Problems🔗

Work out these problems on your own. Save them in an electronic portfolio, so you can show them to your instructor, review them before the exam, use them as a reference when working on the homework assignments.

Problem 1: Webpages🔗

The following DrRacket data definition describes a website as a collection of Webpages:

;; A Webpage is a (make-webpage String [List-of Content])
(define-struct webpage (name content))
 
;; A Content is one of
;; -- Text
;; -- Picture
;; -- Hyperlink
 
;; A Text is a (make-text String Number Boolean)
(define-struct text (name num-lines in-markdown?))
 
;; A Picture is a (make-picture String String Number)
(define-struct picture (name description megabytes))
 
;; A Hyperlink is a (make-link String Webpage)
(define-struct link (text destination))

We are giving you the names of the classes or interfaces you will probably need — make sure you use these names to define your interfaces and classes.

A reminder on naming conventions: For lists of data, the names of the interface should always start with ILo, while the two classes’ names start with MtLo for the empty lists and ConsLo for the nonempty lists; all three of these names should be followed by the name of the datatype of the elements of the list. So we would have ILoString, MtLoString, ConsLoString to represent lists of Strings, ILoBook, MtLoBook, ConsLoBook to represent lists of Books, etc.

Note: if it helps you at all in this assignment, you may assume that every name in this website is distinct.

Problem 2: Avoiding repetition🔗

When your boss compared the output of totalCredits with the actual bill from the web hosting provider, they found that you overestimated how much the bill was. There were some repeated appearances of features in the methods you implemented. For this problem, copy your Webpages.java file to a new UniqueWebpages.java file, and fix that repetition. Note: the automated tests for the above problem expect that repetition, so you cannot submit the same file for both of these problems.

Hint: you should not need to create any new data definitions (i.e. interfaces) for this problem or revise existing ones (i.e. create new classes), though you may need to define some additional helper methods for existing ones.

Problem 3: Completing list-of-string methods for other representations🔗

This is a much broader conception of the usefulness of interfaces, than simply as “tags” for indicating the options of union data. Most of our uses of interfaces this semester will be for union data, and we’ll explore this flexibility in more detail in OOD; for now, I want to give you a small “sneak preview” of that future mindset.

Your task in this problem is to think a bit differently about what it means “to be a list”: in Fundies 1, we said a list was always either '() or a cons. But in Fundies 2, a list is whatever can implement the ILoString interface. One way of looking at MtLoString and ConsLoString is that those two classes represent two ways of “putting lists together”. In class we briefly introduced two new implementations for the ILoString interface: SnocLoString that added one item to the end of a list, and AppendLoString that appended two lists together — these are evidently two other ways of “putting lists together”, and if they can successfully implement the methods needed, then they must be perfectly valid kinds of lists! We didn’t have time to sketch out implementations of methods on those classes in class, so in this problem, you’ll actually implement a few of those methods.

Hint: As a strong suggestion: build lots of examples of lists for this problem, and consider building multiple examples that represent the same elements in the same order, but that are constructed using different mixes of the classes above.

You do not need to implement other list methods (e.g. sort, size, etc.) for this problem, though you may choose to do so to aid your debugging or testing.

Examplar submissions

Related files:
  lists.zip  

For this problem, we are going to to supply an additional submission on Handins. You will write examples and test cases against a placeholder implementation of the classes and interface needed for this problem, and we will run your test cases against multiple implementations: both correct and buggy! Your goal is to write sufficient test cases to distinguish all the correct implementations from all the buggy ones. We call the correct implementations wheat, and the buggy ones chaff: your goal is to separate the wheat from the chaff.

To do this:
  • Create a separate project for this tests-only assignment.

  • Download the lists.zip file and unzip it into your src/ directory: it should create a lists subdirectory with five files in it.

  • Create a file ExamplesLoString.java in your src directory, with the following initial contents:
    import lists.*;
    import tester.Tester;
     
    class ExamplesLoString {
    // your examples go here }

  • You must not modify the supplied Java files: they’re provided only to ensure that your tests match the types expected by our implementations.

You will submit only the ExamplesLoString.java file; do not submit the support files we gave you.

Make sure you’ve worked through the lab this week to understand what Examplar is showing you here. Focus on improving each section of the Examplar results in order: first ensure Correctness of your tests, then improve Thoroughness, and once you have both of those working, improve Precision and Usefulness. It is possible to get 100% Precise and Useful results...but it may not be worth your time to do so. Designing a Correct and Thorough suite of examples is a necessary skill for designing an implementation for anything, but designing a Precise and Useful test suite is a refinement on top of that.

Once you’ve successfully written your Examplar suite, you should be able to copy it in to your tests for the rest of this problem, and confirm that your own implementation satisfies your own Examplar examples. (You will need to remove the import lists.*; line from the top, but everything else should be unchanged.

Problem 4: Lighting up the night🔗

In this problem, you will be drawing and working with tree-shaped data representing a lightning bolt as it flashes through a storm.

interface ILightningBolt { /* see methods below */ }
 
// represents one final endpoint of a lightning bolt class Tip implements ILightningBolt {
}
 
// represents a straight section of a lightning bolt class Segment implements ILightningBolt {
// How long this piece of the bolt is is int length;
// The electric current carried in this part of the bolt, measured in kilo-Amperes int current;
// The angle (in degrees) of this flow, relative to the +x axis double theta;
// The rest of the lightning bolt ILightningBolt bolt;
}
 
// represents the lightning bolt splitting in two class Fork implements ILightningBolt {
// How long the left and right branches are int leftLength;
int rightLength;
// The electric current in each part of the bolt, measured in kilo-Amperes int leftCurrent;
int rightCurrent;
// The angle (in degrees) of the two branches, relative to the +x axis, double leftTheta;
double rightTheta;
// The remaining parts of the lightning bolt ILightningBolt left;
ILightningBolt right;
}

A Segment at an angle of 90 degrees is running straight up; a Fork with a left angle of 135 degrees and a right angle of 45 degrees points on both upward diagonals. (The tips of the bolt don’t need an angle, since we can just draw a small dot to indicate the lightning stops there.)

Examplar submissions

Related files:
  lightning.zip  

We are also supplying an additional submission on Handins for Examplar test cases. Follow similar instructions as above, using the lightning.zip file above, and with starter code

import lightning.*;
import tester.Tester;
import javalib.worldimages.*;
 
class ExamplesLightning {
// your examples go here }

You do not need to write Examplar tests for the draw() method, but you should test the other three methods.

Using the javalib library🔗

The javalib library provides the support for the design of interactive games and creating images composed by combining geometric shapes as well as image files. See The Image Library for more information.

To use the library, download the javalib file above and add it to your project the same way you have added the tester library.

At the top of the .java file where the library is used, add the following import statements:

import tester.*; // The tester library import javalib.worldimages.*; // images, like RectangleImage or OverlayImages import javalib.funworld.*; // the abstract World class and the big-bang library import java.awt.Color; // general colors (as triples of red,green,blue values) // and predefined colors (Color.RED, Color.GRAY, etc.)

You can test images using check-expect just as you can check other values:
boolean testImages(Tester t) {
return t.checkExpect(new RectangleImage(30, 20, OutlineMode.SOLID, Color.GRAY),
new RectangleImage(30, 20, OutlineMode.SOLID, Color.GRAY));
}

But note that you must construct the images in the same manner: for example, the following test will fail:
boolean testFailure(Tester t) {
return t.checkExpect(
new ScaleImageXY(new RectangleImage(60, 40, OutlineMode.SOLID, Color.GRAY), 0.5, 0.25),
new RectangleImage(30, 15, OutlineMode.SOLID, Color.GRAY));
}

Finally, you can display your images so that you can see whether you’re on the right track, as follows:

boolean testDrawBolt(Tester t) {
WorldCanvas c = new WorldCanvas(500, 500);
WorldScene s = new WorldScene(500, 500);
return c.drawScene(s.placeImageXY(myBolt.draw(), 250, 250))
&& c.show();
}

See The Image Library for more information.