Assignment A3#
| Released by: | Monday, 22 September 2025 |
| Base assignment deadline: | Friday, 03 October 2025, 15:00 |
| Code Walk registration/preferences/ext. tokens deadline: | Friday, 03 October 2025, 18:00 |
| Code Walk registration link: | (link) |
| Code Walks: | Wednesday, 08 October 2025
Thursday, 09 October 2025
Friday, 10 October 2025
|
| GitLab template repository: | (link) |
| Compliance tests JAR file: | JAR file |
| Minimum Library Version: | 2025S1-7 |
| Last Updated: | Tuesday, 30 September 2025, 16:16 |
Make sure you have the latest A3Compliance.jar. Its version is 1.10 and you can find the version of your A3Compliance.jar by looking at the first line of its output.
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 7A).
- 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 7A.
- 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 7B. Do not forget both the adjustments of the Design recipe for stateful (imperative) programs and iteration, covered in Week 6. To see roughly how this assignment will be marked, check out the Skeleton Rubric.
The deadline for registering to participate in code walks is Friday, 03 October 2025, 18:00. You need to do this in order for your assignment submission to get marked!
You still need to follow the Design Recipe for all class definitions.
In particular, the (minor) adjustments to the Design Recipe for class definitions were covered in workshop 7B.
However, for class methods (either instance or static ones) you only need to follow the design recipe for the
definition of those methods listed in the sections below and any helper methods directly called by them.
Besides, 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.
Not following the Design Recipe means that you do not have to write documentation nor tests (at your own risk!) for those
methods that do not fall into this category. However, you still have to write methods for which only a single design strategy applies
(methods must only do ONE thing!!!), with some relaxations covered in the workshop slides. Do not write code that is overly complicated.
Formalities#
This assignment is submitted via GitLab.
Access to Your Repository#
To start your assignment, go to the GitLab repository of Assignment 3 and follow these steps:
- Click the Fork button at the top right of the page.
- Do not change the project name, that is, it must still be
comp1110-2025s2-a3 - If asked for a namespace, choose your university ID.
- Do not change the project slug.
- Make sure the visibility of the project (bottom of the page) is set to private.
- Click the
Fork projectbutton at the bottom of the page.
To double check that we can access your assignment, make sure that:
- your assignment 3 project is reachable through the address
https://gitlab.cecs.anu.edu.au/XXXXXXXX/comp1110-2025s2-a3where XXXXXXXX is your uid in the formatu1234567. - your repository includes our marker bot (
comp1110-2025-s2-marker) as aMaintainermember (click onManageon the right side of your project page, thenMembersand you should see the marker bot in the list on the right).
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 Notebooksoo.txt- your signed Statement of Originality
The source Java files of the assignment should be placed in the src/ directory, with a single class per Java source file. The tests should be written using JUnit, and placed in the tests/ directory, with one test class in tests/ per corresponding class in src/. You must have the classes and Java source files listed below in each section. You may also add additional helper source files/Java classes as you see fit. Finally, you may also add pure text files in your tests/ directory to support your tests.
Compliance Tests#
To assist you with all the formalities above and the required classes and methods defined in the following sections, use the A3Compliance.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 A3Compliance.jar .
The current version of the A3 compliance checker is 1.00. 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.
The compliance checker does not check the Distinction-Level Part (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:
In regards to the last point, we note that it is not strictly needed to use the generic HashMap<K,V> class from the Java Standard Libraries. You can use instead stateful maps from the functional Java standard library as covered in the workshops (and the associated exercises).
Info: Functional Java Library#
If you wish to use the functional Java library, you will need to copy the Functional Java Jar File into a folder called library. For more details, see the IntelliJ Project Setup page.
General recommendations for writing JUnit tests in this assignment#
When writing JUnit tests for code that involves files and folders, you have to be extremely careful to design the tests such that these files and folders are properly found by the tests. This amounts to decide where in the file system to store these files, and how to reference them from the tests’ code. In particular, absolute paths such as, e.g., /home/u1234567/comp1110-2025s2-a3/tests/mytest.ini, are computer-dependent , and thus you have to avoid them in general if you want the tests to be portable to other machines (which you want, as we will test your code in a different machine than yours). We thus recommend that you use relative paths (e.g., tests/mytest.ini) in your tests. The use of relative paths requires you to be mindful of the current working directory from which the JUnit tests are triggered. At the end of the day, it amounts to fulfilling the following requirement:
if you move your project folder (i.e., Java source codes, and accompanying files and folders for the tests) to a different computer, e.g., a Linux lab computer, would you be able to still run the tests flawlessly?
We indeed recommend that you go to the lab computers at some point to double check this. Finally, you may also consider creating ad-hoc file system trees within the tests/ folder to support the tests that you write. If you do that manually, e.g., from the console, instead of programmatically/dynamically from the tests themselves, be aware that you will also need to commit and push such file system trees to the remote git repository. Otherwise, we won’t be able to run your tests.
Tasks#
Background and INI format for text files#
Welcome to A3! You’ll be building a set of Java classes to load and manage configuration data for a role-playing game. In this game, you will have characters with different attributes and inventory of items that they are carrying. These characters can also form a party to go on adventures together.
The data representing characters, game items and parties will be provided to the program via text files that follow a particular format. Instead of processing tabular data stored in files following the CSV or TSV format (as in the workshop exercises), this assignment will introduce you to a different, widely-used format for pure text files: the INI format.
INI is a text-based format for configuration data. It’s organized into sections. A section starts with a header line that only contains the name of the section within square brackets (e.g., [MySection] and [another section]), followed by a series of key-value pairs on separate lines of the form Key=Val, where Key denotes the name of the key, and Val the value associated to that key. Sections are separated by one or more empty lines. The file may have several leading and trailing empty lines but no empty line is allowed within a section. This structure is well-suited for organizing settings and game data.
For this assignment, you can assume that section names are unique within a file. Besides, for lines of the form Key=Val, neither Key nor Val can contain =, [, ], newline or tab characters. If Val represents an integer number, you can also assume that you will be able to parse it flawlessly with Integer.parseInt. Furthermore, neither Key nor Value will have leading or trailing spaces.
Part 1: Game Items#
In a file called src/GameItem.java
Part 1 is a regular part of the assignment. However, it’s 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.
The most basic component of any role-playing game is the items that players can find and use. We will define these items in an INI file. Each section of the file represents a single item, and key-value pairs within that section describe item properties.
Each section MUST have at least two key-value pairs, with key names Value and Weight, respectively. Items can also optionally have key-value pairs that represent bonuses to the attributes of the player characters carrying them (see Part 2 for details). These pairs’ keys have names AttackBonus, AgilityBonus, and DefenseBonus. If a bonus is not specified in the file for an item, its value should be treated as 0.
Here is an example file, named, say, items.ini, with the valid format:
[Heavy Sword]
Type=Weapon
Weight=15
AgilityBonus=-5
AttackBonus=10
Value=250
[Elven Cloak]
AgilityBonus=3
Value=120
DefenseBonus=1
Weight=3
[Health Potion]
Value=50
Weight=1
Type=Consumable
[Wooden Shield]
DefenseBonus=5
AgilityBonus=-1
AttackBonus=-7
Value=5
Weight=10
The file above defines four items. The item’s name is taken from the section header (e.g., "Heavy Sword"). Each item mandatorily has the Value (in gold pieces) and Weight (in kilograms) key-value pairs, and optionally, the AttackBonus, AgilityBonus, and DefenseBonus ones. Your parser should ignore key-value pairs with names different from these five (e.g., see the Type key-value pair for the "Heavy Sword" and "Health Potion" items in the file above). Besides, the key-value pairs can be listed in any order, and the order for each section might be different. You can assume there cannot be key-value pairs with the same name within the same section.
Create a class called GameItem to model this data.
You must design at least the following members, as these are the ones we will subject to automatic testing:
// Here, File refers to java.io.File.
// Make sure to use the right import!
/**
* Returns the name of the item (derived from the INI section header).
*/
String getName();
/**
* Returns the value of the item in gold pieces.
*/
int getValue();
/**
* Returns the weight of the item in kilograms.
*/
int getWeight();
/**
* Returns the attack bonus for this item.
*/
int getAttackBonus();
/**
* Returns the agility bonus for this item.
*/
int getAgilityBonus();
/**
* Returns the defense bonus for this item.
*/
int getDefenseBonus();
/**
* Constructs a new GameItem.
*/
GameItem(String name, int value, int weight, int attackBonus,
int agilityBonus, int defenseBonus);
/**
* Given a valid and non-empty INI file of the format described above,
* reads all item definitions from the sections and returns an array
* containing them.
*/
static GameItem[] readItems(File file);
Follow the Design Recipe!
Part 2: Player Characters#
In a file called src/PlayerCharacter.java
With our items defined, we can now create the heroes of our game: the player characters. Characters carry an inventory of GameItems and have the following attributes:
- Strength: Governs physical power. Modified by
AttackBonusfrom items. - Dexterity: Governs agility. Modified by
AgilityBonusfrom items. - Fortitude: Governs resilience. Modified by
DefenseBonusfrom items.
We’ll define player characters in a separate INI file. Each character is a section, and their key-value pairs include their attributes (namely, Strength, Dexterity and Fortitude) and their inventory (i.e. the items that they carry). The inventory is represented as a single key-value pair with key name Inventory and value being a comma-separated list of item names. These names correspond to the items you loaded in Part 1. Your program has to be able to calculate the character’s total attributes by summing their base attributes with the bonuses from all items in their inventory.
Here’s an example file named, say characters.ini:
[Gimli]
Class=Dwarf Warrior
Strength=18
Dexterity=12
Fortitude=30
Inventory=Battle Axe,Chainmail,Health Potion
[Legolas]
Class=Elf Ranger
Strength=14
Fortitude=25
Location=Mirkwood
Inventory=Longbow,Leather Armor,Arrows
Dexterity=20
These files may have their key-value pairs in any order and you need to model only the characters three attributes and inventory. For a character with an empty inventory, both of the following are valid: (1) a line with no value for inventory, namely, Inventory=; and (2) skip the inventory line, that is, if a character has no Inventory key then it has an empty inventory. You can skip any extra Key (like Class or Location) and your PlayerCharacter class doesn’t need to store.
Create a class called PlayerCharacter to model these heroes.
You must design at least the following members, as these are the ones we will subject to automatic testing:
// Here, File refers to java.io.File
// (Make sure to use the right import!),
// and GameItem refers to your class from Part 1.
/**
* Returns the character's name (from the INI section header).
*/
String getName();
/**
* Returns the character's base Strength stat (without item bonuses).
*/
int getStrength();
/**
* Returns the character's base Dexterity stat (without item bonuses).
*/
int getDexterity();
/**
* Returns the character's base Fortitude stat (without item bonuses).
*/
int getFortitude();
/**
* Returns an array of GameItem objects in the character's inventory.
*/
GameItem[] getInventory();
/**
* Returns the character's total strength, calculated as base Strength
* plus the sum of AttackBonus from all items in their inventory.
*/
int computeTotalStrength();
/**
* Returns the character's total dexterity calculated as base Dexterity
* plus the sum of AgilityBonus from all items in their inventory.
*/
int computeTotalDexterity();
/**
* Returns the character's total fortitude calculated as base Fortitude
* plus the sum of DefenseBonus from all items in their inventory.
*/
int computeTotalFortitude();
/**
* Creates a new character.
*/
PlayerCharacter(String name, int strength, int dexterity,
int fortitude, GameItem[] inventory);
/**
* Given a valid and non-empty character INI file and a complete array
* of all possible GameItems that exist in the game (that is, you can
* assume that every item in a character's inventory is present in
* allItems), this method loads the characters from the file.
*/
static PlayerCharacter[] readCharacters(File file, GameItem[] allItems);
Follow the Design Recipe!
Part 3: Adventuring Parties#
In a file called src/Party.java
Heroes rarely adventure alone, but in “adventuring parties”. You can think of an adventuring Party as a group of PlayerCharacters.
The objective of this part of the assignment is to design a class able to manage a collection of characters and perform calculations based on the group’s combined power.
Parties are saved to and loaded from a directory. Each party is stored in its own file named [PartyName].ini, for example, a party named “fellowship” is stored in fellowship.ini. This file must be a valid INI file (this will be tested) but you can decide on the exact structure of this file, that is, sections, keys and values.
Design a new class Party. You must implement at least the following members:
/**
* Returns the name of the party (e.g., from the filename).
*/
String getName();
/**
* Returns the characters who are members of this party.
*/
PlayerCharacter[] getMembers();
/**
* Returns the combined attack rating of the party, calculated as the
* sum of every member's computeTotalStrength().
*/
int computeCombinedAttackRating();
/**
* Creates a new empty Party with a given name.
*/
Party(String name);
/**
* Adds a character to the party.
*/
void addMember(PlayerCharacter character);
/**
* Removes a character from the party.
*/
void removeMember(PlayerCharacter character);
/**
* Saves the current state of the party to an appropriately named file
* ("[name].ini") in the given directory.
*/
void storeParty(File directory);
/**
* Given a directory containing party files and a list of all available
* characters in the game, loads all parties from the INI files in the
* given directory. Assume that all INI files in the directory are
* non-empty and valid INI Party files. Moreover, assume that all
* characters in the Party files are contained in allCharacters.
*/
static Party[] loadParties(PlayerCharacter[] allCharacters,
File directory);
Follow the Design Recipe!
Part 4 (Distinction-Level Part)#
The compliance checker does not check this part of the assignment. Distinction-level parts of assignments require distinction-level work, and this includes a high standard of attention to detail, among others. Thus, you need to pay attention to the specification and implement it accordingly.
In a file called src/IniLoader.java
Create a class that abstracts the INI-loading process from parts 1 and 2. Call this class IniLoader.
Your task is to create a generic method that can parse any INI file structured like the ones in this assignment. For each section in the file, your loader should build a Map<String, String> of its key-value pairs. It then uses a “factory” function, provided by the caller, to turn that data into an object of the correct type.
Because the object’s name comes from the section header itself, the factory function will need both the section name and a map that holds the key-value pairs associated to the section. This requires a BiFunction.
You must design at least the following members:
// You will need to import java.io.File, java.util.Map,
// java.util.function.BiFunction, and java.util.function.Function.
/**
* Reads the given INI file. For each section, it creates a stateful
* Map of the key-value pairs within that section. It then calls the
* elementFactory function, passing the section name (e.g.,
* "Heavy Sword") as the first argument and the stateful Map of its
* properties as the second.
*
* @param file The INI file to read.
* @param makeArray A function to create the final array of the correct
* type and size.
* @param elementFactory A function that takes a section name (String)
* and a Map<String, String> of properties and returns a new object of
* type T.
* @param <T> The type of object to create for each section.
* @return An array of objects created from the INI file.
*/
static <T> T[] loadINI(
File file,
Function<Integer, T[]> makeArray,
BiFunction<String, Map<String, String>, T> elementFactory
);
/**
* The same method as from Part 1, but now implemented using loadINI.
*/
static GameItem[] readItems(File file);
/**
* The same method as from Part 2, but now implemented using loadINI.
*/
static PlayerCharacter[] readCharacters(File file, GameItem[] allItems);
Updates#
| Tuesday, 30 September 2025, 16:16 | Release v1.10 of A3Compliance.jar that works with the Functional Java library. Make sure it is at `library/comp1110lib.jar` |