CS2030 Practical Assessment #1

Back to homepage

We can better manage our lives by keeping track of a schedule of tasks. A task can be scheduled on a certain day, and within a time period. Recurring tasks can also be scheduled which occurs for a number of times based on a certain frequency. You may assume that all tasks are scheduled within a month.

Task

Your task is to manage single-session tasks, as well as recurring tasks within a planner.

Take note!

There are altogether five levels. You are required to complete ALL levels.

You should keep to the constructs and programming discipline instilled throughout the module.

You may assume that all tests provide valid arguments to methods; hence there is no need to validate method arguments.

Level 1

Write a class Task with a constructor that takes in three integers (the day, the start time and the end time) followed by a description of the task.

You will also need to include the following methods:

$ javac your_java_files
$ jshell your_java_files_in_bottom-up_dependency_order
jshell> Task t = new Task(1, 12, 14, "lunch with boss")
t ==> Task: 1,12,14,lunch with boss

jshell> t.edit(13, 14)
$.. ==> Task: 1,13,14,lunch with boss

jshell> t
t ==> Task: 1,12,14,lunch with boss

jshell> t = t.edit(13, 14)
t ==> Task: 1,13,14,lunch with boss

jshell> t.cancel()
$.. ==> Task: 1,13,14,lunch with boss[cancelled]

jshell> t.cancel().edit(12, 14)
|  Error:
|  cannot find symbol
|    symbol:   method edit(int,int)
|  t.cancel().edit(12, 14)
|  ^-------------^

jshell> t.cancel().cancel()
|  Error:
|  cannot find symbol
|    symbol:   method cancel()
|  t.cancel().cancel()
|  ^---------------^

Note that a cancelled task cannot be edited nor cancelled again.

Level 2

Define a RecurringTask class that creates a recurring task with a constructor that takes in a task, followed by the frequency and the number of occurrences.

The following example shows a recurrence of a weekly task (7 days) for four occurrences.

$ javac your_java_files
$ jshell your_java_files_in_bottom-up_dependency_order
jshell> Task t = new Task(1,12,14,"lunch with boss")
t ==> Task: 1,12,14,lunch with boss

jshell> new RecurringTask(t, 7, 4)
$.. ==> Recurring Task: 1,12,14,lunch with boss
#1:Task: 1,12,14,lunch with boss
#2:Task: 8,12,14,lunch with boss
#3:Task: 15,12,14,lunch with boss
#4:Task: 22,12,14,lunch with boss

Just like a normal task, a recurring task can be editted and cancelled:

jshell> RecurringTask rt = new RecurringTask(t, 7, 4)
rt ==> Recurring Task: 1,12,14,lunch with boss
#1:Task:  ... : 22,12,14,lunch with boss

jshell> t.cancel() // this is cancelling t, not rt!
$.. ==> Task: 1,12,14,lunch with boss[cancelled]

jshell> rt // rt is not affected by cancelling t!
rt ==> Recurring Task: 1,12,14,lunch with boss
#1:Task: 1,12,14,lunch with boss
#2:Task: 8,12,14,lunch with boss
#3:Task: 15,12,14,lunch with boss
#4:Task: 22,12,14,lunch with boss

jshell> rt.cancel()
$.. ==> Recurring Task: 1,12,14,lunch with boss[cancelled]

jshell> rt.cancel().cancel()
|  Error:
|  cannot find symbol
|    symbol:   method cancel()
|  rt.cancel().cancel()
|  ^----------------^

jshell> rt.cancel().edit()
|  Error:
|  cannot find symbol
|    symbol:   method edit()
|  rt.cancel().edit()
|  ^--------------^

jshell> rt.edit(11, 13)
$.. ==> Recurring Task: 1,11,13,lunch with boss
#1:Task: 1,11,13,lunch with boss
#2:Task: 8,11,13,lunch with boss
#3:Task: 15,11,13,lunch with boss
#4:Task: 22,11,13,lunch with boss

jshell> rt.edit(11, 13).cancel()
$.. ==> Recurring Task: 1,11,13,lunch with boss[cancelled]

Level 3

Rather than batch-editing or batch-cancelling all occurrences of a recurring task, we would like to edit or cancel one of them. We do that by specifying the index as the first argument to the cancel or edit methods:

The following shows how the single-argument cancel method works:

$ javac your_java_files
$ jshell your_java_files_in_bottom-up_dependency_order
jshell> Task t = new Task(1,12,14,"lunch with boss")
t ==> Task: 1,12,14,lunch with boss

jshell> new RecurringTask(t, 7, 4).cancel(1)
$.. ==> Recurring Task: 1,12,14,lunch with boss
#1:Task: 1,12,14,lunch with boss[cancelled]
#2:Task: 8,12,14,lunch with boss
#3:Task: 15,12,14,lunch with boss
#4:Task: 22,12,14,lunch with boss

jshell> new RecurringTask(t, 7, 4).cancel(1).cancel(1)
$.. ==> Recurring Task: 1,12,14,lunch with boss
#1:Task: 1,12,14,lunch with boss[cancelled]
#2:Task: 8,12,14,lunch with boss
#3:Task: 15,12,14,lunch with boss
#4:Task: 22,12,14,lunch with boss

jshell> new RecurringTask(t, 7, 4).cancel(1).cancel(3)
$.. ==> Recurring Task: 1,12,14,lunch with boss
#1:Task: 1,12,14,lunch with boss[cancelled]
#2:Task: 8,12,14,lunch with boss
#3:Task: 15,12,14,lunch with boss[cancelled]
#4:Task: 22,12,14,lunch with boss

When editing a single occurrence of a recurring task, we are allowed to edit the day, start time and end time.

jshell> new RecurringTask(t, 7, 4).edit(3, 10, 8, 10) // edit third occurrence to day 10, start 8, end 10
$.. ==> Recurring Task: 1,12,14,lunch with boss
#1:Task: 1,12,14,lunch with boss
#2:Task: 8,12,14,lunch with boss
#3:Task: 10,8,10,lunch with boss
#4:Task: 22,12,14,lunch with boss

jshell> new RecurringTask(t, 7, 4).edit(3, 5, 8, 10)
$.. ==> Recurring Task: 1,12,14,lunch with boss
#1:Task: 1,12,14,lunch with boss
#2:Task: 5,8,10,lunch with boss
#3:Task: 8,12,14,lunch with boss
#4:Task: 22,12,14,lunch with boss

Notice in the last test that editing the schedule of one occurrence of a recurring task may require the recurring tasks to be re-ordered in chronological order.

Moreover, unlike cancelling all occurrences of a recurring task, a specific occurrence of a recurring task that has been cancelled can be re-edited.

jshell> new RecurringTask(t, 7, 4).cancel(3)
$.. ==> Recurring Task: 1,12,14,lunch with boss
#1:Task: 1,12,14,lunch with boss
#2:Task: 8,12,14,lunch with boss
#3:Task: 15,12,14,lunch with boss[cancelled]
#4:Task: 22,12,14,lunch with boss

jshell> new RecurringTask(t, 7, 4).cancel(3).edit(3, 10, 8, 10)
$.. ==> Recurring Task: 1,12,14,lunch with boss
#1:Task: 1,12,14,lunch with boss
#2:Task: 8,12,14,lunch with boss
#3:Task: 10,8,10,lunch with boss
#4:Task: 22,12,14,lunch with boss

Here is what happens when we try to cancel/edit one occurrence of a recurring task that has already been batch-cancelled via cancel().

jshell> new RecurringTask(t, 7, 4).cancel(3).edit(3, 10, 8, 10).cancel().edit(1, 2, 3, 4)
|  Error:
|  cannot find symbol
|    symbol:   method edit(int,int,int,int)
|  new RecurringTask(t, 7, 4).cancel(3).edit(3, 10, 8, 10).cancel().edit(1, 2, 3, 4)
|  ^-------------------------------------------------------------------^

jshell> new RecurringTask(t, 7, 4).cancel(3).edit(3, 10, 8, 10).cancel().cancel(1)
|  Error:
|  cannot find symbol
|    symbol:   method cancel(int)
|  new RecurringTask(t, 7, 4).cancel(3).edit(3, 10, 8, 10).cancel().cancel(1)
|  ^---------------------------------------------------------------------^

The last example below shows the effect of batch editing after a single occurrence cancel/edit. Notice that edit is based upon the original specification of the recurring task.

jshell> new RecurringTask(t, 7, 4)
$.. ==> Recurring Task: 1,12,14,lunch with boss // this is the original specification
#1:Task: 1,12,14,lunch with boss
#2:Task: 8,12,14,lunch with boss
#3:Task: 15,12,14,lunch with boss
#4:Task: 22,12,14,lunch with boss

jshell> new RecurringTask(t, 7, 4).cancel(3).edit(3, 10, 8, 10).edit(14, 15)
$.. ==> Recurring Task: 1,14,15,lunch with boss
#1:Task: 1,14,15,lunch with boss
#2:Task: 8,14,15,lunch with boss
#3:Task: 15,14,15,lunch with boss
#4:Task: 22,14,15,lunch with boss

Level 4

Now let's plan our lives!

Write a Planner class with an empty constructor to create an empty planner. Include an add method to add a normal task or recurring task.

$ javac your_java_files
$ jshell your_java_files_in_bottom-up_dependency_order
jshell> Planner p = new Planner();
p ==> 

jshell> Task t = new Task(1,12,14,"lunch with boss")
t ==> Task: 1,12,14,lunch with boss

jshell> p.add(t)
$18 ==> 
Task: 1,12,14,lunch with boss

jshell> p
p ==> 

jshell> p = p.add(t)
p ==> 
Task: 1,12,14,lunch with boss

jshell> p = p.add(new Task(3,16,18,"dinner with spouse"))
p ==> 
Task: 1,12,14,lunch with boss
Task: 3,16,18,dinner with spouse

jshell> t = new Task(3,7,8,"fetch kids to school")
t ==> Task: 3,7,8,fetch kids to school

jshell> p = p.add(new RecurringTask(t,1,5))
p ==> 
Task: 1,12,14,lunch with boss
Task: 3,16,18,dinn ... 7,7,8,fetch kids to school

jshell> p = p.add(new Task(3,14,15,"nap").cancel())
p ==> 
Task: 1,12,14,lunch with boss
Task: 3,16,18,dinn ... sk: 3,14,15,nap[cancelled]

jshell> System.out.println(p.toString())

Task: 1,12,14,lunch with boss
Task: 3,16,18,dinner with spouse
Recurring Task: 3,7,8,fetch kids to school
#1:Task: 3,7,8,fetch kids to school
#2:Task: 4,7,8,fetch kids to school
#3:Task: 5,7,8,fetch kids to school
#4:Task: 6,7,8,fetch kids to school
#5:Task: 7,7,8,fetch kids to school
Task: 3,14,15,nap[cancelled]

There is no need to check for clashes (it just shows how hectic life can be). Moreover, cancelled tasks are also included.

Level 5

There are different ways to view the planner, say on a daily or weekly basis; here we shall just define a daily view.

An interface View is defined below:

interface View {
    void view(ImList<...> tasks); // the ... depends on your implementation
}
Define a class DayView with a constructor that takes in a particular day, and an implementation of the view method that provides a view of the daily schedule for that day. You should print out the tasks for that day in chronological order. You should also ignore all cancelled tasks.
$ javac your_java_files
$ jshell your_java_files_in_bottom-up_dependency_order
jshell> p.view(new DayView(3))
Task: 3,7,8,fetch kids to school
Task: 3,16,18,dinner with spouse