Exercise 3: Simulation 3
- Deadline: 20 February 2024, Tuesday, 23:59 SGT
- Difficulty Level: 9
Prerequisite:
- Completed Exercise 2
- Caught up to Unit 25 of Lecture Notes
- Familiar with CS2030S Java style guide
Goal
This is a continuation of Exercise 2. Exercise 3 extends some of the requirements of Exercise 2 and adds new entities to the world that we are simulating. The goal is to demonstrate that, when OO principles are applied properly, we can adapt our code to changes in the requirements with less effort.
Lab 3 also involves writing your generic classes.
Extension 1: Queueing at The Counters
The Bank has now decided to streamline its operations. It rearranges the layout and makes some space for queues at the counters. With that, customers can now wait at individual counters.
In this lab, we will modify the simulation to add a counter queue to each counter.
The maximum queue length for each counter queue is \(l\). All counter queues are independent. Recall from Exercise 2 that the maximum queue length for the entrance queue is denoted as \(m\). \(m\) and \(l\) may be different.
When a customer arrives, a few scenarios could happen:
- If more than one counter is available, a customer will go to the counter with the smallest id (just like in Exercise 2)
- If none of the counters is available, but at least one of the counter queues is not full, the customer will join the counter with the shortest queue. If there are two counters with the same queue length, we break ties by going to the counter with the smaller id.
- If every counter queue has reached its maximum capacity of \(l\), but the entrance queue is not full, then the customer will join the entrance queue.
- If every counter queue has reached its maximum capacity of \(l\), and the entrance queue has reached its maximum capacity of \(m\), then the customer will leave.
When a counter is done serving a customer and becomes available, the customer at the front of its counter queue will proceed to the counter for service. This event frees up a slot in the counter queue. One customer from the entrance queue may join the counter queue of that counter. It takes 0.01 time unit for a customer to move from the entrance queue to the counter queue.
Note that, the entrance queue is empty unless all counters queues have reached the maximum length. Furthermore, a counter cannot "steal" a customer from another counter queue. Once a customer joins a counter queue, it cannot switch to another counter queue.
Extension 2: Withdrawal and Depositing Money
Recall that every customer comes into the bank with one of two tasks: withdrawal or deposit. In Exercise 3, we now simulate the following:
- Every customer arrives with a task to withdraw or deposit some amount of money.
- Every counter starts with an initial amount of money: $100.
- Each time a counter starts servicing a customer, the amount of money at that counter may increase or decrease. If the customer is withdrawing $\(x\), the amount of money at that counter decreases by \(x\). If the customer is depositing $\(x\), the amount of money at that counter increases by \(x\).
- A counter may not have enough money for withdrawal. If a customer wishes to withdraw more money than what is available at the counter, the withdrawal will fail. The amount of money at the counter does not change in this case.
Changes to Input
-
There is an additional input parameter, an integer \(l\), indicating the maximum allowed length of the counter queue. This input parameter should be read immediately after reading the number of bank counters and before the maximum allowed length of the entrance queue.
-
There is an additional input parameter at the end of each line in the input file that indicates the amount of money the customer is withdrawing or depositing. The new parameter is a positive integer.
Changes to Output
-
We now have two types of queues. If a customer joins the entrance queue, the customer along with the queue before joining should be printed as such:
1
1.400: C3 joined bank queue [ C1 C2 ]
-
Whenever we print a counter, we print the amount of money it has along with its counter queue.
1
1.200: C2 joined counter queue (at S0 $124 [ C1 ])
-
Whenever we print a task, we print the amount of money associated with the task.
1
6.000: C6 withdrawal $1 begin (by S0 $100 [ C9 ])
-
If a service is done successfully,
success
is printed. But if a service fails, i.e., when a customer wants to withdraw more money than what is available at the counter,fail
is printed.1 2 3
3.100: C1 withdrawal $80 begin (by S0 $110 [ ]) 5.100: C1 withdrawal $80 done (by S0 $30 [ ]) success 7.100: C2 withdrawal $50 done (by S0 $30 [ ]) fail
Skeleton for Exercise 3
We provide two classes for Exercise 3, the main Ex3.java
(which is simply Ex2.java
renamed) and Seq.java
. You should not edit Ex3.java
but you need to fill in the blanks for Seq.java
as described below.
We also provide three new classes for testing: CS2030STest.java
(which you should be familiar with from Exercise 0), SeqTest.java
, and QueueTest.java
. You should not edit these test files.
Building Upon Exercise 2.
You are required to build on top of your Exercise 2 submission for this lab.
Assuming you have ex2-<username>
and ex3-<username>
under the same directory, and ex3-<username>
is your current working directory, you can run
1 2 |
|
to copy all your Java code over.
If you are still unfamiliar with Unix commands to navigate the file system and to manage your files, please review our Unix guide.
You are encouraged to consider your tutor's feedback and fix any issues with your design for your Exercise 2 submission before you submit your Exercise 3.
Your Tasks
You have a few tasks to complete for Exercise 3. We suggest you solve this lab in the following order.
1. Make Queue
a generic class
The class Queue
given to you in Exercise 2 stores its elements as Object
references, and therefore is not type-safe. Now that you have learned about generics, you should update Queue
to make it a generic class Queue<T>
.
You are encouraged to test your Queue<T>
in jshell
yourself. A sample test sequence is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
The file QueueTest.java
helps to test your Queue<T>
class.
1 2 |
|
2. Create a generic Seq<T>
class
Let's call the class that encapsulates the counter BankCounter
(you may name it differently). We have been using an array to store the BankCounter
objects. In Exercise 3, you should replace that with a generic wrapper around an array. In other words, we want to replace BankCounter[]
with Seq<BankCounter>
. You may build upon the Seq<T>
class from the notes — Unit 25.
The Seq<T>
class you build must support the following:
-
Seq<T>
takes in only a subtype ofComparable<T>
as its type argument. That is, we want to parameterizeSeq<T>
with only aT
that can compare with itself. Note that in implementingSeq<T>
, you will find another situation where using raw type is necessary. You may, for this case, use@SuppressWarnings("rawtypes")
at the smallest scope possible to suppress the warning about raw types. -
Seq<T>
must support themin
method, with the following descriptor:1
T min()
min
returns the minimum element (based on the order defined by the compareTo
method of the Comparable<T>
interface).
Seq<T>
supports atoString
method. The code has been given to you inSeq.java
.
You are encouraged to test your Seq<T>
in jshell
yourself. A sample test sequence is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
|
The file SeqTest.java
helps to test your Seq<T>
class.
1 2 |
|
3. Make Your BankCounter
Comparable to Itself
Your class that encapsulates the bank counter must now implement the Comparable<T>
interface so that it can compare with itself and it can be used as a type argument for Seq<T>
.
You should implement compareTo
in such a way that counters.min()
returns the counter that a customer should join (unless all the counter queues have reached maximum length).
4. Update Your Simulation
By incorporating Queue<T>
, Seq<T>
, BankCounter
, modify your simulation so that it implements the extensions and changes described above.
Following CS2030S Style Guide
Like Exercise 2, you should also make sure that your code follows the given Java style guide
Assumptions
We assume that no two events involving two different customers ever occur at the same time (except when a customer departs and another customer begins its service, or when a customer is done and another customer joins the counter queue from the entrance queue). As per all exercises, we assume that the input is correctly formatted.
Compiling, Testing, and Debugging
Compilation
To compile your code,
1 |
|
To check for style,
1 |
|
Running and Testing
You may test your simulation code similarly to how you test your Exercise 2.
Note that test cases 1 to 10 set \(l\) to 0, so there is no counter queue. Test cases 11 and 12 set \(l\) to non-zero and \(m\) to 0, so there is no entrance queue. Test cases 13 and 14 test scenarios with both entrance and counter queues.