COMP122 Assessment 3 Due 2021-05-07 at 5pm
Exceptional Press
Book
-title: String
-author: String
-content: String
-edition: int
+getTitle(): String
+getAuthor(): String
+String getContent()
+getEdition(): int
+Book(String t, String a, String c, int e)
+getPages(): int
+toString(): String
Press
-booksPerEdition: int
-edition: Map<String,Integer>
-shelf: Map<String,Queue<Book>>
+Press(String p, int n)
+print(String id, b): List<Book>
+getCatalogue() List<String>
+request(String id, n) List<Book>
VendingMachine
-supplier: Press
-locationFactor: double
-cassette: double
+VendingMachine(Press p, double f)
+getCassette(): double
+insertCoint(double c): void
+returnCoins(): double
+buyBook(String id): Book
During the pandemic you realised that lots of people are looking for books to read but are reluctant
to throw their money at large online corporations while shops are closed. So you came up with the
idea to re-print old classics whose copyright has expired and sell them o vending machines that you
put up where once public libraries stood. In this assignment you’ll implement three aspects of this
endeavour: You will model books, the press, and vending machines.
Part 1: Books
We’ll need a data structure to represent an individual Book. Write a class called Book as follows.
There should be string attributes called title, author, and content as well as an integer attribute
called edition. Since we want readers to be able to see but not change the respective values of a
book, all these fields must be declared private and your class should have accessor-methods for
each of them. That is, your class should have public methods called getTitle, getAuthor, and
getContent that take no arguments and return a String, namely the unchanged value of their
respective attribute. Similarly, there must be a method public int getEdition() that returns the
edition of the book.
Your class must feature a constructor method that accepts and stores initial values for these four
attributes in the order they are mentioned above.
1 public Book(String t, String a, String c, int e)
In order to implement our innovative pricing model each book should be able to report on its content.
Let’s assume the that the layout of our books is such that it fits 800 characters on every page. Add
a (public) method called getPages that takes no arguments and returns the number of pages the
1
COMP122 Assessment 3 Due 2021-05-07 at 5pm
book has as an int. That is, it returns the integer corresponding to the number of characters in the
books content string divided by 800 and rounded up if necessary.
Finally, in order to nicely present the book on a shelf, overload the toString() method to return
title, author, edition, as well as the number of pages in this order. Each should appear in one line and
prefixed with the capitalised name of the attribute followed by a colon and one space. Each line should
end in a newline character ‘\n’ directly aer the last printable character. See below for an example
output String.
Title: Treasure Island
Author: Robert Louis Stevenson
Edition: 1
Pages: 209
Part 2: The Press
Write a class called Press that can be used to create books.
The books we’ll create are going to be re-prints of famous volumes whose copyright has expired. We can
get them as (UTF8 encoded) text files from Project Gutenberg and a selection can also be downloaded
from Canvas for testing. When we instantiate a Press object we’ll be given a path to a directory that
contains several such text files. We’ll assume for simplicity that each kind of book in print is identified
by the name of the text file it is read from, e.g. “120-0.txt”. Such a“bookID”string should include
the suix“.txt”but no preceding directory name.
As it is cumbersome and costly to reconfigure our press when switching to a new book, we’ll print
books in batches and store them until they are distributed to our vending machines. Our press should
therefore have several shelves, one for each kind of book. If someone wants to take out n copies of
a book, we will give them the first n from the shelf. If there are fewer than that many le we print
new ones (with a new“edition”number), add them to the end of the shelf and give out the requested
number of books. Since storage space is expensive there is an fixed number of books each edition will
have. This number is stored in a private field of each Press object and fixed upon instantiation. We
can assume that no user wants to take out more than that many books.
Setting up the press
Your Print class needs to have private attributes as follows.
• an integer called booksPerEdition. Each new edition will have that many books.
• the most recent edition of each book. This should be stored as a map from“BookID”strings
into an integers. That is, there should be a single private attribute called“edition”of type
Map<String, Integer>.
2
COMP122 Assessment 3 Due 2021-05-07 at 5pm
• a shelf to store books. This should be implemented as a map from“BookID”strings into a
queue of Books. That is, there should be a single private attribute called“shelf”that has type
Map<String, Queue<Book>>.
You may add other private attributes to make things work, for example to store the content of each
text file so that you do not need to read it again and again. We will not look at these attributes when
testing and grading your code.
Your class should have a constructor method that takes 1. a (String) path to the directory containing
books as text files, 2. the (int) number of books printed per edition. This should set up the data
structures mentioned above and trigger a first printing run of all books.
1 public Press(String pathToBooKDir, booksPerEdition)
For example, suppose that we instantiate a press as new Press(“mybooks”, 3) and the directory
“mybooks”contains three files called“11-0.txt”,“120-0.txt”, and“12-0.txt”. Then the newly instantiated
Press object should contain
• as shelf attribute, that maps“11-0.txt”to a Queue containing three distinct first edition Books
whose content (and title, author) is read from that file, and similarly for the other two file names.
• as edition attribute, that maps from all three strings to the integer 1 (because we already
printed one edition of each book to fill the shelf).
Printing books
In order to instantiate a single book we need to read the respective text file and extract title, author and
content. Luckily, all these text files have a similar header in the first few lines that contains that info.
They all start in “The Project Gutenberg “, list a few properties such as title, author, language
and so on. Then there is a line that starts with “* START OF” that ends the header and marks the
beginning of the book’s content. For example, here are the first 23 lines of“120-0.txt”.
1 The Project Gutenberg EBook of Treasure Island, by Robert Louis Stevenson
2
3 This eBook is for the use of anyone anywhere in the United States and most
4 other parts of the world at no cost and with almost no restrictions
5 whatsoever. You may copy it, give it away or re-use it under the terms of
6 the Project Gutenberg License included with this eBook or online at
7 www.gutenberg.org. If you are not located in the United States, you’ll have
8 to check the laws of the country where you are located before using this ebook.
9
10 Title: Treasure Island
11
12 Author: Robert Louis Stevenson
13
14 Illustrator: Louis Rhead
3
COMP122 Assessment 3 Due 2021-05-07 at 5pm
15
16 Release Date: March 13, 1994 [EBook #120]
17 [Most recently updated: October 28, 2020]
18
19 Language: English
20
21 Character set encoding: UTF-8
22
23 START OF THIS PROJECT GUTENBERG EBOOK TREASURE ISLAND
Everything from (and including) line 24 to the end of the file we’ll consider the content of the book.
This is likely going to start with a few blank lines. You will need to write some code that opens a text
file and extracts title, author and content strings and then uses your four-argument constructor for the
Book class to instantiate one or more books of this kind.
For this purpose, your Press class should have a public method called print that can be used to
print a whole batch of books at once.
1 public List<Book> print(String bookID, n)
This method should instantiate n books from the text file whose name is given as the string parameter
bookID and return a list that contains these n books. The edition of all new books should be the same
as the new value of edition attribute of our press (for the given bookID), which of course should be
one higher than it was before this printing process.
If the requested book is not in print, i.e. the string given as bookID is not the name of one of our files,
then this method should throw an java.lang.IllegalArgumentException. If the content of a
text file does is not in the form described above, for example if it does not contain a line starting in
“Title: ” then this method should throw an java.util.IllegalFormatException.
Distributing Books
Your Press class needs to have a public method called getCatalogue() that takes no arguments
and returns a list of books it can produce. Again, let’s assume the book is identified by the name of the
text file it is read from, e.g. “120-0.txt”. The getCatalogue method should return a list of Strings
and be declared exactly as below.
1 public List<String> getCatalogue()
Your Press class needs to have a method called request to allow users to take out a number of books
at once. It should have a signature as follows.
1 public List<Book> request(String bookID, int amount)
4
COMP122 Assessment 3 Due 2021-05-07 at 5pm
A user would give a bookID string that identifies the book and the number of copies to take. The
resulting list of books must naturally have the same length as requested and contain that many distinct
copies of the requested book.
This method should return the books from the shelf or trigger a re-print if there are not enough copies
in store: If someone wants to take out n copies of a book, we will give them the first n from the shelf. If
there are fewer than that many le we print new ones (with a new“edition”number), add them to the
end of the shelf and give out the requested number of books. We can assume that no user wants to
take out more books than would fit on the shelf.
If the requested book is not in print, i.e. the string given as bookID is not the name of one of our files,
then this method should throw an IllegalArgumentException.
Part 3. A vending machine for books
Write a class called VendingMachine that can sell books to customers. Each such vending machine
will be supplied by a press and oers all books that press can print. The price each book sells for will
depend on the size of the book but also on some“location factor”that allows us to sell books at higher
prices in posher areas. For instance, a book with 500 pages sells for 500*0.01 = 5.0 GBP from a
vending machine with location factor 0.01.
Your class must have a constructor method that takes exactly three parameters, namely a Press object,
the location factor (a double), and an int that determines the size of its shelves, meaning the number
of books of each kind to store.
1 public VendingMachine(Press supplier, double locationFactor, int size)
These items should be stored in the vending machine as private attributes (of the same name and type)
to be accessed later. So there should be private attributes supplier (a Press), locationFactor (a
double), and size (an int).
The class should also have a private double attribute called“cassette”and a corresponding getter
public double getCassette(). Moreover, there must be public methods as follows.
- a method called“insertCoin”
- public void insertCoin(double coin)
that adds the value of is parameter to the cassette. This method should throw an
IllegalArgumentException if the given coin is not of the right denomination. Acceptable
values are 0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, and 2. - a method called returnCoins
5
COMP122 Assessment 3 Due 2021-05-07 at 5pm - public double returnCoins()
that empties the cassette (sets it to zero) and returns its original value. - a method called buyBook
- public Book buyBook(String bookID)
that sells a book with the given bookID string. It should check if the price of the book is at most
the value of cassette. The price of the book is the number of pages multiplied by the location
factor of the vending machine.
If the cassette contains enough money then the method removes the book from the shelf, reduces
cassette by the price of the book and returns the book. If the book sold like this was the last of
its kind (meaning aer the sale the machine has none le) then the vending machine contacts its
supplier press and requests more copies of this book. The number of copies it requests should
be determined by the value of the size attribute, so we request as many copies of this book as
we can fit.
The buyBook method should also be able to throw (unchecked) exceptions for the following two
scenarios: - If the parameter bookID is not a valid (there is no book by this id on oer) then this should
throw an IllegalArgumentException. - If the price of the book exceeds the value of the cassette then the method should throw a
CassetteException. This type of exception is of course special to our application and
you should define it yourself as a new type of RuntimeException.
6
COMP122 Assessment 3 Due 2021-05-07 at 5pm
Hints - You can use anything you want from the Java standard library.
- Do not only focus on the diicult bits! You can gain points for having the prescribed methods.
- Use the automarker and take its feedback into account before you submit your final version. You
can do that by running check50 . - Notice that nowhere in this assignment do we ask you to write a main method. To test your code,
you can write some (unassessed) main method somewhere that instantiates a Book/Press
/VendingMachine, calls its methods and prints the results. Our checks will try to instantiate
your classes into objects. This means that if your constructor methods are missing or calling
them results in errors, you will not get points for functionality. - To list files in a given directory you can use java.io.File.listFiles() for example like this.
- File directoryPath = new File(booksDirAsString);
- File filesList[] = directoryPath.listFiles();
- for(File file : filesList) {
- System.out.println(“File name: “+file.getName());
- }
- For the Press, the“edition”attribute should be of type Map<String, Integer>. Remember
that Map is an interface that cannot be instantiated so you’ll want to instantiate a HashMap<
String,Integer> here. Also recall that we use the wrapper class Integer and not simply
int because Java’s collections cannot be build on primitive data types. Similarly, you will likely
want to use HashMap<String, LinkedList<Book>> for the“shelf”attribute (LinkedList
is a class that implements the Queue interface‘). - In order to extract title, author and content info from a text file, consider reading the whole file
content into a String and using regular expressions just like in the labs.
Submission
Submit you solution using submit50 just like the lab exercises.
submit50
To check that your submission is in the correct format you can run check50 on the same slug.
7
COMP122 Assessment 3 Due 2021-05-07 at 5pm
Fine Print - Submissions are subject to UoL’s Code of Practice on Assessment and the usual late penalties
apply. This means you can still submit until 120 hours past the deadline, and will incur a -5%
penalty for each 24 hour period immediately following the deadline. Submissions aer that will
not be considered. You can submit multiple times and only the latest version (and it’s submission
time) will be used for grading. - Your submission is an individual piece of work. No collaboration with other students is allowed!
Expect that plagiarism detection soware will be run on your submission to compare your work
to that of other students. - Do not define classes in any Java packages! Most IDEs will suggest including a statement like
- package yourProjectName;
at the beginning of each java file. However, in order to tests your submission we need to know
the namespace where your classes are defined and the most fail-proof assumption is to use the
default namespace, i.e., no package definition. If you don’t know what this is about, don’t worry
and make sure your code does not contain any package declarations as above and compiles fine
using javac *java in the directory that contains your files. - Code that does not compile will get zero points and will not be further considered. Make sure
your code compiles directly using javac on the console.
If you require an extension due to extenuating circumstances please get in touch with the CS student
oice (csstudy@liv.ac.uk) before the submission deadline. We cannot grant any extensions aerwards.
If you are granted an extension you cannot in addition submit late aer your personal deadline.
The results will be made available on Canvas and we aim for a turn-around time of three weeks.