CS 201 - Homework 3 - Interfaces and Vectors

Due: Wednesday 10/3 at 8am

This assignment has a programming problem with two parts. When you are done, submit your programs (CircularVector.java and Josephus.java) using the HW 3 submission page.

Lab exercises

There are no specific exercises this week. You can use the lab time and our help to:


This week's programming assignment is to solve the "Josephus" problem. A messenger is to be chosen from a group of people. Since the mission is dangerous, the messenger is to be chosen randomly. The technique chosen is to arrange everyone in a circle. Pick a number n. Now count off n people, and remove the n+1st from the circle. Continue counting off until only 1 person is left. That person is the messenger. (The original "historically correct" version is bloodier. This is the PG version!)

There are two parts to this assignment.


First, you will need to provide the code for the data structure that handles all of the people. To do this, you are supposed to provide a class named CircularVector that implements the interface Circular as given in the file Circular.java.

Start by creating a new directory hw3 in your cs201 directory, and save the file Circular.java there. Then, create a new file CircularVector.java, and paste in the following skeleton:

// Don't forget comments!

// to tell java where to find the Vector class, use ONE of following two import statements:

//import java.util.Vector; // get it from java.util

import structure.*; // get it from Bailey's structure package
  // if this causes problems, see Lab 1, exercise 0.
  // ask a tutor for help if necessary

public class CircularVector implements Circular

    // add your code here

    // useful shorthand for System.out.println to save some typing
    public static void p(String s) {

    // use a main method like the following to test your implementation:
    public static void main(String[] args) {
        p("creating new circular vector");
        Circular myList = new CircularVector();
        p("size is " + myList.size());
        p("adding 7");
        p("adding 8");
        p("calling next");
        p("current is now " + myList.getCurrent());

        // add more code to *thoroughly* test all methods!

Your implementation should include two instance variables: list, a vector to hold all people, and current, an integer that specifies which element of the vector corresponds to the person in the circle who is currently being pointed at. You'll also need to define a constructor without parameters that initializes the instance variables properly.

Virtually all of the operations of the class are specified relative to the current element. For example next moves the current element to refer to the next person (if the current person is last in the vector, then current must shift to the element at the beginning of the list: 0). The other operations should be clear from their names and the pre and post-conditions given for them. Notice that it is quite important what happens to the current indicator after each operation. For example, after removeCurrent(), the current element becomes the element after the one removed (unless the list becomes empty, in which case there is no current element - indicated by setting current to -1).

Note: If you import Vector from java.util, you will get compiler warning messages about "unchecked conversions" once you add code to store Objects in the Vector (e.g., via commands like list.add(obj); ). You can safely ignore such warnings -- we will soon see how we can use "generic" types to avoid this issue. If the warnings bother you, you have two options to get rid of them: either use Bailey's Vector (using "import structure.*;"), or declare the Vector explicitly to hold Objects, by replacing all instances of "Vector" with "Vector<Object>".

To help you test your implementation, I'm providing additional testing code: CircularVectorTest.java. Save this file in your HW 3 folder alongside your CircularVector implementation, compile it, and run it. If you get any output "*** ... expected", e.g.,

     next, current = 9 *** 7 expected
then you know you still have bugs.


Once you have written and thoroughly tested the CircularVector class, you will write a class Josephus that will run a simulation of the Josephus problem. The class should have two instance variables - an int to hold the number to be skipped, and a Circular structure to represent the circle - and should provide the following constructor and instance method:
   // constructor:
   public Josephus(int numPeople, int numToSkip)
   // Pre:   numPeople and numToSkip are both >= 1
   // Post:  Initializes the instance variables to set up 
   //  the "circle" of potential messengers.  Make sure
   //  the "current" number of the circle is 0 (i.e. the first person).

   // instance method:
   public void findMessenger()
   // Pre:   A Josephus problem has been set up, with at least one potential
   //  messenger.
   // Post:  Messenger selected has been displayed on the screen; those
   //  not selected have had their names printed in the order in which they
   //  were excluded.
Test your implementation using a main method that creates a new object of type Josephus, initialized (using the constructor) with two numbers supplied by the user via command-line arguments. If fewer or more than 2 command-line arguments are given, the program should explain its usage. Otherwise, the object's findMessenger method should be called in order to run the simulation. Here are some sample runs:
    > java Josephus 
      usage: Josephus <numPeople> <numToSkip>

    > java Josephus 3 4
    Solving Josephus problem with 3 people, skipping 4
    Skip 1
    Skip 2
    Skip 3
    Skip 1
    Remove 2
    Skip 3
    Skip 1
    Skip 3
    Skip 1
    Remove 3
    The messenger is 1

    > java Josephus 17 3
    Solving Josephus problem with 17 people, skipping 3
    Skip 1
    Skip 2
    Skip 3
    Remove 4
    Skip 5
    Skip 5
    Remove 6
    The messenger is 5
Remember that the command-line arguments are strings. To convert them to integers, use something like
    int num = Integer.parseInt(args[0]);