Lab: Objects

Dear Computer

Chapter 5: Objects

Lab: Objects

In today's lab, you'll explore how objects are used to encapsulate state and behaviors. You'll also get some more practice with higher-order functions.

Top Rhymes

RhymeBrain is a web service. You give it a word, and it gives you a list of its rhymes. See it at work by checking out the rhymes for flesh. Note how the word is passed to the web service by appending it as a query parameter to the URL. Note also the structure of the results. What is the type of the overall collection? What is the type of an individual word? How would you access the score of the first word in the collection?

Write a Ruby program in top_rhymes.rb that shows a list of a word's top-scoring rhymes pulled down from RhymeBrain. Follow these steps to get it up and running:

Create a Rhyme class that has state for just the word and score. Add getters with as little work as possible.
Define a top-level function named top_rhymes that accepts a word and score threshold as parameters. This function is not a behavior of an individual Rhyme instance, so it should not be part of the Rhyme class.
Inside top_rhymes, fetch the JSON-formatted rhymes of the given word from the web service. The most stable means of slurping down a web page is the builtin net/http library. This program demonstrates how you might use it:
Ruby
require 'net/http'
require 'uri'

body = Net::HTTP.get(URI.parse(url_string))
Investigate the json library, and use it to parse the body of the response. The body is a string. Temporarily output the parsed data and investigate its type.
Convert the parsed data into an array of Rhyme. Use the most appropriate higher-order function. Do not use a loop or each.
Winnow down the rhymes to just those whose scores meet the threshold. Use the most appropriate higher-order function. Do not use a loop or each. Return (not print) the top rhymes as an array.
Accept command-line parameters via ARGV for the word to query and the score threshold. Observe that command-line parameters always arrive in a program as strings. Call the function with the parameters, and print the results.

Make sure your script works for arbitrary words and score thresholds. Here are the results from runs with two different words and thresholds:

Shell
> ruby top_rhymes.rb muscle 300
mussel
bustle
rustle
hustle
tussle
tousle
phrasal
> ruby top_rhymes.rb crinkle 260
wrinkle
tinkle
winkle
sprinkle
twinkle
periwinkle
incl
single
mingle
shingle
jingle
tingle
dingle
commingle
surcingle
intermingle

Bounds

Games devote considerable processor time to detecting collisions between objects. One way to speed up collision detection is to treat each complex shape on the screen as a simple box. Detecting if two boxes collide is much faster than detecting if two arbitrary shapes collide.

Write a Ruby program in bounds.rb that reads in a file of two-dimensional points, computes their bounding box, and prints some output that you can paste into Desmos to visually inspect the box. Follow these steps to get it up and running:

Write a Point class that has state for its x- and y-coordinates. Add getters and setters with as little work as possible.
Add a to_s method to Point to returns a string representation of the point in the form (X, Y), which is the format that Desmos expects of points.
Read in a file of points formatted like this:
5,8
-10,0
3,-3
2,7
-4,1
...
Replace each x- and y-coordinate with real numbers of your choosing. Give the file a name of your choosing. Use File.read to slurp up the file into a single string and then use the lines method the String class to break it up into lines. Turn the lines into instances of Point. Use an appropriate higher-order function. Don't use a loop or each. Ensure that your code will work with any number of points.
Write a Bounds class that has state for the minimum and maximum x- and y-coordinates it has seen so far. In other words, it tracks the coordinates of its left, right, top, and bottom edges. Initially it has no minimum or maximum.
Add an empty? method to Bounds that returns true if and only if no points have been added to the box.
Add an enclose method to Bounds that accepts a point as its only parameter. It grows the bounds as needed to enclose the given point.
Add a to_s method to Bounds that returns a Desmos-friendly format of the bounds. It lists the four corners in a comma-separated list that is assigned to a variable, say B, like this:
B = [(-10, -3), (5, -3), (5, 8), (-10, 8)]
If you paste the returned string into Desmos and then add another item with the text polygon(B), Desmos will draw a rectangle between the four corners.
Populate a new bounding box by adding your points one a time. Use an appropriate higher-order function. Do not use a loop.
Print the points in a string of the form [(5, 8), (-10, 0), ...].
Print the bounding box.
Paste the strings into this Desmos graph. Does the bounding box fit tightly around the points?

Submit

To receive credit for this lab, you must submit your two Ruby scripts on Canvas by Monday noon. Late labs or forgot-to-submits are not accepted because Monday at noon is when your instructor has time to grade.

← Lecture: Graphing Calculator