Programming Assignment 05: Scheduler

Estimated reading time: 10 minutes
Estimated time to complete: 2–3 hours (plus debugging time)
Prerequisites: Assignment 03
Starter code: scheduler-student.zip
Collaboration: not permitted

Overview

Common complaints among students are that SPIRE is awful, that setting up schedules is awful, and so on. Turns out, common complaints among registrars are that (name-of-University’s-registration-system) is awful, that setting up schedules is awful, and so on. So maybe you can do better?

In this assignment, you’ll write an automated course scheduler, which given a list of students and courses, does its best to put students into their preferred courses while not exceeding their maximum course load (and not exceeding the capacity of any courses).

We’ve provided a large set of unit tests to help with automated testing, though you might also want to write a class with a main method for interactive testing. The Gradescope autograder includes a few more tests, but they exist primarily to verify you’re not gaming the autograder. If your code can pass the tests we’ve provided, it is likely correct. As before, we’ve disable the timeout code so you can use the debugger, but if your code gets stuck during testing, you might want to uncomment these two lines at the top of each test file:

    @Rule
    public Timeout globalTimeout = Timeout.seconds(10); // 10 seconds

Goals

  • Translate written descriptions of behavior into code.
  • Practice writing instance methods.
  • Practice interacting with the List abstraction.
  • Test code using unit tests.

Downloading and importing the starter code

As in previous assignments, download and save (but do not decompress) the provided archive file containing the starter code. Then import it into Eclipse in the same way; you should end up with a dna-scheduler-student project in the “Project Explorer”.

What to do

As usual, look over the files we’ve provided. The Course class describes a course, including its name and maximum capacity. The Student class represents a single student, their maximum course load, and a list of courses the student would like (in order of preference, most-preferred-to-least). The Scheduler class is responsible for maintaining lists of students and courses, and for placing students into courses correctly.

You’ll need to write Course and Student before you tackle Scheduler. These should be straightforward. Notes:

  • A student’s preference list might be longer than their maximum load; that’s OK.
  • The only thing that might catch you by surprise is the requirement that when these classes return lists (like the Course.getRoster()) method, the returned list should not share state with the internal state of the Course. How do you guarantee this? By copying the internal state of the roster to a new list and returning the copy.

How can you make this copy? It depends. If your roster is built on the fly from other objects’ state, than the new list you build will automatically be independent. If the roster is a List instance variable, then copy it using the ArrayList‘s copy constructor.

Then move on to Scheduler. Some hints:

  • To implement drop and unenroll, you may need to add methods to Student and/or Course. Remember, it’s fine to do so (you can add methods, but you can’t change existing method signatures).
  • Read the comment for assignAll carefully, as correctly implementing the logic of the course assignment algorithm is the hardest part of this assignment.
  • Notice that there is no constraint on when scheduleAll can be run: it might happen after a student is dropped from a course, for example.

Take a look at SchedulerTest.testThree() to get a sense of how the scheduler works:

  • There are already three courses defined (a, b, and c, with capacities 2, 2, and 1, respectively). testThree also defines d and e with capacities 2 and 3, respectively.
  • There are three students, s, t, and u.

    • s wants courses a, b, c, d, e (in that order), up to a maximum load of 3 courses.
    • t wants courses c, a, d, e, b, up to 4.
    • u wants courses b, a, d, c, e, up to 5.
  • The scheduler gives each student one course (if possible) before giving each student a second course, and so on. So:

    • s gets added to a.
    • t gets added to c (which is now full).
    • u is gets added to b.

    At least one schedule was changed, so the scheduler continues:

    • s is already in a, and so gets added to b (which is now full).
    • t is already in c, and so gets added to a (which is now full).
    • u is already in b, cannot be added to a (which is full), and so is added to d.

    At least one schedule was changed, so the scheduler continues:

    • s is already in a and b, cannot be added to c (which is full), and so is added to d (which is now full.
    • t is already in c and a, cannot be added to d (which is full), and so is added to e.
    • u is already in b, cannot be added to a (which is full), is already in d, cannot be added to c (which is full), and so is added to e.

    At least one schedule was changed, so the scheduler continues:

    • s is at max load, so there is nothing to be done for s.
    • t is already in c and a, cannot be added to d (which is full), is already in e, and cannot be added to b (which is full) so there is nothing to be done for t.
    • u is already in b, cannot be added to a (which is full), is already in d, cannot be added to c (which is full), and is already in e, so there is nothing to be done for u

    Nothing was done this round, so the scheduler is done.

The test checks that the students have the right schedules, and that the courses have the right rosters.

Submitting the assignment

When you have completed the changes to your code, you should export an archive file containing the entire Java project. To do this, follow the same steps as from Assignment 01 to produce a .zip file, and upload it to Gradescope.

Remember, you can resubmit the assignment as many times as you want, until the deadline. If it turns out you missed something and your code doesn’t pass 100% of the tests, you can keep working until it does.