Assignment U3#
Applies to: | COMP1110 |
Released by: | Monday, 07 April 2025, 09:00 |
Base assignment deadline: | Friday, 18 April 2025, 15:00 |
Code Walk registration deadline: | Friday, 18 April 2025, 18:00 |
Code Walk registration link: | CWAC |
Code Walks: | Thursday, 24 April 2025
|
GitLab template repository: | (link) |
GitLab CI file: | .gitlab-ci.yml |
Last Updated: | Thursday, 17 April 2025, 20:45 |
This assignment uses regular Java 23, and JUnit Jupiter 5.9.0. You may optionally import the Functional Java Standard Libraries. Do not import other libraries into your project. Your code may not:
- Explicitly throw exceptions.
- Catch exceptions outside of the allowed pattern for reading/writing files (see Slides of Workshop 6B).
- Use concurrency (if you do not know what that is, you will not be using it so long as you write the code on your own).
- Use reflection (if you do not know what that is, you will not be using it so long as you write the code on your own).
- Interact with the environment outside of the file system operations described on the Slides of Workshop 6B.
- Write to or read from files other than described in the assignment.
In everything you do, you must follow the Design Recipe. The minor adjustments to the Design Recipe for class definitions are available in Slides of Workshop 6B To see roughly how this assignment will be marked, check out the Skeleton Rubric.
You still need to follow the Design Recipe and write appropriate documentation and tests. In particular, the (minor) adjustments to the Design Recipe for class definitions were covered in workshop 6B. Do not write code that is overly complicated.
Formalities#
This assignment is submitted via GitLab.
Access to Your Repository#
In order for us to be able to collect and mark it, you need to satisfy the following conditions:
- Your repository’s name must be
comp1110-2025s1-u3
(exactly), placed directly in your user namespace (the default). That is, if your uid isu1234567
, the address of your GitLab project should read ashttps://gitlab.cecs.anu.edu.au/u1234567/comp1110-2025s1-u3
. - Your repository must have our marker bot (
comp1110-2025-s1-marker
) added as aMaintainer
.
You can achieve both these points by creating your project through forking our template repository and not changing the name, or by just using the correct name when creating the project and then manually adding the bot.
Notebooks and Push Requirement#
You need to keep a notebook file as explained on the Git and Notebooks page. You need to commit and push the current state of your files:
- at the end of every session where you work on the assignment
- at least once per hour (our checks implement this that no two pushes during sessions recorded in the notebook are more than 70 minutes apart).
- at least once per major part of the assignment (i.e. for this assignment, at least four times). You are absolutely free to commit and/or push more often than that.
You need to write informative commit messages, and informative notes for each session in your notebook, which describe what it is that you did for this particular commit or session, respectively.
Statement of Originality#
Your submission (and therefore your git repository) needs to include a signed statement of originality.
This must be a text file named soo.txt
.
That file must contain the following text, with the placeholders [your name here]
and [your UID here]
replaced with your name and UID (remove the brackets!), respectively:
I declare that this work upholds the principles of academic
integrity, as defined in the University Academic Misconduct
Rule; is entirely my own work; is produced for the purposes
of this assessment task and has not been submitted for
assessment in any other context, except where authorised in
writing by the course convener; gives appropriate
acknowledgement of the ideas, scholarship and intellectual
property of others insofar as these have been used; in no part
involves copying, cheating, collusion, fabrication, plagiarism
or recycling.
I declare that I have not used any form of generative AI in
preparing this work.
I declare that I have the rights to use and submit any assets
included in this work.
[your name here]
[your UID here]
Files Summary#
Your repository must be accessible to us and must have the following structure:
notebook.yml
- your Notebooksoo.txt
- your signed Statement of Originalitysrc
- a folder containing your source files:Article.java
- containing your work for part 1Group.java
- containing your work for part 2Cart.java
- containing your work for part 3Loader.java
- containing your work for part 4
tests
- a folder containing your test files:ArticleTests.java
- containing your tests for part 1GroupTests.java
- containing your tests for part 2CartTests.java
- containing your tests for part 3LoaderTests.java
- containing your tests for part 4
Project Configuration and Running Programs#
We recommend that you use IntelliJ IDEA for this assignment. However, you do not have to. If you do, the standard settings that result from following the IntelliJ Project Setup Guide should make your project work with our testing environment.
If you do not want to (or cannot) use IntelliJ IDEA, or if you want to make sure you can run your program like our automated testing framework, then you can follow the guide available here. This will allow you to trigger your tests directly from the console, in a similar way we did in the first half of the course with the functional Java library support for tests.
Info: Java Standard Libraries#
Part of this assignment asks you to do things for which there are operations in the Java Standard Libraries. Consider particularly looking at the following pages:
Tasks#
As a a general rule in this assignment, you do not need to come up with examples or write tests for methods whose name starts with “get”, except if you have any sort of complicated logic in them. You may of course use them in your tests of other methods.
Pre-Assignment Exercise#
This exercise is purely optional, but doing it may come in handy later in the assignment, especially if you feel more comfortable with the Functional Java Standard Libraries.
In a file called src/Util.java
Create a class called Util
.
In it, design the following class static method.
/**
* Returns an array that has the same length as the given list,
* and contains the elements of the list in reverse order.
* Examples:
* - Given: Nil()
* Expect: a String array of length 0
* - Given: Cons("hello", Cons("world!", Nil()))
* Expect: a String array arr of length 2,
arr[0] = "world!", arr[1] = "hello"
*/
static String[] consListToReverseArray(ConsList<String> list)
Follow the Design Recipe!
You may also consider writing a version of this method that does not reverse the order of elements, or versions that work on other kinds of lists or arrays, as might be required for the rest of the assignment tasks. For reasons that are somewhat unique to Java and Java-based languages, it is not easy to write a generic version of this method. Unless you already know how about this, don’t try to do it!
Note: it is easy to transform an array into a ConsList
- MakeList
does that!
Part 1#
In a file called src/Article.java
Part 1 is a regular part of the assignment and will be included in marking it. However, it is designed as an on-ramp. Tutors may help you with the code here if you ask for help - though you should still try to do as much as possible yourself.
Different computer programs often need to exchange information, possibly when they are executed on different computers. The so-called file formats facilitate this data sharing process. A file format is an standardized set of rules that establishes how data must be laid out in a file. Adhering to a file format, the programs agree on a common way to represent data in files, reducing the possibility that errors occur in the data exchange process.
Knowing in advance the file format of a file to be processed (read and/or written) in a computer program is essential, as the file format will determine the shape of the programming language instructions that are needed to process (a.k.a. parse in computer science parlance) or generate files in such a format.
One important kind of (text) file format is called “Comma-Separated Values”, or CSV in short.
This file format is for tabular data, where each line represents a row in the table, and the columns are separated by commas
(i.e., the character ','
). For this assignment, for simplicity, we will use a simplified version of this format where we
assume that text data never contains a comma, a newline, or quotation marks.
You can also assume that any column that contains numeric data can be parsed with Integer.parseInt
, and that data will have no leading or trailing spaces, and that all rows have the same number of columns (and no missing data).
Those assumptions of course only hold for files given to you by our tests - where it is you that generates a file, you need to make sure you can read it again.
You may have previously seen spreadsheet files (e.g., Microsoft Excel spreadsheets), which often come with a header label for each column in the first row, describing the data in the respective column. In the actual CSV format, this is not strictly necessary, but for the purposes of this assignment, we’ll assume that the CSV files that we are dealing with always have header labels. Here is an example file, which we will use in this part:
Name,Price
Banana,200
Strawberry,100
Rolls,500
Steak,1000
Apple,300
Toilet Paper,700
The above is a file that adheres to our simplified version of CSV format, with two columns, labelled as “Name”, and “Price”.
For this part of the assignment, we will assume that names always come first, followed by prices.
It has six data entries for different articles with different names and prices. The file has seven lines overall, plus a newline (and thus an empty line) at the end. Prices are stored as integers in cents, to avoid rounding errors that come in with using double
s or float
s. You can also see in this example that neither the data in the column labelled as “Name” nor the one labelled as “Price” contains a comma, a newline, or quotation marks.
Create a class called Article
to model the above data.
You must design at least the following members, as these are the ones that we will subject to automatic testing:
// Here, File refers to java.io.File.
// Make sure to use to right import!
/**
* Returns the name of the article
*/
String getName()
/**
* Returns the price of the article
*/
int getPrice()
/**
* Constructs a new Article given a name and a price
*/
Article(String name, int price)
/**
* Given a CSV file of the above format,
* with Names first and Prices second,
* as described in the header,
* reads in all the articles in the file
* and returns an array that contains them
*/
static Article[] readArticles(File file)
Follow the Design Recipe!
Part 2#
In a file called src/Group.java
One nice thing about headers is that a CSV file can contain more data than you care about. Besides, different files may contain the columns in a different order. Your code can cope with arbitrary orderings of the columns if you look at the header labels first to deduce which columns you need to look at in future lines.
In this part, we’ll deal with groups of articles, which are read from CSV files that look as follows:
Price,Group,Name
200,Fruit,Banana
100,Fruit,Strawberry
500,Bread,Rolls
1000,Meat,Steak
300,Fruit,Apple
700,Hygiene,Toilet Paper
These files may have their columns in arbitrary order, and may also have additional columns with more data. Thus, for example, we may also test the code in Part 2 with a CSV file which looks as follows:
Group,Name,Price,Instock
Fruit,Banana,200,Y
Fruit,Strawberry,100,Y
Bread,Rolls,500,N
Meat,Steak,1000,N
Fruit,Apple,300,Y
Hygiene,Toilet Paper,700,Y
You can also assume, for simplicity, that two different columns cannot have the same label. For the purposes of this assignment, you can assume that each article name only occurs once in the articles CSV file.
Create a class called “Group” to model groups of articles.
You must design at least the following members, as these are the ones that we will subject to automatic testing:
// Here, File refers to java.io.File,
// and Article refers to your Article class
// from Part 1.
// Make sure to use to right import!
/**
* Returns the name of the group
*/
String getName()
/**
* Returns the articles in this group
*/
Article[] getArticles()
/**
* Returns the average price of articles
* within the group, rounded down
*/
int getAveragePrice()
/**
* Creates a new group with a given name containing
* the given articles
*/
Group(String name, Article[] articles)
/**
* Given a CSV file of the format described above, loads
* the articles and groups from the file and returns
* the groups.
*/
static Group[] readGroups(File file)
Follow the Design Recipe!
Part 3#
In a file called src/Cart.java
, and with edits to src/Group.java
Different groups of articles may have different tax rates associated with them. We’ll assume a standard tax rate of 10%. Article groups that have a different rate will have an entry in a separate CSV file, giving the rate in centi-percent, i.e. 1000 means 10%.
Group,Tax Rate
Fruit,0
Meat,1500
Combined with the file above, this would mean that the “Fruit” group is taxed at 0%, “Meat” is taxed at 15%, and the “Bread” and “Hygiene” groups are taxed at 10% (i.e., the standard tax rate). For the purposes of this assignment, you can assume that each group name only occurs at most once in the tax rate CSV file.
Add the following members to the Group
class from Part 2:
/**
* Returns the tax rate for this group in centi-percent
*/
int getTaxRate()
/**
* Adjusts the tax rates of the given groups based on
* entries in the given tax rate file, which has
* the format described above (but may also have additional
* columns, and have columns in an arbitrary order)
*/
static void adjustTaxRates(Group[] groups, File taxRateFile)
Additionally, design a new class Cart
, representing a shopping cart.
Carts are also stored in CSV files, but this time, a CSV file represents a single cart, with potentially multiple entries.
We’ll read and write carts from a particular folder.
Each cart has an ID, and carts will be stored in files named [ID].csv
. For example, the cart with ID 5 is stored in 5.csv
.
You can decide on how to exactly name and order the columns in the CSV file.
You must design at least the following members, as these are the ones that we will subject to automatic testing:
/**
* Returns the ID of the cart
*/
int getID()
/**
* Returns the distinct kinds of articles that
* are in the cart in non-zero amounts, in
* arbitrary order
*/
Article[] getArticlesInCart()
/**
* Returns how often a given article is in the cart,
* 0 if it is not in the cart at all
*/
int getArticleCount(Article article)
/**
* Returns the total tax to be paid for the articles
* in the cart, based on their groups' tax rates,
* in cents.
* The tax to be paid for a single item of an
* individual article is calculated as:
* ([Price] * [TaxRate]) / 10000
* This means taxes in our scheme are always rounded
* down.
*/
int taxAmount()
/**
* Returns the total amount to be paid for the cart,
* including the sum of the articles' prices, and
* the tax to be paid on them, in cents.
* For the purposes of this function, the total
* cost of each item for each article is
* ([Price] * (10000 + [TaxRate])) / 10000
* This means taxes in our scheme are always rounded
* down.
*/
int cartTotal()
/**
* Creates a new empty cart with a unique ID
*/
Cart()
/**
* Adds a single item of an article to the cart
*/
void addArticle(Article a)
/**
* Removes up to a certain number of items of
* a certain article kind from the cart, as many
* as possible (i.e. if there are fewer than count
* items of the given article in the cart, the
* new count is 0)
*/
void removeArticles(Article a, int count)
/**
* Given a directory in which carts are stored,
* saves the current state of the cart to
* an appropriately named file ("[ID].csv") in
* the directory, overriding a potentially
* existing file for that same cart
*/
void storeCart(File directory)
/**
* Given a directory in which Cart data is stored,
* and an existing list of articles, loads the carts
* from the CSV files in the directory
*/
static Cart[] loadCarts(Article[] articles, File directory)
Follow the Design Recipe!
Don’t assume that what we are doing here is enough to build an actual system for tax invoices! Consult accountants and tax lawyers about the rules around these things, especially with respect to rounding, if you are building such a system.
Part 4 (Distinction-Level Part)#
In a file called src/Loader.java
Create a class that abstracts the CSV-loading process from the earlier parts.
Call this class Loader
.
You must design at least the following members, as these are the ones that we will subject to automatic testing:
/**
* Reads the given CSV file, and creates a HashMap<String,String>
* for each line in the file that contains actual data (i.e. excluding
* the header and any empty lines). The HashMap associated to a line,
* uses the column header labels as keys, and the actual data
* stored in the columns of that line as the associated values.
* The method then calls elementFactory with that HashMap in order
* to create a new element of the given type. Returns an array of the
* same size as there are data lines in the CSV file, filled with the
* entries based on the lines. Because of Java's restrictions, you
* need to pass in a function makeArray that returns an array of
* the given size for the right type.
*/
static <T> T[] loadCSV(File file, Function<Integer, T[]> makeArray, Function<HashMap<String, String>, T> elementFactory)
/**
* The same method as from before, but using loadCSV
*/
static Article[] readArticles(File file)
/**
* The same method as from before, but using loadCSV
*/
static Group[] readGroups(File file)
/**
* The same method as from before, but using loadCSV
*/
static void adjustTaxRates(Group[] groups, File taxRateFile)
/**
* The same method as from before, but using loadCSV
*/
static Cart[] loadCarts(Article[] articles, File directory)
Follow the Design Recipe!
Updates#
Sunday, 13 April 2025, 08:55 | Fixed signature of loadCSV method |
Thursday, 17 April 2025, 20:45 | added CI file |