CPSC 124 Introduction to Programming Spring 2024

Lab 9
Writing Classes

Due: Tue 4/9 at the start of lab


Introduction

The bundling of subroutines and variables into modules known as objects is at the heart of object-oriented programming. Lab 8 focused on using already-written classes; in this lab you'll gain experience with writing classes of your own.

Collaboration

Labs and projects are for practice and learning. While it can be very productive to work on problems with your peers, it is also easy to underestimate how much you yourself understand and can do in such situations — so often something looks easy when someone else does it! With this in mind, you should always make the first attempt on a problem or programming task yourself using only the resources provided for the course (textbook, slides and examples posted on the schedule page, other resources linked on the course webpages). After that point, you are encouraged to come to office hours and/or go to Teaching Fellows. You may not collaboratively write solutions or code, and you may not copy solutions or code written by others, even if you contributed ideas.

You can discuss specific exercises with other students in general terms — such as how you might get started on that problem, or how or when to use various programming constructs, or strategies for debugging — but how to use a particular programming construct to solve a specific problem or debugging a particular program should only be discussed in office hours or with the Teaching Fellows.


Setup


API Documentation

API documentation for the provided classes can be found below:


Working With Multiple Files

As in lab 8, we're now working with programs that involve more than one file. Each .java file needs to be compiled in order for the program to run. There are several options for compiling multiple files:

Java will attempt to compile dependencies as needed — if you compile your main program, for example, and it involves other classes which have been updated since they were last compiled, those classes will be recompiled automatically when you compile the main program. Sometimes, though, Java can't figure out all the dependencies and you can get confusing results due to a mix of old and new versions, so it is recommended that you instead use one of the options above to explicitly compile everything needed.


Exercises

For all exercises:

Continue to write pseudocode (and to practice stepwise refinement in the development of your pseudocode) before writing Java. Also continue to practice incremental development — test as you go (using placeholder variables and subroutines as needed) rather than writing the whole program before you try to compile or run it for the first time.


Exercise #1

You have been provided with a file War.java (one of the files you copied) which implements the card game War. (This is similar to the BasicWar example from class, but includes all of the rules from the game instead of a simplified version.) To try the program out, compile War.java and run it.

Imagine that we want to modify the program so that each player has a name (other than "player 1" and "player 2"). In addition, we want to keep track of how many times each player wins a war during the game. You could do this by introducing four new variables: name1 and name2 for the names and numwins1 and numwins2 for the number of wins. But this gets to be a lot of variables, and there's a lot of duplication of effort because the same things are done for each player.

A better solution is to create a new type Player to bundle together everything that belongs to a player — name, hand, and number of wars won. The main program will then only need two variables to keep track of everything to do with the players: player1 and player2.

Player should have the following instance variables:

It should have a constructor which takes the player's name as a parameter and initializes the name instance variable accordingly. The constructor should also create a new empty hand for the player's hand, and should initialize the number of wars won to 0.

It should have the following methods:


Pong is one of the classic computer games. Dating back to 1972, it was one of the earliest arcade games and the first with widespread success. Pong simulates a game of table tennis — each player has a paddle and they try to hit the ball back and forth.

In the remaining exercises, you will implement a version of Pong.

You have been provided with two parts of this program: a main program in Pong.java and a class Bouncer.java which contains some functions for determining when the ball hits a paddle or wall.

Note: This program makes use of JavaFX, so remember that you need to compile with jfxc instead of javac and run with jfx instead of java.

To see how your program should work:

There is occasionally some odd bouncing behavior with the ball and paddle. Getting bouncing exactly right is tricky, so as long as your program generally works (i.e. the oddness is no more frequent than the demo), you're OK.

You should also notice that some messages are printed out to your terminal window when you run the program:

 *** using demo PongTable *** 
 *** using demo PongBall *** 
 *** using demo PongPaddle *** 
 *** using demo PongPaddle *** 

You'll be writing these classes in the exercises, but .class files were provided so that you can see how the program should work and so you can test your program as you go. The messages are printed to remind you that you are using provided versions of the classes instead of your own; they will go away as you compile your own versions.

Note: it is very important that you name your classes and methods as directed, and that you have the right header for each method. (i.e. the right types of parameters in the right order, and the right return type) If you don't, the provided code will not work! (You'll get compiler errors and possibly program crashes with NoSuchMethodError exceptions. If you get error messages you can't figure out, ask!)

Another note: You should include the lines

import javafx.scene.canvas.*;
import javafx.scene.paint.*;
import javafx.scene.input.*;

at the very beginning (before the public class part) of each class that you write. If you forget them, you will get "symbol not found" compiler errors. (VSCode may also "helpfully" add a different import, java.awt.Color, which will cause more compiler problems. If you notice that import has appeared in any of your files, delete it.)


Exercise #2

The PongPaddle class describes the paddles used in the Pong game.

PongPaddle should have instance variables for the following things:

All of these values should be doubles except for the color, which should be of type Color.

There should be a constructor which takes the paddle's position (x and y coordinates), dimensions (width and height), and color (type Color) as parameters. The instance variables should be initialized accordingly.

PongPaddle should also have the following methods:

When you are done, compile PongPaddle and then run the main program (Pong). If all is well, the program should work just like the demo version (check that the paddles are drawn in the right spot and that pressing the appropriate keys moves them correctly) and the "*** using demo PongPaddle ***" messages should have gone away.


Exercise #3

The PongBall class describes the ball used in the Pong game.

PongBall should have instance variables for the following things:

All of these values should be doubles except for the color, which should be of type Color.

There should be a constructor which takes the ball's position (x and y coordinates), radius, velocity (horizontal and vertical), and color (type Color) as parameters and initializes the instance variables accordingly.

PongBall should also have the following methods:

When you are done, compile PongBall and then run the main program (Pong). If all is well, the program should work just like the demo version (check that the ball is drawn in the right spot and that it moves and bounces correctly) and the "*** using demo PongBall ***" message should have gone away.


Exercise #4

The PongTable class coordinates all of the elements of the game.

PongTable should have instance variables for the following things:

Note that the ball and paddles will be objects (you just wrote those classes...), so choose the types accordingly. The width and height of the playing area should be doubles.

There should be a constructor which takes the width and the height of the playing area as parameters, and initializes those instance variables accordingly. The other instance variables will need to be initialized with new objects of the appropriate types: pass the right things to the constructors for those classes so that the ball has a radius of 4 and starts in the middle of the playing area (choose your own smallish values for the velocity), and the paddles have dimensions 10x50 and start in the middle of their respective sides of the playing area. You can choose your own colors, as long as the paddles and ball are all different colors.

PongTable should also have the following methods:

When you are done, compile PongTable and then run the main program (Pong). If all is well, the program should work just like the demo version (check that everything is drawn in the right spot, the ball moves and bounces correctly, and the paddles move correctly) and the "*** using demo PongTable ***" message should have gone away.


Handin and Grading

Don't forget to hand in your work when you are done!

As in lab 2 (and all labs), grading will be based on both functionality and style. Style means following the good programming style conventions outlined in lab 2, as well as producing reasonably compact and elegant solutions. "Reasonably compact and elegant" means that your program is not significantly longer or more complex than it needs to be. In particular, you must use loops when loops are appropriate — achieving repetition by copying-and-pasting a bunch of code will not earn credit.