Assignment A2#

Released by:Monday, 11 August 2025
Base assignment deadline:Friday, 22 August 2025, 15:00
Code Walk registration/preferences/ext. tokens deadline:Friday, 22 August 2025, 18:00
Code Walk registration link:(link)
Code Walks:
Wednesday, 27 August 2025
Thursday, 28 August 2025
Friday, 29 August 2025
GitLab template repository:(link)
Compliance tests JAR file:JAR file
Minimum Library Version:2025S1-7
Last Updated:Friday, 15 August 2025, 16:17

This assignment is restricted to using the Functional Java libraries. Please note the required minimal library version above! In everything you do, you must follow the Design Recipe. This includes adding documentation to all functions created, except for the functions used for testing (that is, testing interfaces) and test functions. To see roughly how this assignment will be marked, check out the Skeleton Rubric.

You really really need to stick to the restrictions of Functional Java. Don’t just write Java code simply because you already know Java. The penalties in the rubric for doing so are quite harsh.

Formalities#

This assignment is submitted via GitLab.

Access to Your Repository#

To start your assignment, go to the GitLab repository of Assignment 2 and follow these steps:

  1. Click the Fork button at the top right of the page.
  2. Do not change the project name, that is, it must still be comp1110-2025s2-a2
  3. If asked for a namespace, choose your university ID.
  4. Do not change the project slug.
  5. Make sure the visibility of the project (bottom of the page) is set to private.
  6. Click the Fork project button at the bottom of the page.

To double check that we can access your assignment, make sure that:

  • your assignment 2 project is reachable through the address https://gitlab.cecs.anu.edu.au/XXXXXXXX/comp1110-2025s2-a2 where XXXXXXXX is your uid in the format u1234567.
  • your repository includes our marker bot (comp1110-2025-s2-marker) as a Maintainer member (click on Manage on the right side of your project page, then Members and you should see the marker bot in the list on the right).

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 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 what 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, 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 contain the following files in its root directory:

  • notebook.yml - your Notebook
  • soo.txt - your signed Statement of Originality

The deadline for registering to participate in code walks is Friday, 22 August 2025, 18:00. You need to do this in order for your assignment submission to get marked!

Compliance Tests#

To assist you with all the formalities above and the required records and functions defined in the following sections, use the A2Compliance.jar checker. Save the compliance checker to the same folder as your assignment and execute the following in the terminal to check your assignment: java -jar --enable-preview A2Compliance.jar .

The current version of the A2 compliance checker is 1.01. Always ensure that you have the latest version of it by verifying that the version displayed in the first output line matches the previously mentioned one.

Keep in mind that passing the compliance tests does not imply that you will get a good grade because the compliance checker does not evaluate the logic of your functions.

In contrast to Assignment 1, in this assignment you will only have to follow the Design Recipe for a set of clearly specified functions. Not following the Design Recipe means that you do not have to write documentation nor tests (at your own risk!) for such functions. However, you still have to adhere to functional Java principles, and write functions for which only a single design strategy applies (functions must only do ONE thing!!!).

Tasks#

Part 1: The File System Calculator#

In a file called FileSystem.java

In this part of the assignment, you will model a simple file system and implement core functions for it using recursion. For example, one of the goals in this assignment is to calculate the total disk space used by a directory, including all files and sub-directories it contains. This is a classic application of recursion on hierarchical data.

1. Designing the File System Model#

Before you begin, you must think about how to represent the items in a file system. A file system consists of two kind of items: files and directories.

A file is a simple item. It has a name (String) and a size (int) measured in bytes. It cannot contain other items.

A directory (also known as a folder) is a more complex item. It has a name (String), but it also contains a collection of other file system items, that is, it can contain both files and other directories. A directory can be empty, that is, it might not contain other file system items.

To handle these two kinds of items together, you will need a way to represent “any item in a file system”.

Throughout this document, we will use placeholders to refer to the data types you will define:

  • [I]: The data type that represents any item in the file system.
  • [F]: The data type that represents a single file.
  • [D]: The data type that represents a directory.

Design the data types to represent [I], [F] and [D]. You must decide on the actual names for these types yourself and how to represent the collection of the file system items inside a directory. You need to follow the Design Recipe for these data definitions.

2. Testing interface#

Design the following functions to be used by our tests (i.e., the tests that we will use to mark your assignment). You are also allowed to use these functions in your tests too. For all the following functions in the test interface you do not need to follow the Design Recipe.

// To interpret the item [I]
boolean isFile([I] item);
boolean isDirectory([I] item);

// To construct file system items for testing
[I] makeFile(String name, int size);
[I] makeEmptyDirectory(String name);

3. Populating a Directory#

Design the following function that adds a given item to a directory. You need to fully follow the Design Recipe for addItemToDirectory, this includes all helper function used directly or indirectly, that is, helper functions used by any helper functions in this part.

/**
 * Adds a given item (file or subdirectory) to a directory.
 *
 * @param directory The directory to which the item will be added.
 * @param item      The item to add to the directory. 
                    It can be a file or another directory.
 * @return The directory containing all the original items 
           plus the new item.
 */
[D] addItemToDirectory([D] directory, [I] item);

4. Calculating Total Size#

Design the following function that calculates the total size of a file system item in bytes. You need to fully follow the Design Recipe for calculateSize, this includes all helper function used directly or indirectly.

/**
 * Calculates the total size of a given file system item in bytes.
 * - If the item is a file, its size is its own defined size in bytes.
 * - If the item is a directory, its size is the sum of the sizes
 *   of all items it contains, calculated recursively, in bytes.
 *
 * @param item The file system item to calculate the size of.
 * @return The total size in bytes.
 */
int calculateSize([I] item)

5. Finding an Item#

Design a function that can find an item anywhere in a file system based on its name. If multiple items have the same name, your function can return the first one it finds.

You need to follow the Design Recipe for findByName and the helper functions directly called by it. However, you do not need to follow the Design Recipe for any function called by the helper functions of findByName (that is, the helper functions indirectly used by findByName). See above for a description of what “not following the Design Recipe” means.

/**
 * Recursively searches the file system rooted at 
 * initialItem for an entry with the given name.
 *
 * @param name The name of the file or directory 
 *             to search for.
 * @param initialItem The file system item where the search 
 *                    should begin.
 * @return The first item found with the matching name, 
 *         or Nothing if no such item exists in the file 
 *         system rooted at initialItem.
 */
Maybe<[I]> findByName(String name, [I] initialItem)

Part 2: Marble Crush#

In a file called MarbleCrush.java

Design a world program which handles a two-dimensional (2D) grid of coloured marbles that the user will crush (delete) using the mouse. The user will also be able to create new marbles by typing space. Similar to the BouncingMarbles from Assignment 1, the world is 300 pixels wide and 500 pixels high and all marbles are drawn as circles of radius 10 pixels. The marbles are positioned to be touching the adjacent marbles in the grid, with no space in between them and no overlapping. Therefore the world should have 25 rows of marbles with 15 marbles per row (i.e., 15 columns of marbles). The marble colours are BLUE, RED, GREEN, and BLACK. Unlike the previous assignment, the marbles in this world are stationary and do not move on their own. At the start of the program, the entire grid is populated with marbles, and the colour for each individual marble is decided randomly among the four colours enumerated above.

The program must handle user interaction through the mouse and keyboard. When the user left-clicks the mouse, the program must first determine if the coordinates of the click belong to the space occupied by the marble. We assume that the space occupied by a marble is the space occupied by its bounding box, that is, the area represented by a square of side length 20 pixels in which the marble is inscribed, with the marble’s center placed on the center of the bounding box. If a marble is clicked (i.e., the click is within the bounding box of the marble), that marble and all other marbles currently on the grid that share the same colour must be crushed (deleted), leaving their former occupied space as empty spaces. If the user clicks on an empty space where no marble exists, the state of the world should not change. Furthermore, if the user hits the SPACE bar, the program must identify all empty spaces on the grid (that is, bounding boxes without a marble inside) and fill each one with a new marble. The colour of each new marble must be randomly chosen from the four available colours.

A central challenge of this program is the management of the collection of marbles and the tracking of empty spaces on the grid. As part of your design, you must devise a method for representing all marbles of each colour as well as the empty locations.

For this part of the assignment, you need to follow the Design Recipe only for your data definitions, and the draw, mouseEvent, and keyEvent functions, and the helper functions immediately called by them. However, you do not need to follow the Design Recipe for any function called by the helper functions of these functions. See above for a description of what “not following the Design Recipe” means.

In order to get you started, we provide the helper function below, that you can copy and paste into your assignment’s code. Depending on the approach chosen to solve the problem, you may or may not use this function in your assignment. Please note that the generateAllMarblesCenterPosition function uses iteration (loops) which is not allowed in functional Java at this point of the course. You do not need to understand the function’s body, just what the function does (i.e., purpose statement and signature). You may want to re-write a version of it using recursion. Students doing so would get 10 bonus marks in their assignment. In order to get such bonus marks, the function written using recursion should have the same signature as generateAllMarblesCenterPosition, but must be named generateAllMarblesCenterPositionRecursively.

/**
*  Generates a list of pairs with the coordinates of the
*  centers of the marbles laid out in a two-dimensional grid 
*  of marbles with numMarbleRows rows and numMarbleCols columns. 
*  The marbles are positioned to be touching the adjacent marbles 
*  in the grid, with no space in between them and no overlapping. 
*  The positions of the marble centers are ordered in row-major order, 
*  i.e.,  first by rows, and then by columns. The origin of 
*  coordinates is assumed  to be placed in the lower left corner of 
*  the bounding box of the marble positioned in the lower left corner 
*  of the grid of marbles. The x-axis points right, and the y-axis 
*  points down.
*  Design strategy: Iteration (will cover this in week 5/6)
*  Example:
*    Given: marbleRadius=10, numMarbleRows=2, numMarbleCols=3
*    Expect: [(10,10),(30,10),(50,10),(10,30),(30,30),(50,30)]
*  @param marbleRadius The radius of the marble in pixels (>0)
*  @param numMarbleRows The number of rows in the 2D grid 
                        of marbles (>0)
*  @param numMarbleCols The number of columns in the 2D grid 
                        of marbles (>0)
*  @return A list with the coordinates of the marble centers 
           in the 2D grid
*/
ConsList<Pair<Integer,Integer>> 
   generateAllMarblesCenterPosition(int marbleRadius,
                                    int numMarbleRows,
                                    int numMarbleCols)
{
  ConsList<Pair<Integer,Integer>> outputList = new Nil<>();
  int marbleDiameter = marbleRadius*2;
  int currentCenterCoordY = marbleRadius;
  for (int i=0; i<numMarbleRows; i++) {
    int currentCenterCoordX = marbleRadius;
    for (int j=0; j<numMarbleCols; j++) {
      outputList = Append(outputList,
             MakeList(new Pair<Integer,Integer>(currentCenterCoordX,
                                                currentCenterCoordY)));
      currentCenterCoordX+=marbleDiameter;
    }
    currentCenterCoordY+=marbleDiameter;
  }
  return outputList;
}

Provide the following testing interface:

// [W] should be replaced with whatever type you use 
//     to represent the world state
// [M] should be replaced with whatever type you use 
//     to represent a marble
// [C] should be replaced with whatever type you use 
//     to represent a colour 
//     (Note: this is your OWN data definition for colours, 
//      possibly different from the Colour opaque data type 
//      in the Universe package)

// your stepping function
[W] step([W]);

// your drawing function
Image draw([W]);

// your mouse event handling function
[W] mouseEvent([W], MouseEvent);

// your key event handling function
[W] keyEvent([W], KeyEvent);

// returns the initial state of your world
[W] getInitialState();

// returns Something with the marble 
// at pixel coordinate (x, y) or Nothing 
// if no marble is there
Maybe<[M]> getMarbleAt([W], int x, int y);

// returns the colour of a given marble
[C] getColour([M]);

// returns the number of marbles of a 
// given colour
int numberOfMarblesOfColour([W], [C]);

// returns the number of empty locations 
// in the grid of marbles
int numberOfEmptyLocations([W]);

Updates#

Friday, 15 August 2025, 16:17Part 2. Fixed a typo in the capitalization of generateAllMarblesCenterPositionRecursively
bars search caret-down plus minus arrow-right times