5.92

1 1/9: Classes and objects

Subversion test run: Assignment 0

Exercise 1. Find your homework partner

Exercise 2. Familiarize yourself with how we will use Git and GitHub

Exercise 3. Create and submit a dummy Assignment 0 with your homework partner:
  • Problem 1: Add some numbers together

  • Problem 2: Create an image

Setting up

To write object-oriented programs we will use a special dialect of Racket called class/0 that includes support for classes and objects. Just like we progressed through BSL, ISL, and ASL last semester, we will progress from class/0 on to richer object-oriented dialects as we learn more about how to program with objects.

To install the class/0 language in DrRacket, go to File → Install .plt File... → Web and copy in this URL:

http://www.ccs.neu.edu/course/cs2510hsp14/class-system-latest.plt

Once installed, use the class/0 language by selecting Language → Choose Language... → Use the language declared in the source. Then start your file with the following lines:

#lang class/0
(require 2htdp/image)
(require class/universe)

The #lang line tells Racket to use the class/0 language, and the two require lines load the image and universe libraries that we’ll use to create images and interactive programs.

Classes and objects

Here is an example class in Racket to represent balls that we can ask geometric questions of and draw to the screen.

; A Ball is a (new ball% Number Number Number Color)
(define-class ball%
  (fields x y radius color)
 
  ; -> Number
  ; The Ball's area
  (define (area)
    (* pi (sqr (send this radius))))
 
  ; Ball -> Boolean
  ; Do the Balls have the same radius?
  (define (same-radius? b)
    (equal? (send this radius) ; (How to access our own field)
            (send b radius)))  ; (How to access someone else's field)
 
  ; Ball -> Boolean
  ; Do the Balls have the same area?
  (define (same-area? b)
    (equal? (send this area)  ; (How to call our own method)
            (send b area)))   ; (How to call someone else's method)
 
  ; -> Image
  ; The image representing the Ball
  (define (draw)
    (circle (send this radius) "solid" (send this color))))

We can create and use Ball objects as follows:

> (define b (new ball% 50 25 10 "red"))
> b

(new ball% 50 25 10 "red")

> (send b x)

50

> (send b radius)

10

> (send b area)

314.1592653589793

> (send b same-radius? (new ball% 10 20 3 "red"))

#f

> (send b same-area? (new ball% 10 20 3 "red"))

#f

> (send b draw)

image

We can add new Ball behaviors by adding methods to the ball% class.

Exercise 4. Write a circumference method for the class ball% that calculates the Ball’s circumference.

Exercise 5. Write a distance-to method for the class ball% that takes another Ball and returns the distance between the centers of the two Balls.

Exercise 6. Write an overlaps? method for the class ball% that takes another Ball and determines whether the two Balls overlap.

Let’s construct another class to represent rectangles.

Exercise 7. Write a block% class to represent rectangular blocks on the screen. Include x and y fields to record its position, width and height fields to record its size, and a color field. Construct some examples of Blocks.

Exercise 8. Write a diagonal method for block% that calculates the length of the rectangle’s diagonal.

Exercise 9. Write a draw method for block% that returns an image representing the Block.

The World as an object

Recall how we used big-bang last semester:

; A World is a (make-world ...)
(define-struct world (...))
 
; tick : World -> World
(define (tick w)
  ...)
 
; draw : World -> Image
(define (draw w)
  ...)
 
(big-bang (make-world ...)
          (on-tick tick)
          (on-draw draw))

We would define functions to implement the various behaviors of the World and then pass each of them off to big-bang, along with an initial World value. In other words, big-bang needed a combination of structurethe initial World—and functionsthe various behaviors. But we know that

structure + functions = object

So here’s how we will use our new version of big-bang that expects just a single object:

; A World is a (new world% ...)
(define-class world%
  (fields ...)
 
  ; -> World
  (define (on-tick)
    ...)
 
  ; -> Image
  (define (to-draw)
    ...))
 
(big-bang (new world% ...))

big-bang is now a function that takes an object (here, (new world% ...)) which must respond to the to-draw method, and may respond to a handful of others, including on-tick, on-mouse, and on-keysee the big-bang docs for the full list. To create such an object, we define a class with the desired methods. Here we use the name world%, but you can call it anything you like.

Exercise 10. Using big-bang, create an animation where the user clicks to place Balls on the screen. Each click adds a Ball to the screen at the location of the mouse. For now, all the Balls can be the same color and size.

To use big-bang, you’ll need to construct an object, and to construct an object, you’ll need to write a class. Which fields and methods should you include?

Let’s add some variety by randomly selecting various aspects of what we put on the screen. Here are a few useful functions for choosing things randomly:

; random-between : Integer Integer -> Integer
; Randomly choose a number between a and b (inclusive)
(define (random-between a b)
  (+ a (random (+ 1 (- b a)))))
 
; choose : [Listof X] -> X
; Randomly choose an element from the list
(define (choose xs)
  (list-ref xs (random (length xs))))
 
; random-color : -> Color
; Randomly choose a color from a set of common colors
(define (random-color)
  (choose (list "red" "blue" "green" "yellow" "orange" "purple" "black")))

Exercise 11. Extend your animation so that when the user creates a Ball, its size and color of the Ball is chosen randomly.

Exercise 12. Modify your animation to use Blocks instead of Balls. Which methods need to change?

Exercise 13. Extend your animation to use Blocks and Balls—let’s call them, collectively, Creatures:

; A Creature is one of:
;  - Ball
;  - Block

When the user clicks, first randomly choose whether to create a Block or a Ball, and then randomly choose its parameters.

So far our animation isn’t very animate. Let’s teach our Creatures how to change over time.

Exercise 14. Add a step method to both Balls and Blocks. Sending step to a Ball should return a new Ball that has been moved or resized in some way, and sending step to a Block should return a new Block that has been moved or resized in some other way.

Exercise 15. Add an on-tick method to your class of Worlds that steps all of its creatures.

Now we have a basic framework for animating various kinds of Creatures. Unless you’ve done something strange, any objects that understand the x, y, draw, and step methods should slot in with minimal changes.

Exercise 16. (Open ended) Create new kinds of Creatures with new kinds of movement. Try some of these ideas:

  • speeding up over time

  • changing direction over time

  • moving randomly

  • moving randomly with a bias

  • gravitating toward a fixed point

  • gravitating toward each other

  • moving in circles

  • moving in spirals

If large numbers of off-screen or invisible Creatures are slowing down your animation, detect when they disappear and remove them.