For this project you will simulate a game where different characters interact on a 2-dimensional grid and where each cell in the grid can contain zero, one or multiple pieces. A game playout continues for n iterations or until a victor emerges. During each of the iterations all cells of the grid are updated synchronously according to the rules stipulated in Section 3. There are six main classes of pieces: Warrior, Healer, Potion, Weapon, Water, and Magic Crystal pieces. The details relating to each piece’s function and characteristics is defined in Section 2. As the game progresses, the warriors battle one another and interact with other pieces on the grid; your program should print visualisation information after each iteration in the game and produce warrior statistics once the game has terminated.
The warrior pieces are the main characters of the game and begin the playout with an allocation of 6 different attributes; as the game progresses these warriors are matched against one another in battle until a victor emerges.
- Age - This is in terms of iterations, each time another iteration of the game playout occurs this age increases by 1.
- Health - This is a percentage measure representing how well the player is doing in the game.
- Movements - Each warrior has a list of movements which they perform, one per iteration.
- Offense Power - This value represents the amount of heath they remove from another warrior in battle.
- defence Strength - This is a measure of the effectiveness of a warrior’s defensive skills.
- Weapon Inventory - Warriors have an inventory size which allows them to hold a maximum of w weapons at any one time; each weapon possessed by the warrior increases the player’s offensive power during battle.
There are four types of warriors: Stone Warriors, Flame Warriors, Water Warriors and Air Warriors. Each type of warrior has a unique special ability as defined in Section 3.9.
Healer pieces are those that bring order and peace to the world around them, the game has two defined types of healer pieces namely the Restorer and the Peacemaker, their roles are defined in Section 3.10.
Drinking an unknown potion can be a gamble for a warrior, unknowing what the affect of the potion might be. The game has three types of potions, each with their own affect on a warrior.
- Trance Causing Mixture - This type of potion causes the warrior who drank it to become confused and perform the inverted movements to those which they otherwise would have performed. This trance lasts up until they drink a Trance Healing Mixture.
- Trance Healing Mixture - This potion has no affect on warriors that have not been effected by the Trance Causing Mixture; for those warriors in a trance it heals them of their confusion and they again perform movements as originally specified.
- Invisibility Mixture - This type of potion causes the warrior to become invisible to other warrior and healer pieces for i iterations of the game. When invisible, the warriors still perform their movements as normal but they do not enter battle with any other warriors and so remain unharmed. They do however make themselves known to Restorer pieces when in contact with them so that they can be healed and increase their health attribute.
Weapon objects can be positioned in a cell on the grid or be held in the inventory of a warrior. If held in the inventory of a warrior, the weapon adds offense power to the warrior according to the weapon specific value specified in the game setup file; each weapon is configured at the beginning of the game with an offense power benefit.
Water flows around the grid and benefits each warrior according to the rules in Section 3.12.
A maximum of 1 magic crystal may be present in the game and when activated, the crystal causes all warriors except for those four that activated the crystal to be removed from the game; see Section 3.13 for the rules relating to this piece.
The neighbourhood of a piece is defined as the 8 closest cells to the piece. In Figures 1,2 and 3 the blue cell represents the current piece and the green cells represent the neighbourhood of that piece. In a situation in which the current cell is on the edge of the grid, the neighbourhood wraps around to the opposite edge of the grid.
Each game playout is made up of n iterations (n is defined in the program setup files) and for each iteration, every cell in the grid is updated according to its neighbourhood. Each cell is updated synchronously, relying only on data from that iteration and not any updates made during the transition to the next iteration.
Each warrior is able to move around the grid according to their individual-specific sequence of moves, executed one position per iteration. Since each list of moves is of finite length, when the end of the list is reached then the player should `wrap’ the moves around and start from the beginning of the list again. For example: If a warrior has the list “wassdq” as their moves list, then for 8 iterations they would perform the moves “wassdqwa”, one per iteration. See Section 5.0.1 for explanation of what direction each movement character represents.
A maximum of 1 healer, 1 potion, 1 magic crystal, 1 weapon and 1 water piece may together be present on a cell; warrior pieces however can occur with multiple pieces at a cell at any one time with the constraint that a maximum of 10 warrior pieces will occur on the same cell, see Section 5.1.3 for exception handling for situations where this rule is violated.
When warrior cells move off the edge/corner of the grid, they wrap around to the opposite edge/corner of the grid.
High levels of health indicate that the player will likely be able to continue in the game for quite a few iterations while low levels of health indicate that the warrior might soon leave the game. If the warrior experiences a drop in health equal to or below 0%, the warrior loses the game and is removed from the grid (this removal comes into effect in the following iteration). Your program should then immediately print “A warrior has left the game!”.
For each iteration and each warrior, the health of the warrior must be updated according to the pieces that are present in the warrior’s neighbourhood for that iteration. Note that the cell that the warrior occupies is not included in its neighbourhood and the warrior does not interact with pieces present at this cell unless explicitly specified by a rule.
During an iteration, each warrior is in battle with and can only be affected by those warriors which are in their neighbourhood. A comparison must be made between the defence strength of the current warrior and that of each of its neighbour warriors: if the current warrior’s defence strength is greater or equal to that of the neighbouring warrior then the current warrior does not incur a reduction in health; if the current warrior’s defence strength is less than that of the neighbouring warrior then the current warrior incurs a reduction in health equal to that ofthe neighbouring warrior’s offense power. Please make careful note of Section 3.14 point 3 when implementing warrior battles.
In the situation where multiple warriors are present on the same cell on the grid then for each warrior on the cell, their defence strength is increases by 2% for each additional warrior of the same type also on the cell (this change remains after the iteration i.e. it does not only apply to the iteration at which the overlapping occurs). This is due to the warriors sharing battle skill information.
If the age of a warrior is above 15, their defence strength strength must not be above 70%. If the age of a warrior is above 25, their defence strength must not be above 50%. If the age of a warrior is above 50, their defence strength must not be above 30%.
Each weapon has an allocated amount of offense power that it adds to the warrior that carries it. When a warrior piece occupies the same cell as a weapon piece, the warrior puts the weapon in their inventory; after which the weapon is no longer on the grid. If multiple warrior pieces are present on a cell as well as a weapon piece then the warrior with the highest offense power acquires the weapon. In a situation where multiple warriors tie with the highest offense power then the warrior with the lowest ID value obtains the weapon.
Each warrior is only capable of holding a certain number limit, L, of weapons at a given time but since warriors never refuse to pick up new weapons, the warriors drop some weapons when they exceed L. This dropping takes place in first-in-first-out order i.e. the weapon least recently picked up is the weapon dropped. If a warrior has a full inventory then it is guaranteed that they will, for the rest of the game have a full inventory since each time they pick up a weapon they will drop the one least recently obtained. Note that when a weapon is dropped, its offense benefit it reversed.
In the situation where two or more warriors are present at the same cell where this cell also contains a weapon piece, then if a warrior picks this weapon up and due to a full inventory also drops a weapon then the dropped weapon may not again be picked up until the next iteration (i.e. the weapon cannot be picked up in the same iteration in which it was dropped).
If a warrior loses and is removed from the grid then all the weapons in their inventory are removed from the game with them.
Each warrior has a special ability which they activate in a situation where their health is below or equal to 10%. The ability is effective from the iteration at which the ability was performed (i.e. the number of iterations count includes the iteration at which the ability was performed as one of the iterations). Each warrior may only activate their special ability once.
- Stone Warrior - The stone warrior generates an earthquake which creates an effective defence against its enemies. The warrior’s defence strength becomes set to the maximum of its current defense strength or 95% for 4 iterations. After which the warrior’s defence strength is set to the value it held before the ability was activated (subject to the rules of 3.7); any increase in defense strength gained for this stone warrior due to warrior alliances (Section 3.6 paragraph 2) during the time in which the special ability was activated are lost/overwritten after the 4 iterations. Unfortunately, due to the energy needed to create an earthquake, the warrior’s health decreases by 3% (note that this is not 3% of their warrior’s current health but it is literally the value 3%). Your program should immediately print “Special ability performed by stone warrior!”.
- Flame Warrior - This type of warrior generates a fire shield which results in a defence strength of 100% for 2 iterations, after which the warrior’s defence strength returns to the maximum of either its defence strength at the time of the ability activation or the value 70%; any increase in defense strength gained for this flame warrior due to warrior alliances (Section 3.6 paragraph 2) during the time in which the special ability was activated are lost/overwritten after the 2 iterations. Note that this value can be less than either of these in the situation where the warrior’s age necessitates a bound on the defence strength (Section 3.7). Your program should immediately print “Special ability performed by flame warrior!”.
- Water Warrior - The water warrior creates a watervapour shower which refresh the warrior and results in an increase in health of 20%(note that this is not 20% of their warrior’s current health but it is literally the value 20%) for the water warrior. Your program should immediately print “Special ability performed by water warrior!”.
- Air Warrior - This type of warrior manipulates the air into whirlwinds which attribute to an increase in offense strength of 30% (note that this is not 30% of their warrior’s current offense strength but it is literally the value 30%) for 3 iterations. After 3 iterations the offense strength is reduced by this 30%. Your program should immediately print “Special ability performed by air warrior!”.
Note that the bound on defence strength determined by the warrior’s age is not taken into account for the iterations in which the stone/flame warrior’s special ability is active (i.e. a warrior over 15 will be allowed to have a defence strength of 75%/100% due to the nature of the special ability; it therefore overrides the rules in Section 3.7). When determining what value the warrior’s defence strength should return to after the stone/flame warrior’s special ability period has completed, the defence strength bound determined by age should be taken into consideration again.
- Restorer - When a warrior has a restorer piece in their neighbourhood, the warrior’s health increases by a value b where the benefit b is a value uniquely defined for each restorer piece in the program setup files.
- Peacemaker - When a peacemaker piece is in the neighbourhood of warrior, the other warriors in its neighbourhood do not attack the piece, the warrior therefore does not take any damage.
When a warrior has one or multiple potion objects in its neighbourhood, the warrior drinks all available potions and is affected according to the rules in Section 2.3.1. Potions do not disappear from the grid once used. A few specific situation outcomes should be noted:
- If multiple potions of the same type are present in a warrior’s neighbourhood, the net effect is the same as one potion.
- If both a trance causing mixture and a trance healing mixture are present in a warrior’s neighbourhood then the warrior is not affected by the trance causing mixture.
- It is possible for a warrior to be affected by both the trance causing and invisibility mixture at one time.
- If a warrior is affected by the invisibility potion and encounters another invisibility potion; the second potion overrides the first and the invisibility lasts according to the second potion specification with a restarted iteration counter.
- If multiple invisibility potions are present in the warrior’s neighbourhood, the potion with the longest lasting strength is followed.
Only a single water piece may be present in a cell on the grid and the pieces act according to the following rules:
- If a cell contains a water piece and has 0 or 1 water objects in its neighbourhood, then the water object is removed from the grid (as if the water was absorbed into the ground).
- If a cell contains a water piece and has 2 or 3 water objects in its neighbourhood, then the water object remains on the grid.
- If a cell contains a water piece and has 4 or more water objects in its neighbourhood, then the water object is removed from the grid (as if the water flowed into the other water cells).
- If a cell does not contain a water object but has 3 water objects in its neighbourhood then a water object becomes present on the grid at this cell (as if the water flowed from the surrounding water).
During an iteration, if a warrior has one or more water objects in its neighbourhood then the warrior takes a refreshing drink and their health is increased by 3%. Each iteration where a warrior has no water objects in its neighbourhood, the warrior’s health decreases by 0.5%.
Water warriors gain power from the water around them; for each water object in the water warrior’s neighbourhood, its offense power is boosted by 1% (note that this is a permanent change).
When the magic crystal has exactly 1 of each type of warrior in its neighbourhood, configured in the formation one warrior per corner of the neighbourhood, then the crystal is activated and removes all warriors from the game except for those 4 that activated the magic crystal. The crystal itself is then removed from the grid and no warrior battles occur for that iteration. Your program should immediately print “The Magic Crystal has been activated! Four warriors remain…”.
- A helpful hint is that you should update each cell within the grid with respect to itself, taking into consideration information from its neighbourhood but never altering the neighbourhood cells around it. In other words, each cell is updated from the perspective of that cell where neighbouring cells affect it but it does not affect neighbouring cells.
- Since, within a single iteration, some operations alter the warrior’s attributes but other operations rely on these attribute values, the order in which these operations occur within the iteration result in different attribute value outcomes at the end of the iteration. It is therefore very important that you follow the operation order list below as this order will impact the statistics output printed at the end of your program execution. Please note that water and warrior movement updates come into effect at the beginning of each new grid configuration.
- If the magic crystal is activated, warriors should be removed from the grid as specified in Section 3.13.
- Warrior offense/health adjusted according to non-warrior pieces(water/restorer) in its neighbourhood and possible health decrease if no water is present in its neighbourhood.
- Warrior special abilities.
- Warrior’s defence adjusted according to warriors of the same type present on the same cell on the grid.
- Peacemaker check.
- Warrior battles (Rules in point 3 below).
- Increment age and update warrior attributes accordingly
- Weapon pick up.
- Check if a warrior has won.
- It is therefore very important that, at the beginning of an iteration, you store the beginning values for an offense strength and defence strength; these stored values are then the ones used for comparison during battle. This prevents the issue of different outcomes since the updates made during battle do not affect the comparisons for the next warrior in the battle. It is vitally important that you get this right, if the test cases are working it is a good indication that you have grasped the concept.
- It is highly advised that you do the following to aid in a neat and effective project implementation.
- Look at the provided skeleton code structure and understand why each element has been put in place.
- Take some time to plan your coding strategy before jumping in and writing a bunch of code that could end up looking a bit like spaghetti.
- Use modular programming techniques to simplify your code, ideally to the extent that your method names `talk’ you through the algorithm without even reading the comments yet. Modular programming will also help to identify and fix bugs in your code since functionally different segments of code will be held in different methods.
Your program should take in two command line arguments, the first argument naming the path to the game setup file and the second a 0 or 1 value where 0 indicates no use of the game visualisation and a 1 indicates the use of the game visualisation. When game visualisation is not used, your program should output warrior statistics in accord with Section 4.1; when the game visualisation is used then your program should output statistics in accord with Section 4.1 as well as output visualisation as described in Section 4.2. If you do not use the exact format described in the following sections, your output will not be marked.
The starting grid’s stats and thereafter the stats for each iteration of the game should be printed, your program should output command-line statistics for each warrior still present on the grid. If the number of iterations to run is zero then you should immediately print the statistics of the starting board. The output order should list the information for each warrior starting with the top left corner of the grid and ending with the bottom right corner of the grid. The grid should be traversed similarly to the pattern of ordering shown in Figure 4 (i.e. row for row (downwards direction), traversing the row cells left to right). If multiple warriors are present at one cell on the grid, the printing order should be in ascending order of the warrior object’s IDs.
Figure 4: Example grid traversal order
Each warrior’s statistics should be output on a new line and each value should be separated by a space and then a comma character. The values are id, age, health, offense power, defence strength, number of weapons in their inventory, the type of warrior they are (“Stone”, “Flame”, “Water” or “Air”), the row index and the column index of their position on the grid. See Table 1 for an example of this format.
Visualisation output should be printed to the command line in the format described below, once before any iterations (detailing the starting state stats) and then once after every iteration of the game execution; each visual grid should be matched with its statistics printed directly afterwards. Please see the sample output files provided on sunLearn for examples of the output format. If the number of game iterations is zero then you should print the visual representation of the starting grid, the warrior statistics and terminate. You have two options of output format, please specify in a ReadMe.txt file included in your submission whether you used the plain visualisation or the colourful visualisation output method since different scripts will be used depending on your choice. Please note that the marks will be exactly the same whether you choose the plain or the colourful output versions, it is purely a choice of your own preference and since there could be problems with plugin downloads etc in the case of the colourful version the plain version is absolutely sufficient.
After each iteration in the game execution, your program should print the updated grid in the format of example output Figure 5. Each piece type has a different character representation as defined in the list below; the displayed item for each cell should be separated by a space character and a new line must be printed after the final row (although not shown in the Figure 5 screenshot).
- A water warrior is represented by a `W’ character.
- A stone warrior is represented by a `S’ character.
- A flame warrior is represented by a `F’ character.
- An air warrior is represented by a `A’ character
- An empty cell is represented by a `.’ character.
- A potion piece is represented by a ‘p’ character.
- A healer piece is represented by a ‘h’ character.
- A magic crystal piece is represented by a ‘c’ character.
- A weapon piece is represented by a ‘x’ character.
- A water piece is represented by a ‘w’ character.
Since different pieces may overlap and occupy the same cell at the same time the order of visualisation priority is as follows where those pieces higher in the list should be prioritised in the display over those lower in the list.
- If multiple warriors are present on a cell at one time, an integer number representing the number of warriors on the cell should be used instead of a warrior character.
- Magic crystal.
- Empty Cell
If an iteration occurs where only 1 warrior is present on the grid, your program must print the grid as described above and follow it with the string “A warrior has been proven victor!”. The game playout should be terminated at this point and nothing else printed.
If an iteration occurs where 0 warriors are present on the grid, your program must print the grid as described above and follow it with the string “No warriors are left!”. The game playout should be terminated at this point and nothing else printed.
The colourful visualisation allows certain piece types to be colour coded. The format follows the rules in Section 4.2.1 but uses ANSI Escape Codes to produce colour-coded command-line output. These ANSI escape codes can be used in linux terminal and IntelliJ IDE without any extra plugin downloads/setting changes but eclipse necessitates a plugin download before the colours will display in the eclipse console; instructions for this are listed below.
Eclipse ANSI Escape Code plugin instructions:
- Click on the Help tab of eclipse
- Click on `Eclipse MarketPlace…’
- Type in “ANSI Escape in Console” into the search bar.
- Click install to the plugin named “ANSI Escape in Console” (see Figure 6)
- Accept the terms of the license agreement.
- Restart Eclipse
- Your eclipse should now have the required functionality. Please note that your may prefer the way the colours display in eclipse’s dark theme but it is up to your own preferences what you prefer. You can change the theme by going to eclipse’s Window tab, Preferences, General, Appearance and then select the dark theme (a restart may be required).
It is of the utmost importance that you use the colour codes defined in ConsoleColours.java (on the SunLearn 144 home page under Project 2020). You should add this colour library to your project and use printing statements in the format of Figure 8 instead of those ordinarily formatted as Figure 7.