diff --git a/.gitignore b/.gitignore
index 2873e189e1..7c0eb941cd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,6 @@ bin/
/text-ui-test/ACTUAL.TXT
text-ui-test/EXPECTED-UNIX.TXT
+
+#custom
+/data
diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..13eae68f38
--- /dev/null
+++ b/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: main.CalculaChroniclesOfTheAlgorithmicKingdom
+
diff --git a/README.md b/README.md
index f82e2494b7..ffd2d4313d 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Duke project template
+# Game
This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it.
diff --git a/build.gradle b/build.gradle
index ea82051fab..c44faf18ad 100644
--- a/build.gradle
+++ b/build.gradle
@@ -29,11 +29,11 @@ test {
}
application {
- mainClass.set("seedu.duke.Duke")
+ mainClass.set("main.CalculaChroniclesOfTheAlgorithmicKingdom")
}
shadowJar {
- archiveBaseName.set("duke")
+ archiveBaseName.set("Release v2.1")
archiveClassifier.set("")
}
@@ -42,5 +42,7 @@ checkstyle {
}
run{
+ enableAssertions = true
standardInput = System.in
+ enableAssertions = true
}
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 0f072953ea..b180aa580f 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -1,9 +1,10 @@
# About us
-Display | Name | Github Profile | Portfolio
---------|:----:|:--------------:|:---------:
- | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
- | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
- | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
- | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
- | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
+ Display | Name | Github Profile | Portfolio
+-----------------------------------------------------|:-----------:|:--------------------------------------:|:---------------------------------:
+  | Aarav Rawal | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
+  | Tanner Lie | [Github](https://github.com/tannerlie) | [Portfolio](team/tannerlie.md)
+  | Fang Sihan | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
+  | Samuel | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
+
+
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 64e1f0ed2b..c3ca0d2e15 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -1,38 +1,263 @@
# Developer Guide
-## Acknowledgements
+## Design
-{list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well}
+### Architecture
-## Design & implementation
+Given below is a higher-level overview of the main components for the app to work.
-{Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.}
+```Main``` has methods which are responsible for:
+1. App launch: Initialises the various classes needed and starting up the game
+2. App running: Calls the various methods in other Classes to run the game
+3. App shutdown: Saves the game state
+
+listed below are a collection of classes used by multiple components which will be generalised as ```Commons```.
+1. ```TextBox``` which is used to set all the messages and narrations for the user.
+2. ```FileReader``` to read our design.txt files in order to print certain screens.
+3. ```PlayerStatus``` which stores the status and inventory of the player.
+
+```Ui``` responsible for displaying the game's UI, interactions and narrations to the user.
+```Storage``` responsible for saving the current state of the game when quitting the app.
+```Parser``` is a collection of classes that converts the user's commands and starts the command execution process.
+```Map``` is a collection of classes that handles the data that is being printed to the main portion of the screen.
+
+Below is how some of the architecture components would interact with each other when the user inputs the command to move.
+
+
+
+The section below gives more details of each component.
+### UI Component (Ui class)
+
+
+
+The Ui class is responsible for managing the user interface aspects of the application. It handles the display
+of various elements such as player status, text boxes, maps, inventory, help menu, and messages.
+
+The `Ui` Component,
+- contains only one class `Ui.java` for Ui related job
+- depends on attributes such as `mapData` or `shopItems` in other classes to print
+### Parser Component (Parser class)
+
+
+
+The Parser class package is designed to analyze and parse user commands in a text-based adventure game scenario.
+It processes user input and determines the appropriate action to take based on predefined command types.
+
+The `parser` component,
+- provides method to read text-based user command
+- analyzes and returns the corresponding command type based on the text-based user command
+
+### User Command Component
+
+User can type command to do things on the Map.
+
+If the user type the command, `parseCommand` function will be called. After that, the original input will be
+analyzed by `analyseCommand` function to see if it matches a kind of `CommandType`. Then, we will return new
+Command back to the main based on the command type. The Final step is to call the `execute` function. If the command
+is the type of `fightCommand`, we will call the execute function with one parameter `Scanner`. For all other
+conditions, we will call the execute function with no parameter.
+
+### Map Component: Overview
+
+The API of this component is defined in BaseMap.java.
+
+Each map instance is associated with a 2-dimensional array of characters which represents the
+printed map for the player, all the printable data is stored in the `MapData` for each instance of a map.
+All maps will come with a given `height` and `width`, all of these attributes are inherited
+from the AMap abstract class. Currently, the `FirstMap` and `BattleInterface` classes
+extend AMap. `FirstMap` is the first map displayed upon entering the game and it displays the position of the player.
+The `BattleInterface` is the map displayed when the player interacts with an `interactable`.
+
+The `MapGenerator` is a class that handles the random generation of the enemies and the location of the shop, and is
+only used in `FirstMap` only.
+
+The following image shows the architecture of the Map component
+
+
+
+
+The reason why the player's map(FirstMap), the shop's interface and the battle interface all extend off of the `BaseMap`
+class is because during the game loop, these maps are being cycled through as the main screen the user will view. When
+an `Enemy` is interacted with and the [FIGHT] command is used, the `enableFight` is executed for either the Enemy, this
+also applies for the Shop. `enableFight` is another game loop that handles all the user - Enemy or user - ShopKeeper
+interactions.
+
+### Map Component: ShopMap Class
+
+The API of this class is defined in ShopMap.java.
+
+There exists only 1 shop at any given time during gameplay. During an interaction with the shop. A new separate gameloop
+ will execute. This comes from the execution of `enableFight`. Below is the diagram that displays how the `enableFight`
+method works.
+
+
+
+
+This is the general flow of `enableFight`.
+
+1. Enter game loop.
+2. Print player status, the shopkeeper and the text box.
+3. Get a command from the user.
+4. if a valid purchase is detected the purchase is processed.
+5. push dialogue to the text box.
+6. repeat until the command given is "exit".
+
+This general flow is also similar to that of the battleInterface's enableFight. However, in the battleInterface, the
+fight loop only ends when either the player or the enemy dies.
+
+### Interacting with Environment Component
+
+The API of this component is defined in InteractingCommand.java
+
+
+
+
+This component happens when the user chooses to key the interact command ```e```.
+Here is how it works:
+1. When the user chooses to fight, the command is parsed.
+2. The ```CalculaChroniclesOfTheAlgorithmicKingdom``` component then calls the execute() method in ```InteractingCommand```.
+3. It executes the method and creates other objects like ```Enemy``` and ```ShopKeaper``` components which are responsible for the
+entity classes in the game and also ```BattleInterface``` and ```ShopMap``` which are responsible for displaying these entities among other things.
+4. The ```BattleInterface``` or ```ShopKeeper``` will then read from a .txt file to store their displays by creating the ```FileReader``` object and
+running their respective methods.
+5. These displays, textboxes and player status will then be subsequently printed by the ```CalculaChroniclesOfTheAlgorithmicKingdom``` object.
+
+### Battling Component
+
+The API of this component is defined in FightCommand.java.
+
+
+
+
+This component occurs when the user chooses to fight an enemy after interacting with it using the command
+```f``` or ```fight```.
+Here is how it works:
+1. When the user chooses to fight, the command is parsed.
+2. The ```CalculaChroniclesOfTheAlgorithmicKingdom``` object then calls the execute() method in ```FightCommand``` and enables the fighting.
+3. The ```MathPool``` object is created, which is responsible for the math questions to answer and another ```Ui``` object is created to interact with the user.
+4. In the enableFight() method, it has a loop which asks the user math questions to answer until the player or enemy dies. The player takes damage for
+every wrong answer and deals damage to the enemy for every correct answer.
+5. In this loop, there is another loop to parse the answer given by the user, and displays an error message and the same math question
+until the user gives an answer which is a valid integer.
+6. Once either the player or enemy dies, it then exits and runs the relevant checks to eventually print the output to be shown to
+the user after battle, handled by ```CalculaChroniclesOfTheAlgorithmicKingdom```.
+
+### Item Usage Component
+
+The API of the following component is defined in OpenInventoryCommand.java.
+
+
+
+This component occurs when the user decides to open up the inventory. The user opens up the inventory using the command ```i```
+or ```inventory```.
+Here is how it works:
+1. When the user chooses to open the inventory, the command is parsed.
+2. The ```CalculaChroniclesOfTheAlgorithmicKingdom``` object then calls the execute() method in ```OpenInventoryCommand```to get
+the inventory from the stored maps in ```BaseMap```.
+3. The inventory would then be printed on the Ui for display.
+
+The API of the following component is defined in UseCommand.java.
+
+
+
+This component occurs when the user decides to use an item after navigating to the inventory page containing consumable items.
+Here is how it works:
+1. When the user chooses to use an item after navigating to the consumable items page, the command is parsed.
+2. The ```CalculaChroniclesOfTheAlgorithmicKingdom``` object then calls the execute() method
+3. The method goes through the necessary checks to check if the item intended to use has been indicated as stated in the UserGuide.
+4. If any of the checks fail, an error message would be displayed to flag out what went wrong.
+5. If all the checks passes, the inventory is obtained from the ```PlayerStatus``` object. The inventory is then searched to check if it
+contains the item.
+6. The method useItem(item) in the ```PlayerInventory``` object is called if the item is found. Subsequently,
+an error message is printed outlining the error.
+
+## Implementation
+### Saving feature
+In the main class, the saving is done in every loop through a method called `saveAllGameFile`.
+The following sequence diagram shows how methods are called during saving mechanism.
+
+
+
## Product scope
### Target user profile
-{Describe the target user profile}
+Our target users are young students who are hoping the revise their mathematical skills.
### Value proposition
-{Describe the value proposition: what problem does it solve?}
+It allows the target user to supplement their existing revision with a more fun and interacting way to revise their mathematics knowledge.
## User Stories
-|Version| As a ... | I want to ... | So that I can ...|
-|--------|----------|---------------|------------------|
-|v1.0|new user|see usage instructions|refer to them when I forget how to use the application|
-|v2.0|user|find a to-do item by name|locate a to-do without having to go through the entire list|
+| Priority | As a ... | I want to ... | So that I can ... |
+|----------|----------------|----------------------------------------------------------|---------------------------------------------------------|
+| *** | new player | get access to a help menu | refer to them when I don't know the commands to proceed |
+| *** | player | see a map of the play area | see the map and location in real-time |
+| *** | player | move around at will | explore the world as I want to |
+| *** | player | have an ending to the game | win the game |
+| *** | player | be able to track stats/items | gauge how my characters progress |
+| *** | player | save my game | come back and finish it when I have time |
+| *** | player | have a death and restart mechanic | add challenge to the game |
+| ** | player | be able to fight entities | battle in and interactive way |
+| ** | player | collect items | enhance my character |
+| ** | player | interact with things in the environment | be more immersed into the game |
+| ** | player | see an actual image of the characters | know what I am fighting against |
+| ** | student player | have variations in the questions asked | revise more stuff rather than the same questions |
+| ** | player | have clear distinctions between entities I interact with | have a clearer picture of what I'm doing |
+| ** | student player | refresh my knowledge of math | revise as I play at the same time |
+| * | player | know the background of this game | follow the storyline |
+| * | player | see funny and engaging dialogue | enjoy the story |
+| * | player | have access to hints to the questions | make calculations easier |
-## Non-Functional Requirements
-{Give non-functional requirements}
+## Non-Functional Requirements
-## Glossary
+1. Should work on any Windows, Linux, Unix as long as it has Java 11 or above installed.
+2. Users should be able to use the app without problems with basic CLI knowledge.
+3. A student user should be able to complete the game by answering all the questions.
-* *glossary item* - Definition
## Instructions for manual testing
-{Give instructions on how to do a manual product testing e.g., how to load sample data to be used for testing}
+### Launch and Shutdown
+1. Initial launch
+ 1. Download the jar file and copy it into an empty folder.
+ 2. In your command line interface (CLI), navigate to the directory the jar file is in
+ and enter this command ```java -jar Release.v2.1.jar```.
+2. Saving the game
+ 1. When you feel like closing the game, enter the command ```quit``` or ```q```.
+ 2. This will close and save the game for when you're ready to come back.
+
+### Game Movement
+1. The game controls utilises w, a, s and d keys to move about as we are all familiar with. ```w``` is for moving upwards,
+```a``` is for moving leftwards, ```s``` is for moving downwards and ```d``` is for moving rightwards.
+2. Enter ```s``` in the command line and the character represented by the symbol P will move 1 space downwards. A space is denoted by a ```.``` on the map.
+3. To move multiple spaces at a time, you may enter a movement direction followed by an integer with a space between them.
+e.g. ```s 3```
+
+### Interacting with entities
+1. An interactable entity is denoted by a character on the map.
+2. The ```#``` character denotes the shop to buy items and the rest is for you to explore and find out.
+3. Navigate next to a character and enter ```e``` to interact with it.
+4. There will be prompts in the game to help you navigate the interactions.
+
+### Battling
+1. Interacting with an enemy will trigger a battle prompt.
+2. ```r``` or ```run``` will allow u to eun away if you're not ready to face the enemy.
+3. ```f``` or ```fight``` will trigger the battling sequence where the aim is to get the math questions correct
+in order to chip away at the enemies health to defeat it.
+4. All answers to the questions are integers.
+5. Upon successfully defeating the enemy, exp and money is obtained.
+
+### Shop
+1. Once enough money is accumulated, items can be bought from the shop in order to defeat persistent enemies.
+2. Interacting with the shop will bring up a page to enter or exit the shop.
+3. Key in the command to enter the shop to be greeted with items to purchase.
+4. In order to purchase an item enter the index of the item, e.g. ```1```.
+
+### Item usage
+1. In order to use the items, open up the inventory using the ```i``` or ```inventory``` command.
+2. To use an item of index item 1, enter the command ```use 1``` .
+3. This only works if there are items in your inventory.
\ No newline at end of file
diff --git a/docs/README.md b/docs/README.md
index bbcc99c1e7..9c68c3ef98 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,8 +1,14 @@
-# Duke
+# CalculaChroniclesOfTheAlgorithmicKingdom
-{Give product intro here}
-
-Useful links:
+CalculaChroniclesOfTheAlgorithmicKingdom is an open-world game played on the CLI. It aims to provide a fun and interactive
+way for younger students to learn/revise their mathematics knowledge. It is equipped with full player autonomy to explore,
+interact with shops and their inventory as well as slaying monsters with their wits and intellect by solving mathematical problems.
+
+Below is a list of links for our project:
* [User Guide](UserGuide.md)
* [Developer Guide](DeveloperGuide.md)
* [About Us](AboutUs.md)
+* [B1G-SAM PPP](team/b1g-sam.md)
+* [bestdownloader365 PPP](team/bestdownloader365.md)
+* [tannerlie PPP](team/tannerlie.md)
+* [aaravrawal_PPP](team/aaravrawal.md)
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index abd9fbe891..68a909779d 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -2,41 +2,147 @@
## Introduction
-{Give a product intro}
+Welcome to CalculaChroniclesOfTheAlgorithmicKingdom. This is a simple text based
+game. Your goal in this game is to defeat the enemies within and claim victory for yourself as a
+math wizard.
## Quick Start
-{Give steps to get started quickly}
1. Ensure that you have Java 11 or above installed.
-1. Down the latest version of `Duke` from [here](http://link.to/duke).
+2. Download the latest version of `CalculaChroniclesOfTheAlgorithmicKingdom` from [here](https://github.com/AY2324S2-CS2113-W12-3/tp/releases).
## Features
-{Give detailed description of each feature}
+### The Map
+This game displays the character's position on a 2D grid, the player is denoted by a `P`
+and the other interactable entities are denoted by other symbols. The entities on the map are randomly generated in each
+play through of the game.
-### Adding a todo: `todo`
-Adds a new item to the list of todo items.
+### The Player
+At all times, the player's health, money and exp is displayed at the top of the screen. Dropping the player's health
+to 0 will cause the player to die and the game is over.
+
+### The Text Box
+At all times, on the bottom part of the screen, a text box will be visible and it will be visible. The text box informs
+the player of narrations from the narrator, dialogue from the entities, general instructions from the user interface and
+also error messages when they occur.
+
+### Movement
+Traversing the map is similar to many common computer games. We use the "WASD" system such that
+entering `w` to the program shifts the player up by 1 space, entering `a` shifts the player to the left,
+entering `s` shifts the player down 1 space and lastly, entering `d` shifts the player to the right by 1 space.
+This movement can only take place when the 2D grid map is visible.
+
+Additionally, should the player wish to move more than 1 space at a time, the player can modify the directional commands
+by adding a number in this manner.
+
+E.g `d 10`
+
+The above command moves the player rightwards by 10 spaces.
+
+
+### Interacting
+
+To interact with any entity in the game the player first has to move towards the symbol and be within close proximity
+to the symbol. We define close as the player needing to be directly above, below, to the left or to the right of an
+entity symbol, in other words, there can be no gap in between the player and the entity and interactions cannot occur
+diagonally.
+
+To interact the player enters `e`.
+
+This action will bring up a new interface called the battle interface which can be for either battling enemies or accessing the shop.
+This interface will display an image that corresponds to the symbol on the map and gives you 2 options, to `run` or to `fight`.
+
+### Run
+
+Should the player, in the battle interface, determine that the enemy is too strong, the player may choose to type `run`
+to back out of the fight and return to the main map to continue moving around.
+
+### Fight
+
+Should the player, in the battle interface, wish to fight the enemy. Entering `fight` in the battle interface will
+start a fight. A series of math questions will appear based on the strength of the enemy. Generally, stronger enemies
+will come with harder math questions.
+
+The player will then enter the correct answer. The answer is guaranteed to be an integer. Getting the question correct
+will cause the player to attack the enemy and getting it wrong will cause the enemy to attack the player. Getting the
+questions wrong repeatedly will deplete the player's health and once the player's health reaches 0, the player dies and
+the game is over. However, depleting the enemy's health to 0 will result in a victory and the player is rewarded with
+some gold and exp before returning the player to the main map.
+
+
+### Items
+
+There are various consumables the player can acquire throughout the game. The items are consumable items, meaning the
+item can be only used once before it is destroyed. There are 2 general types of items, the healing item and the damage
+item. Healing items will recover the player's health, if the player's health is already maxed out at
+100hp(health points), the healing item will OVER-HEAl and increase the player's health past the initial 100hp. Damage
+items will empower the player's next attack to do increased damage on a successful hit.
+
+### Shop
+
+Items are purchasable at the shop denoted by a '#' on the map. Interacting with the shop causes the player to enter the
+shop. Just like the enemies, the player must enter `fight` to browse the shop's items. After entering the shop, buy an
+item by entering the index of the item and the item will automatically be purchased and transferred to the Inventory.
+The purchase will only go through if the player has enough money. To exit the shop, the player enters `exit`.
+
+### Inventory
+
+The inventory of the player can only be accessed when the player is not currently interacting with an entity. To bring
+up the inventory the player enters `i`. To use an item the player enters the keyword `use` followed by the index of the
+item.
+
+E.g `use 1`
+
+To close the inventory, the player enters `close`.
+
+### Hints
+
+Sometimes, hints are scattered throughout the map such that some text will display just below the map to help the
+player, hints are entirely passive and no user input is required for the hints to trigger.
+
+### Quit
+
+Enter `q` to quit the game. The game is automatically saved.
+
+
+### Help
+
+If you need a refresher on the controls, entering either `h` or `help` will bring up a set of instructions.
+
+### Saving
+
+Our program can save map when you are playing the game.
+Also, it will save the player status and your inventory items
+Please Note: After buying things in shop or fighting with a monster, you have to move on the map to save your file.
+
+### Reset
+
+Should a reset be necessary, the player can completely wipe the current progress of the game and regenerate a new game
+at ANY POINT IN THE GAME by entering `reset`.
-Format: `todo n/TODO_NAME d/DEADLINE`
-* The `DEADLINE` can be in a natural language format.
-* The `TODO_NAME` cannot contain punctuation.
-Example of usage:
-`todo n/Write the rest of the User Guide d/next week`
-`todo n/Refactor the User Guide to remove passive voice d/13/04/2020`
## FAQ
-**Q**: How do I transfer my data to another computer?
+**Q**: Is there any prerequisite to run the application.
-**A**: {your answer here}
+**A**: Java 11 needs to be installed and the jar file must be in an empty folder before running.
## Command Summary
-{Give a 'cheat sheet' of commands here}
-
-* Add todo `todo n/TODO_NAME d/DEADLINE`
+`w` `a` `s` `d` to move around
+`e` to interact
+`q` to quit
+`h` to print help menu
+`run` to escape the battle interface
+`fight` to commence a fight
+`i` to bring up inventory
+`close` to leave inventory
+`exit` to leave the shop
+`reset` to reset the entire game and start a new game.
+ All math questions have integer answers.
diff --git a/docs/diagrams/Architecture.puml b/docs/diagrams/Architecture.puml
new file mode 100644
index 0000000000..89985d3b41
--- /dev/null
+++ b/docs/diagrams/Architecture.puml
@@ -0,0 +1,26 @@
+@startuml
+box Architecture
+participant "User" as user
+participant ":CalculaChroniclesOfTheAlgorithmicKingdom" as main
+participant ":UI" as ui
+participant ":Parser" as parser
+participant ":MoveRightCommand" as command
+
+user -> main : "w"
+activate main
+main -> parser : parseCommand()
+activate parser
+parser --> main : command
+deactivate parser
+main -> command : execute()
+activate command
+command --> main
+deactivate command
+main -> ui : print()
+activate ui
+ui --> user
+deactivate ui
+user -> main : "d"
+
+end box
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/BattleInterface.puml b/docs/diagrams/BattleInterface.puml
new file mode 100644
index 0000000000..04b8cf37d3
--- /dev/null
+++ b/docs/diagrams/BattleInterface.puml
@@ -0,0 +1,123 @@
+@startuml
+
+box Battle Component
+participant ":CalculaChroniclesOfTheAlgorithmicKingdom" as main
+participant ":UI" as ui
+participant ":Parser" as parser
+participant ":TextBox" as text
+participant ":FightCommand" as f
+participant ":PlayerStatus" as player
+participant ":Enemy" as e
+participant ":BattleInterface" as bi
+participant ":FileReader" as fileReader
+participant ":Map" as map
+participant ":MathPool" as mathpool
+
+'activate main
+'main -> parser : parseCommand(userCommandText)
+'activate parser
+'create f
+'parser -> f
+'activate f
+'f --> parser
+'deactivate f
+'parser --> main : command class
+'deactivate parser
+'main -> main : executeCommand()
+activate main
+main -> f : execute()
+activate f
+f -> bi : enableFight()
+activate bi
+create mathpool
+bi -> mathpool
+activate mathpool
+mathpool --> bi
+deactivate mathpool
+bi -> mathpool : init()
+activate mathpool
+mathpool --> bi
+deactivate
+create ":UI" as UI
+bi -> UI
+activate UI
+UI --> bi
+deactivate UI
+loop player and enemy is alive
+ bi -> player : getPlayerHealth()
+ activate player
+ player --> bi : player health
+ deactivate player
+ bi -> e : getHealth()
+ activate e
+ e --> bi : enemy health
+ deactivate e
+ bi -> UI : printPlayerStatus(currentPlayer)
+ activate UI
+ UI --> bi
+ deactivate UI
+ bi -> UI : printMap(mapData, currentEntity)
+ activate UI
+ UI --> bi
+ deactivate UI
+ bi -> mathpool : getQuestionByDifficulty(difficulty);
+ activate mathpool
+ mathpool --> bi : question
+ deactivate mathpool
+ bi -> UI : printQuestion(question)
+ activate UI
+ UI --> bi
+ deactivate UI
+ loop command is not an integer
+ bi -> text : setNextError(error)
+ activate text
+ text --> bi
+ deactivate text
+ bi -> text : setNextInstruction(question)
+ activate text
+ text --> bi
+ deactivate text
+ bi -> UI : printTextBox()
+ activate UI
+ UI --> bi
+ deactivate UI
+ end
+ alt correct answer
+ bi -> bi : playerHitEnemy()
+ else wrong answer
+ bi -> bi : enemyHitPlayer()
+ end
+end
+bi --> f
+deactivate bi
+alt enemy died
+ f -> map : getInteractX()
+ activate map
+ map --> f : x coordinate
+ deactivate map
+ f -> map : getInteractY()
+ activate map
+ map --> f : y coordinate
+ deactivate map
+ f -> map : clearSpot(x coordinate, y coordinate)
+ activate map
+ map --> f
+ deactivate map
+ f -> map : handleLootingByPlayer()
+ activate map
+ map --> f
+ deactivate map
+else player died
+ f -> map : handleDeath();
+ activate map
+ map --> f
+ deactivate map
+end
+f --> main
+deactivate f
+
+
+
+end box
+
+@enduml
diff --git a/docs/diagrams/Command.puml b/docs/diagrams/Command.puml
new file mode 100644
index 0000000000..3fcf96b717
--- /dev/null
+++ b/docs/diagrams/Command.puml
@@ -0,0 +1,9 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+
+Alice -> Bob: Authentication Request
+Bob --> Alice: Authentication Response
+
+Alice -> Bob: Another authentication Request
+Alice <-- Bob: another authentication Response
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/Interaction.puml b/docs/diagrams/Interaction.puml
new file mode 100644
index 0000000000..69898d2d18
--- /dev/null
+++ b/docs/diagrams/Interaction.puml
@@ -0,0 +1,118 @@
+@startuml
+
+box Battle Component
+participant ":CalculaChroniclesOfTheAlgorithmicKingdom" as main
+participant ":UI" as ui
+participant ":Parser" as parser
+participant ":TextBox" as text
+participant ":InteractingCommand" as iCommand
+participant ":Enemy" as e
+participant ":BattleInterface" as bi
+participant ":ShopKeeper" as staff
+participant ":ShopMap" as shopMap
+participant ":FileReader" as fileReader
+participant ":Map" as map
+
+activate main
+'main -> parser : parseCommand(userCommandText)
+'activate parser
+'create iCommand
+'parser -> iCommand
+'activate iCommand
+'iCommand --> parser
+'deactivate iCommand
+'parser --> main : command class
+'deactivate parser
+'main -> main : executeCommand()
+'activate main
+main -> iCommand : execute()
+activate iCommand
+iCommand -> map : handleInteract()
+activate map
+map --> iCommand : entity
+deactivate map
+alt noEntityToInteract
+ iCommand -> text : setNextNarration(narration)
+ activate text
+ text --> iCommand
+ deactivate text
+else hasEntityToInteract
+ iCommand -> text : setNextNarration(narration)
+ activate text
+ text --> iCommand
+ deactivate text
+ iCommand -> text : setNextInstruction(instruction)
+ activate text
+ text --> iCommand
+ deactivate text
+end
+iCommand -> map : getInteractX()
+activate map
+map --> iCommand : x coordinate
+deactivate map
+iCommand -> map : getInteractY()
+activate map
+map --> iCommand : y coordinate
+deactivate map
+alt is enemy
+ create e
+ iCommand -> e
+ activate e
+ e --> iCommand
+ deactivate e
+ iCommand -> text : setNextDialogue(dialogue)
+ activate text
+ text -> iCommand
+ deactivate text
+ create bi
+ iCommand -> bi
+ activate bi
+ bi --> iCommand
+ deactivate bi
+ iCommand -> bi : initMap(width, height)
+ activate bi
+ create fileReader
+ bi -> fileReader
+ activate fileReader
+ fileReader --> bi
+ deactivate fileReader
+ bi -> fileReader : readEnemyDesign()
+ activate fileReader
+ fileReader --> bi : enemy display map
+ deactivate fileReader
+ bi --> iCommand
+ deactivate bi
+else is a shop
+ create staff
+ iCommand -> staff
+ activate staff
+ staff --> iCommand
+ deactivate staff
+ create shopMap
+ iCommand -> shopMap
+ activate shopMap
+ shopMap --> iCommand
+ deactivate shopMap
+end
+iCommand --> main
+deactivate iCommand
+'deactivate main
+'main -> main : printMessageUnderMap(userCommand, ui, playerStatus, textBox)
+'activate main
+'alt not calling help menu or quitting game
+' alt show battle interface
+' main -> ui : printEnemy(currentMap)
+' activate ui
+' ui --> main
+' deactivate ui
+' else
+' main -> ui : printMap(currentMap)
+' activate ui
+' ui --> main
+' deactivate ui
+' end
+'end
+
+end box
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/ItemUsage.puml b/docs/diagrams/ItemUsage.puml
new file mode 100644
index 0000000000..3672e3dc4d
--- /dev/null
+++ b/docs/diagrams/ItemUsage.puml
@@ -0,0 +1,62 @@
+@startuml
+box
+participant ":CalculaChroniclesOfTheAlgorithmicKingdom" as main
+participant ":UseCommand" as use
+participant ":TextBox" as text
+participant ":PlayerStatus" as status
+participant ":BaseMap" as map
+participant ":PlayerInventory" as inventory
+
+activate main
+main -> use : execute()
+activate use
+opt current screen displayed is consumable inventory screen
+use -> text : setNextInstruction(instruction)
+activate text
+text --> use
+deactivate text
+use -> text : setNextError(error)
+activate text
+text --> use
+deactivate text
+use --> main
+end
+opt consumable list is empty
+use -> text : setNextError(error)
+activate text
+text --> use
+deactivate text
+use --> main
+end
+opt item not specified
+use -> text : setNextError(error)
+activate text
+text --> use
+deactivate text
+use --> main
+end
+opt item index was not a valid integer
+use -> text : setNextError(error)
+activate text
+text --> use
+deactivate text
+end
+use -> status : getPlayerInventory()
+activate status
+status --> use
+deactivate status
+opt item index doesn't exist
+use -> text : setNextError(error)
+activate text
+text --> use
+deactivate text
+use --> main
+end
+use -> inventory : useItem(item)
+activate inventory
+inventory --> use
+deactivate inventory
+use --> main
+deactivate use
+end box
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/Map.puml b/docs/diagrams/Map.puml
new file mode 100644
index 0000000000..68a8b59a09
--- /dev/null
+++ b/docs/diagrams/Map.puml
@@ -0,0 +1,58 @@
+## AMap Class Diagram
+@startuml
+hide circle
+
+
+ class BaseMap {
+- currentMap : int (static)
+- storedMaps : ArrayList (static)
++ movePlayerUpOne() : void
++ movePlayerDownOne() : void
++ movePlayerLeftOne() : void
++ movePlayerRightOne() : void
++ handleInteract() : String
+ }
+
+ class FirstMap {
++ isWon() : boolean
+ }
+
+ class MapGenerator {
+ + generateMap() : void
+ }
+
+ class ShopMap {
+ - currentPlayer : PlayerStatus
+ - currentTextBox : TextBox
+ - currentEntity : ShopKeeper
+ - inventory : PLayerInventory
+ + enableFight(Scanner in) : void
+ }
+
+ class BattleInterface {
+ - currentPlayer : PlayerStatus
+ - currentTextBox : TextBox
+ - currentEntity : InteractableEntity
+ + enableFight() : void
+ }
+
+ class PLayerInventory {
+ - currentTextBox : TextBox
+ - playerstatus : PlayerStatus
+ + useItem(Consumable item)
+ }
+
+
+
+ BaseMap <|-- FirstMap
+ BaseMap <|-- ShopMap
+ BaseMap <|-- BattleInterface
+ BaseMap <|-- PLayerInventory
+
+
+@enduml
+
+
+
+
+## AMap Sequence Diagram
\ No newline at end of file
diff --git a/docs/diagrams/OpenInventory.puml b/docs/diagrams/OpenInventory.puml
new file mode 100644
index 0000000000..d950fb4397
--- /dev/null
+++ b/docs/diagrams/OpenInventory.puml
@@ -0,0 +1,17 @@
+@startuml
+box
+participant ":CalculaChroniclesOfTheAlgorithmicKingdom" as main
+participant ":OpenInventoryCommand" as open
+participant ":BaseMap" as map
+
+activate main
+main -> open : "execute()"
+activate open
+open -> map : "get(INVENTORY_IDENTITY)"
+activate map
+map --> open : inventory
+deactivate map
+open --> main
+deactivate open
+end box
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/Parser.puml b/docs/diagrams/Parser.puml
new file mode 100644
index 0000000000..b2ada50c98
--- /dev/null
+++ b/docs/diagrams/Parser.puml
@@ -0,0 +1,29 @@
+@startuml
+hide circle
+skinparam classAttributeIconSize 0
+
+class Parser{
+{method} +parseCommand(userCommand:String) : Command
+}
+enum "<>\nCommandType" as CommandType{
+FIGHT
+RUN
+MOVE_FORWARD
+MOVE_DOWNWARD
+MOVE_LEFT
+MOVE_RIGHT
+INTERACT
+QUIT
+HELP
+EXIT
+ERROR
+INVENTORY
+USE_ITEM
+CLOSE_INV
+RESET
+}
+
+Parser ..> CommandType
+
+hide CommandType method
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/SavingFeature.puml b/docs/diagrams/SavingFeature.puml
new file mode 100644
index 0000000000..4b3446ef1e
--- /dev/null
+++ b/docs/diagrams/SavingFeature.puml
@@ -0,0 +1,45 @@
+@startuml
+hide footbox
+
+actor User
+
+
+participant ":CalculaChroniclesOfTheAlgorithmicKingdom" as mainClass
+participant ":MapStorage" as MapStorage
+participant ":PlayerStatusStorage" as PlayerStatusStorage
+participant ":InventoryItemsStorage" as InventoryItemsStorage
+
+
+loop until the command type is QuitCommand
+ User -> mainClass:type a random command
+ activate mainClass
+ mainClass -> mainClass: setUserCommand(...)
+ activate mainClass
+ deactivate mainClass
+ mainClass -> mainClass: executeCommand(...)
+ activate mainClass
+ deactivate mainClass
+ mainClass -> mainClass: printMessageUnderMap(...)
+ activate mainClass
+ deactivate mainClass
+ mainClass -> mainClass: saveAllGameFile(...)
+ activate mainClass
+ mainClass -> MapStorage:saveMap(map)
+ activate MapStorage
+ mainClass -> PlayerStatusStorage:savePlayerStatus(playerStatus)
+ activate PlayerStatusStorage
+ mainClass -> InventoryItemsStorage:saveFile(PLAYER_INVENTORY)
+ activate InventoryItemsStorage
+ deactivate mainClass
+ deactivate MapStorage
+ deactivate PlayerStatusStorage
+ deactivate InventoryItemsStorage
+end
+
+deactivate mainClass
+
+destroy mainClass
+destroy MapStorage
+destroy PlayerStatusStorage
+destroy InventoryItemsStorage
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/ShopMap.puml b/docs/diagrams/ShopMap.puml
new file mode 100644
index 0000000000..2ac09fdadf
--- /dev/null
+++ b/docs/diagrams/ShopMap.puml
@@ -0,0 +1,42 @@
+@startuml
+actor Player
+participant ":ShopMap" as Shop
+participant ":Ui" as UI
+participant ":TextBox" as TextBox
+participant ":Scanner" as Scanner
+
+Player -> Shop : enableFight(Scanner)
+activate Shop
+
+Shop -> TextBox : queueTextBox()
+activate TextBox
+TextBox -> TextBox : setNextNarration("You are greeted...")
+TextBox -> TextBox : setNextDialogue(currentEntity.getDefaultMessage() + formatShop())
+TextBox -> TextBox : setNextInstruction("Give the shopkeeper...")
+deactivate TextBox
+
+loop while answerCommand != "exit"
+ Shop -> UI : printPlayerStatus(currentPlayer)
+ Shop -> UI : printShopKeeper(currentEntity)
+ Shop -> UI : printTextBox(currentTextBox)
+ UI --> Player : await command
+ Player -> Scanner : nextLine()
+ Scanner --> Shop : user command
+
+ alt answerCommand matches "\\d+"
+ Shop -> Shop : processPurchase(answerCommand)
+ else answerCommand == "run"
+ TextBox -> TextBox : setNextError("Invalid command...")
+ else else
+ TextBox -> TextBox : setNextError("Invalid command...")
+ end if
+
+ Shop -> TextBox : prepareNextDialogue()
+ TextBox --> Player : Display updated dialogue/instruction
+end
+
+Shop -> TextBox : clearAll()
+TextBox -> TextBox : setNextNarration("You exited the shop!!")
+deactivate Shop
+@enduml
+
diff --git a/docs/diagrams/Ui.puml b/docs/diagrams/Ui.puml
new file mode 100644
index 0000000000..79102a3a6f
--- /dev/null
+++ b/docs/diagrams/Ui.puml
@@ -0,0 +1,32 @@
+@startuml
+hide circle
+skinparam classAttributeIconSize 0
+
+class Ui
+class PlayerStatus
+class TextBox
+class "{abstract}\nBaseMap" as BaseMap{
+#mapData:ArrayList>
+}
+class Enemy
+class ShopKeeper{
+#shopItems:ArrayList
+}
+class InteractableEntity
+class BattleInterface
+class ShopMap
+class PlayerInventory
+class FirstMap
+
+Ui ..> PlayerStatus
+Ui ..> TextBox
+Ui ..> BaseMap
+Ui ..> Enemy
+Ui ..> ShopKeeper
+InteractableEntity <|-- ShopKeeper
+InteractableEntity <|-- Enemy
+BaseMap <|-- BattleInterface
+BaseMap <|-- ShopMap
+BaseMap <|-- PlayerInventory
+BaseMap <|-- FirstMap
+@enduml
\ No newline at end of file
diff --git a/docs/team/aaravrawal.md b/docs/team/aaravrawal.md
new file mode 100644
index 0000000000..35303cb0dc
--- /dev/null
+++ b/docs/team/aaravrawal.md
@@ -0,0 +1,28 @@
+# Aarav Rawal - Project Portfolio Page
+
+## Project: CalculaChroniclesOfTheAlgorithmicKingdom
+CalculaChroniclesOfTheAlgorithmicKingdom - Chronicles of the Algorithmic Kingdom. This is a simple text based
+game played entirely on the terminal. It is written in Java.
+
+### Summary of Contributions
+- Features:
+ - Implemented the interacting command class that allows user to interact with various entities in the map
+ - implemented the inventory class and shop class that allows user to purchase various items from the shop
+ - Implemente the Shop map class that displays the shop in the CLI
+ - Implemented the Math pool class and designed all questions in the game for increasing difficulty
+- ###### Additions:
+ - Added the functionality to exit the shop
+ - Added the functionality to progressivly increase math question difficulty
+
+
+- Code contributed
+ [RepoSense link](https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=aaravrawal52&breakdown=true&sort=groupTitle%20dsc&sortWithin=title&since=2024-02-23&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other).
+
+
+- Project management
+ - Documented the Architecture in the Developer Guide.
+ - Documented the InteractingCommand, usage and Item Usage component in the Developer Guide with the use of UML diagrams.
+
+- Community
+ - Reported an above-average number of bugs in the PE-D (9 bugs to be exact)
+
diff --git a/docs/team/b1g-sam.md b/docs/team/b1g-sam.md
new file mode 100644
index 0000000000..b15f92e5cb
--- /dev/null
+++ b/docs/team/b1g-sam.md
@@ -0,0 +1,39 @@
+# Samuel Chung - Project Portfolio Page
+
+## Project: CalculaChroniclesOfTheAlgorithmicKingdom
+CalculaChroniclesOfTheAlgorithmicKingdom - Chronicles of the Algorithmic Kingdom. This is a simple text based
+game played entirely on the terminal. It is written in Java.
+
+### Summary of Contributions
+- Features:
+ - Implemented BaseMap as a template class to allow seamless transitions between what is being displayed on the main
+ screen of the User Interface.
+ - Implemented BattleInterface to handle player-enemy interactions as well as to display relevant ASCII art for
+ aesthetics.
+ - Implemented ShopMap to handle player-ShopKeeper interactions as well as to display the relevant ASCII art.
+ - Implemented the HintHandler class which creates invisible triggers around the map which gives the player hints,
+ or messages, similar to other, currently existing, games.
+ - Implemented TextBox. TextBox is a class that supplements the main UI display towards the bottom of the screen.
+ It handles the error messages, narration messages, dialogue from entities, player instructions in a nicely
+ formatted manner.
+ - Implemented PlayerStatus. PlayerStatus is another supplementary class in addition to the main UI display. It
+ handles the tracking of the health, money and exp statistic of the player.
+ - Implemented the Math Package. This package allows the team to quickly create math questions and answers and sort
+ them by difficulty to properly determine the questions being asked by the various enemies on the map.
+ - Implemented the skeleton of the Consumable item class.
+
+
+- Code contributed
+ [RepoSense link](https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23&tabOpen=true&tabType=authorship&tabAuthor=B1G-SAM&tabRepo=AY2324S2-CS2113-W12-3%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false)
+
+
+- Project management
+ Created the first release of the User Guide.
+ Documented the Map component in the Developer Guide with the use of puml diagrams.
+
+
+- Community
+ - Created overall framework of the project with the help of bestdownloader365 at the start of the tp
+ - Reported "an above-average number of bugs in the PE-D (8 bugs to be exact)"(CS2113 Teaching Team, April 2024)
+ during the PE-D.
+
diff --git a/docs/team/bestdownloader365.md b/docs/team/bestdownloader365.md
new file mode 100644
index 0000000000..f0a595292f
--- /dev/null
+++ b/docs/team/bestdownloader365.md
@@ -0,0 +1,48 @@
+# Fang Sihan - Project Portfolio Page
+
+## Project: CalculaChroniclesOfTheAlgorithmicKingdom
+
+This is a simple text based game. Your goal in this game is to defeat the enemies within and claim victory
+for yourself as a math wizard. The user interacts with it using a CLI. It is written in Java 11.
+
+### Summary of Contributions
+
+- New Feature:
+ - Added the ability to use `w`, `a`, `s`, `d` command on the map.
+ - Added the ability to use `e` command to interact with shop or monsters.
+ - Added the ability to use `fight` or `run` command when the user is in battle interface.
+ - What it does: Created an inner loop framework in `FightingCommand` to interact with various
+ monsters' interfaces
+ or shop interface.
+ - Added the ability to save `map`, `player status` and `inventory` data in the local disk.
+ - What it does: It can save the player's playing status to ensure that they can read the archive
+ and
+ return to the place where they last played the next time they enter the game.
+ - Added a singleton pattern class `MapGenerator` for generating random map at the beginning of the
+ game.
+
+- Code contributed:
+ [RepoSense link](https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=fang&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23)
+
+
+- Project management:
+ - Create and manage the release `v1.0` - `v2.1` (3 releases) on Github
+ - The overall framework was written down by me and another teammate at the beginning of the project, and
+ the
+ framework was continuously optimized in the subsequent time.
+
+- Enhancements to existing features:
+ - Added exception handling in class `PlayerStatusStorage`
+ - Added new `execute(Scanner)` method to class `Command`, made fighting with monsters and entering shop
+ possible
+
+- Documentation:
+ - User Guide:
+ - Added documentation for the features `Saving` and `Inventory`
+ - Developer Guide:
+ - Added `Parser` and `Ui` component
+ - Added the implementation details of `Saving` feature
+
+- Community:
+ - Reported bugs and suggestions for other teams in the class (PE-D)
+
diff --git a/docs/team/tannerlie.md b/docs/team/tannerlie.md
new file mode 100644
index 0000000000..36cd5297d7
--- /dev/null
+++ b/docs/team/tannerlie.md
@@ -0,0 +1,30 @@
+# Tanner Lie - Project Portfolio Page
+
+## Project: CalculaChroniclesOfTheAlgorithmicKingdom
+CalculaChroniclesOfTheAlgorithmicKingdom - Chronicles of the Algorithmic Kingdom. This is a simple text based
+game played entirely on the terminal. It is written in Java.
+
+### Summary of Contributions
+- Features:
+ - Implemented a FileReader class and framework to read from our resources in order to display relevant ASCII art for the game.
+ - Created Enemy classes for different enemies and their art, as well as their printing methods.
+ - Implemented PlayerInventory class which stores the players' inventory equipped with logic to use items, add items, and to display the
+ items on the CLI.
+ - Implemented the commands in order to open up the inventory as well as the various methods mentioned above.
+ - Implemented many of the exceptions handling throughout the app.
+ - Cleaned up checkstyle violations.
+
+
+- Code contributed
+ [RepoSense link](https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=tannerlie&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23&tabOpen=true&tabType=authorship&tabAuthor=tannerlie&tabRepo=AY2324S2-CS2113-W12-3%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code~other&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false).
+
+
+- Project management
+ - Documented the Architecture in the Developer Guide.
+ - Documented the BattleInterface, Interacting, Inventory usage and Item Usage component in the Developer Guide with the use of puml diagrams.
+ - Documented the User Stories, nonfunctional requirements and manual testing guide in the Developer Guide.
+
+
+- Community
+ - Reported "an above-average number of bugs in the PE-D (8 bugs to be exact)"(CS2113 Teaching Team, April 2024)
+ during the PE-D.
\ No newline at end of file
diff --git a/picture/ArchitectureSequenceDiagram.png b/picture/ArchitectureSequenceDiagram.png
new file mode 100644
index 0000000000..a227542d64
Binary files /dev/null and b/picture/ArchitectureSequenceDiagram.png differ
diff --git a/picture/BattleInterface.png b/picture/BattleInterface.png
new file mode 100644
index 0000000000..3f71b5ce1b
Binary files /dev/null and b/picture/BattleInterface.png differ
diff --git a/picture/Command.svg b/picture/Command.svg
new file mode 100644
index 0000000000..3625e977e0
--- /dev/null
+++ b/picture/Command.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/picture/Interaction.png b/picture/Interaction.png
new file mode 100644
index 0000000000..6e2c2f0123
Binary files /dev/null and b/picture/Interaction.png differ
diff --git a/picture/ItemUsage.png b/picture/ItemUsage.png
new file mode 100644
index 0000000000..6c53663630
Binary files /dev/null and b/picture/ItemUsage.png differ
diff --git a/picture/Map.png b/picture/Map.png
new file mode 100644
index 0000000000..4723146448
Binary files /dev/null and b/picture/Map.png differ
diff --git a/picture/OpenInventory.png b/picture/OpenInventory.png
new file mode 100644
index 0000000000..81c53b8702
Binary files /dev/null and b/picture/OpenInventory.png differ
diff --git a/picture/Parser.png b/picture/Parser.png
new file mode 100644
index 0000000000..34c64226d1
Binary files /dev/null and b/picture/Parser.png differ
diff --git a/picture/SavingFeature.png b/picture/SavingFeature.png
new file mode 100644
index 0000000000..c2c242c7ee
Binary files /dev/null and b/picture/SavingFeature.png differ
diff --git a/picture/ShopMap.png b/picture/ShopMap.png
new file mode 100644
index 0000000000..d83ad3bca2
Binary files /dev/null and b/picture/ShopMap.png differ
diff --git a/picture/Ui.png b/picture/Ui.png
new file mode 100644
index 0000000000..376a714269
Binary files /dev/null and b/picture/Ui.png differ
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000000..05526476fe
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,2 @@
+include 'graph'
+
diff --git a/src/main/java/command/Command.java b/src/main/java/command/Command.java
new file mode 100644
index 0000000000..075038423e
--- /dev/null
+++ b/src/main/java/command/Command.java
@@ -0,0 +1,49 @@
+package command;
+
+import textbox.PlayerStatus;
+import textbox.TextBox;
+import map.BaseMap;
+
+import java.io.FileNotFoundException;
+import java.util.Scanner;
+
+
+public abstract class Command {
+ protected TextBox textBox;
+ protected PlayerStatus playerStatus;
+ protected String commandDescription;
+ protected BaseMap currentMapForCommand;
+
+ public Command() {
+ commandDescription = "Impossible";
+ currentMapForCommand = null;
+ }
+
+ public abstract void execute();
+
+ public void execute(Scanner in) throws FileNotFoundException {
+ }
+
+ public void execute(PlayerStatus playerStatus) {
+ }
+
+ public String getCommandDescription() {
+ return commandDescription;
+ }
+
+ public BaseMap getCurrentMapForCommand() {
+ return currentMapForCommand;
+ }
+
+ public void setCurrentMapForCommand(BaseMap givenMap) {
+ currentMapForCommand = givenMap;
+ }
+
+ public void setPlayerStatus(PlayerStatus playerStatus) {
+ this.playerStatus = playerStatus;
+ }
+
+ public void setTextBox(TextBox textBox) {
+ this.textBox = textBox;
+ }
+}
diff --git a/src/main/java/command/CommandType.java b/src/main/java/command/CommandType.java
new file mode 100644
index 0000000000..ce4256f64d
--- /dev/null
+++ b/src/main/java/command/CommandType.java
@@ -0,0 +1,28 @@
+package command;
+
+public enum CommandType {
+ FIGHT("(?i)\\h*(f|fight)\\h*"),
+ RUN("(?i)\\h*(r|run)\\h*"),
+ MOVE_FORWARD("(?i)\\h*(w)(\\h+\\d{1,5})?\\h*"),
+ MOVE_DOWNWARD("(?i)\\h*(s)(\\h+\\d{1,5})?\\h*"),
+ MOVE_LEFT("(?i)\\h*(a)(\\h+\\d{1,5})?\\h*"),
+ MOVE_RIGHT("(?i)\\h*(d)(\\h+\\d{1,5})?\\h*"),
+ INTERACT("(?i)\\h*(e)\\h*"),
+ QUIT("(?i)\\h*(q|quit)\\h*"),
+ HELP("(?i)\\h*(h|help)\\h*"),
+ EXIT("(?i)\\h*(exit)\\h*"),
+ ERROR(""),
+ INVENTORY("(?i)\\h*(i|inventory)\\h*"),
+ USE_ITEM("(?i)\\h*(use)(\\h+\\d+|\\h+\\w+)?\\h*"),
+ CLOSE_INV("(?i)\\h*(close)\\h*"),
+ RESET("(?i)\\h*(reset)\\h*");
+ final String regExpression;
+
+ CommandType(String regExpression) {
+ this.regExpression = regExpression;
+ }
+
+ public String getRegExpression() {
+ return regExpression;
+ }
+}
diff --git a/src/main/java/command/ErrorCommand.java b/src/main/java/command/ErrorCommand.java
new file mode 100644
index 0000000000..327bc01f5a
--- /dev/null
+++ b/src/main/java/command/ErrorCommand.java
@@ -0,0 +1,9 @@
+package command;
+
+public class ErrorCommand extends Command {
+
+ @Override
+ public void execute() {
+ textBox.setNextError("Invalid Command here");
+ }
+}
diff --git a/src/main/java/command/HelpCommand.java b/src/main/java/command/HelpCommand.java
new file mode 100644
index 0000000000..9a0db26e29
--- /dev/null
+++ b/src/main/java/command/HelpCommand.java
@@ -0,0 +1,14 @@
+package command;
+
+import ui.Ui;
+
+public class HelpCommand extends Command {
+ public HelpCommand(){
+ commandDescription = "HelpMe!!";
+ }
+ @Override
+ public void execute() {
+ Ui ui = new Ui();
+ ui.printHelpMenu();
+ }
+}
diff --git a/src/main/java/command/QuitCommand.java b/src/main/java/command/QuitCommand.java
new file mode 100644
index 0000000000..03671db2e4
--- /dev/null
+++ b/src/main/java/command/QuitCommand.java
@@ -0,0 +1,11 @@
+package command;
+
+public class QuitCommand extends Command{
+ public QuitCommand(){
+ commandDescription = "TIRED";
+ }
+ @Override
+ public void execute() {
+
+ }
+}
diff --git a/src/main/java/command/ResetCommand.java b/src/main/java/command/ResetCommand.java
new file mode 100644
index 0000000000..3a951fd31d
--- /dev/null
+++ b/src/main/java/command/ResetCommand.java
@@ -0,0 +1,101 @@
+package command;
+
+import inventoryitems.Item;
+import map.BaseMap;
+import map.FirstMap;
+import map.MapGenerator;
+import textbox.PlayerStatus;
+
+import java.util.ArrayList;
+
+import static main.CalculaChroniclesOfTheAlgorithmicKingdom.PLAYER_INVENTORY;
+import static map.BaseMap.mapIndex;
+import static map.BaseMap.currentMap;
+import static map.BaseMap.storedMaps;
+import static map.MapGenerator.FIRST_MAP_IDENTITY;
+import static map.MapGenerator.INVENTORY_IDENTITY;
+
+public class ResetCommand extends Command {
+ public ResetCommand() {
+ commandDescription = "RESET!";
+ }
+
+ @Override
+ public void execute() {
+
+ }
+
+ @Override
+ public void execute(PlayerStatus playerStatus) {
+ System.out.print("\n\n\n\t\t\t\t\tResetting the game\n\n\n");
+ for (int i = 0; i < 201; i++) {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ System.out.println("Thread.sleep function failed!\n" + e.getMessage());
+ }
+ System.out.print("Cleaning all maps |" + "#".repeat(i / 6) +
+ " ".repeat(33 - i / 6)
+ + "|" + "%" + i / 2 + "\r");
+ }
+ System.out.println();
+
+ storedMaps.clear();
+ mapIndex.clear();
+ for (int i = 0; i < 201; i++) {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ System.out.println("Thread.sleep function failed!\n" + e.getMessage());
+ }
+ System.out.print("Cleaning player inventory |" + "#".repeat(i / 6) +
+ " ".repeat(33 - i / 6)
+ + "|" + "%" + i / 2 + "\r");
+ }
+ System.out.println();
+
+ ArrayList generalItem = PLAYER_INVENTORY.getGeneralItems();
+ generalItem.clear();
+
+ for (int i = 0; i < 201; i++) {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ System.out.println("Thread.sleep function failed!\n" + e.getMessage());
+ }
+ System.out.print("Resetting player status |" + "#".repeat(i / 6) +
+ " ".repeat(33 - i / 6)
+ + "|" + "%" + i / 2 + "\r");
+ }
+ System.out.println();
+
+ playerStatus.setPlayerHealth(100);
+ playerStatus.setPlayerMoney(0);
+ playerStatus.setPlayerExp(0);
+ playerStatus.setPlayerDamage(5);
+
+ for (int i = 0; i < 201; i++) {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ System.out.println("Thread.sleep function failed!\n" + e.getMessage());
+ }
+ System.out.print("Generating new map |" + "#".repeat(i / 6) +
+ " ".repeat(33 - i / 6)
+ + "|" + "%" + i / 2 + "\r");
+ }
+ System.out.println();
+
+ BaseMap map = new FirstMap();
+ MapGenerator.getInstance().generateMap(map);
+ map.setTextBox(textBox);
+
+ storedMaps.add(PLAYER_INVENTORY);
+ mapIndex.put(INVENTORY_IDENTITY, storedMaps.size() - 1);
+ PLAYER_INVENTORY.setPlayerStatus(playerStatus);
+ PLAYER_INVENTORY.setCurrentTextBox(textBox);
+ storedMaps.add(map);
+ mapIndex.put(FIRST_MAP_IDENTITY, storedMaps.size() - 1);
+ currentMap = mapIndex.get(FIRST_MAP_IDENTITY);
+ }
+}
diff --git a/src/main/java/command/fight/FightingCommand.java b/src/main/java/command/fight/FightingCommand.java
new file mode 100644
index 0000000000..f25862eb4c
--- /dev/null
+++ b/src/main/java/command/fight/FightingCommand.java
@@ -0,0 +1,46 @@
+package command.fight;
+import command.Command;
+import command.ResetCommand;
+import map.BaseMap;
+import map.ShopMap;
+
+import java.io.FileNotFoundException;
+import java.util.Scanner;
+
+import static map.BaseMap.mapIndex;
+import static map.BaseMap.storedMaps;
+import static map.MapGenerator.FIRST_MAP_IDENTITY;
+
+
+public class FightingCommand extends Command {
+ public FightingCommand() {
+ commandDescription = "FIGHT!";
+ }
+
+ @Override
+ public void execute() {
+ }
+
+ @Override
+ public void execute(Scanner in) throws FileNotFoundException {
+ if (currentMapForCommand instanceof map.battleinterface.BattleInterface) {
+ currentMapForCommand.enableFight(in);
+ BaseMap.currentMap = mapIndex.get(FIRST_MAP_IDENTITY);
+ if (currentMapForCommand.getEntityDeath()) {
+ int xPos = storedMaps.get(BaseMap.currentMap).getInteractX();
+ int yPos = storedMaps.get(BaseMap.currentMap).getInteractY();
+ storedMaps.get(BaseMap.currentMap).clearSpot(xPos, yPos);
+ currentMapForCommand.handleLootingByPlayer();
+ } else if (currentMapForCommand.getPlayerDeath()) {
+ currentMapForCommand.handleDeath();
+ Command deathReset = new ResetCommand();
+ deathReset.execute(playerStatus);
+ }
+ }
+
+ if (currentMapForCommand instanceof ShopMap) {
+ currentMapForCommand.enableFight(in);
+ BaseMap.currentMap = mapIndex.get(FIRST_MAP_IDENTITY);
+ }
+ }
+}
diff --git a/src/main/java/command/fight/RunningCommand.java b/src/main/java/command/fight/RunningCommand.java
new file mode 100644
index 0000000000..49442f3f88
--- /dev/null
+++ b/src/main/java/command/fight/RunningCommand.java
@@ -0,0 +1,28 @@
+package command.fight;
+
+import command.Command;
+import map.BaseMap;
+import map.battleinterface.BattleInterface;
+import map.ShopMap;
+
+import static map.BaseMap.storedMaps;
+import static map.MapGenerator.FIRST_MAP_IDENTITY;
+import static map.BaseMap.mapIndex;
+
+public class RunningCommand extends Command {
+ public RunningCommand() {
+ commandDescription = "RUN!";
+ }
+ @Override
+ public void execute(){
+ if(currentMapForCommand instanceof BattleInterface) {
+ textBox.setNextNarration("You decide to run and successfully got away");
+ BaseMap.currentMap = mapIndex.get(FIRST_MAP_IDENTITY);
+ currentMapForCommand = storedMaps.get(BaseMap.currentMap);
+ } else if(currentMapForCommand instanceof ShopMap){
+ textBox.setNextNarration("You exited the shop!!");
+ BaseMap.currentMap = mapIndex.get(FIRST_MAP_IDENTITY);
+ currentMapForCommand = storedMaps.get(BaseMap.currentMap);
+ }
+ }
+}
diff --git a/src/main/java/command/inventory/CloseInventoryCommand.java b/src/main/java/command/inventory/CloseInventoryCommand.java
new file mode 100644
index 0000000000..18a3a68247
--- /dev/null
+++ b/src/main/java/command/inventory/CloseInventoryCommand.java
@@ -0,0 +1,18 @@
+package command.inventory;
+
+import command.Command;
+import map.BaseMap;
+
+import static map.BaseMap.mapIndex;
+import static map.MapGenerator.FIRST_MAP_IDENTITY;
+
+public class CloseInventoryCommand extends Command {
+
+ public CloseInventoryCommand() {
+
+ }
+ @Override
+ public void execute() {
+ BaseMap.currentMap = mapIndex.get(FIRST_MAP_IDENTITY);
+ }
+}
diff --git a/src/main/java/command/inventory/OpenInventoryCommand.java b/src/main/java/command/inventory/OpenInventoryCommand.java
new file mode 100644
index 0000000000..96f2891a51
--- /dev/null
+++ b/src/main/java/command/inventory/OpenInventoryCommand.java
@@ -0,0 +1,20 @@
+package command.inventory;
+
+import command.Command;
+import map.BaseMap;
+
+import static map.BaseMap.mapIndex;
+import static map.MapGenerator.INVENTORY_IDENTITY;
+
+public class OpenInventoryCommand extends Command {
+ public OpenInventoryCommand() {
+ commandDescription = "Inventory";
+ }
+
+ @Override
+ public void execute() {
+ BaseMap.currentMap = mapIndex.get(INVENTORY_IDENTITY);
+ textBox.setNextNarration("Here's your inventory! You can use an item by keying in [use] followed by it's \n" +
+ "index with a space between them. Alternatively, enter [close] to close your inventory.");
+ }
+}
diff --git a/src/main/java/command/inventory/SellCommand.java b/src/main/java/command/inventory/SellCommand.java
new file mode 100644
index 0000000000..3fde6c4e05
--- /dev/null
+++ b/src/main/java/command/inventory/SellCommand.java
@@ -0,0 +1,64 @@
+package command.inventory;
+
+import command.Command;
+import inventoryitems.Item;
+import map.PlayerInventory;
+
+import java.util.ArrayList;
+import java.util.stream.Collectors;
+
+import static java.lang.Integer.parseInt;
+
+public class SellCommand extends Command {
+ String userCommand;
+
+ public SellCommand(String userCommand) {
+ commandDescription = "SELL!";
+ this.userCommand = userCommand;
+ }
+
+ public void findItem(String item, ArrayList itemList) {
+ PlayerInventory inventory = playerStatus.getPlayerInventory();
+ Item itemToSell;
+ try {
+ itemToSell = itemList.stream().filter(x -> x.getName().equalsIgnoreCase(item))
+ .collect(Collectors.toList()).get(0);
+ inventory.sellItem(itemToSell);
+ } catch (Exception e) {
+ textBox.setNextError("Please enter a valid item number or item name");
+ }
+ }
+
+ @Override
+ public void execute() {
+ PlayerInventory inventory = playerStatus.getPlayerInventory();
+ ArrayList list = playerStatus.getPlayerInventory().getGeneralItems();
+ if (list.isEmpty()) {
+ textBox.setNextError("The item does not exist");
+ return;
+ }
+ String itemString = "";
+ int itemIndex;
+ try {
+ itemString = userCommand.split(" ", 2)[1];
+ itemIndex = parseInt(itemString);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ textBox.setNextError("Please enter an item number or item name");
+ return;
+ } catch (NumberFormatException e) {
+ findItem(itemString, list);
+ return;
+ } catch (IndexOutOfBoundsException e) {
+ textBox.setNextError("The item does not exist");
+ return;
+ }
+ Item item;
+ try {
+ item = list.get(itemIndex - 1);
+ } catch (Exception e) {
+ textBox.setNextError("The item does not exist");
+ return;
+ }
+ inventory.sellItem(item);
+ }
+}
diff --git a/src/main/java/command/inventory/UseCommand.java b/src/main/java/command/inventory/UseCommand.java
new file mode 100644
index 0000000000..f9e16def67
--- /dev/null
+++ b/src/main/java/command/inventory/UseCommand.java
@@ -0,0 +1,46 @@
+package command.inventory;
+
+import command.Command;
+import inventoryitems.Consumable;
+import inventoryitems.Item;
+import map.PlayerInventory;
+
+import static java.lang.Integer.parseInt;
+
+public class UseCommand extends Command {
+ String userCommand;
+
+ public UseCommand(String userCommand) {
+ commandDescription = "USE!";
+ this.userCommand = userCommand;
+ }
+
+ @Override
+ public void execute() {
+ if (playerStatus.getPlayerInventory().getGeneralItems().isEmpty()) {
+ textBox.setNextError("The item does not exist");
+ return;
+ }
+ String itemString = "";
+ int itemIndex;
+ try {
+ itemString = userCommand.split(" ", 2)[1];
+ itemIndex = parseInt(itemString);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ textBox.setNextError("Please enter an item index");
+ return;
+ } catch (NumberFormatException e) {
+ textBox.setNextError("Please enter a valid integer for the item index");
+ return;
+ }
+ Item item;
+ PlayerInventory inventory = playerStatus.getPlayerInventory();
+ try {
+ item = inventory.getGeneralItems().get(itemIndex - 1);
+ } catch (Exception e) {
+ textBox.setNextError("The item does not exist");
+ return;
+ }
+ inventory.useItem((Consumable) item);
+ }
+}
diff --git a/src/main/java/command/mapmove/ExitShop.java b/src/main/java/command/mapmove/ExitShop.java
new file mode 100644
index 0000000000..4e5d2f2586
--- /dev/null
+++ b/src/main/java/command/mapmove/ExitShop.java
@@ -0,0 +1,23 @@
+package command.mapmove;
+
+import command.Command;
+import map.BaseMap;
+import map.ShopMap;
+
+import static map.BaseMap.storedMaps;
+import static map.MapGenerator.FIRST_MAP_IDENTITY;
+import static map.BaseMap.mapIndex;
+
+public class ExitShop extends Command {
+ public ExitShop() {
+ commandDescription = "RUN!";
+ }
+ @Override
+ public void execute(){
+ if(currentMapForCommand instanceof ShopMap) {
+ textBox.setNextNarration("You exited the shop!!");
+ BaseMap.currentMap = mapIndex.get(FIRST_MAP_IDENTITY);
+ currentMapForCommand = storedMaps.get(BaseMap.currentMap);
+ }
+ }
+}
diff --git a/src/main/java/command/mapmove/InteractingCommand.java b/src/main/java/command/mapmove/InteractingCommand.java
new file mode 100644
index 0000000000..000e4686e5
--- /dev/null
+++ b/src/main/java/command/mapmove/InteractingCommand.java
@@ -0,0 +1,124 @@
+package command.mapmove;
+
+import interactable.InteractableEntity;
+import interactable.ShopKeeper;
+import interactable.enemies.Centaur;
+import interactable.enemies.Dragon;
+import interactable.enemies.Demon;
+import interactable.enemies.Gryphon;
+import interactable.enemies.Goblin;
+import map.BaseMap;
+import map.ShopMap;
+import map.battleinterface.BattleInterface;
+
+import java.util.Objects;
+
+import static main.CalculaChroniclesOfTheAlgorithmicKingdom.PLAYER_INVENTORY;
+import static map.BaseMap.storedMaps;
+import static map.BaseMap.mapIndex;
+import static map.MapGenerator.CENTAUR;
+import static map.MapGenerator.DEMON;
+import static map.MapGenerator.DRAGON;
+import static map.MapGenerator.GOBLIN;
+import static map.MapGenerator.GRYPHON;
+import static map.MapGenerator.SHOP;
+
+public class InteractingCommand extends MapMoveCommand {
+
+ public InteractingCommand() {
+ commandDescription = "interact";
+ }
+
+ @Override
+ public void execute() {
+ String entityInteractedWith = currentMapForCommand.handleInteract();
+ if (Objects.equals(entityInteractedWith, "no interaction")) {
+ textBox.setNextNarration("Nothing to interact with here");
+ } else if (Objects.equals(entityInteractedWith, "@") ||
+ Objects.equals(entityInteractedWith, "$") ||
+ Objects.equals(entityInteractedWith, "%") ||
+ Objects.equals(entityInteractedWith, "^") ||
+ Objects.equals(entityInteractedWith, "&")) {
+ textBox.setNextNarration(entityInteractedWith + " appears in your path. What will you do?");
+ textBox.setNextInstruction("Will you [fight] or will you [run]?");
+ }
+
+
+ char entity = entityInteractedWith.charAt(0);
+ BaseMap battleMap;
+ InteractableEntity monster;
+ int xPos = currentMapForCommand.getInteractX();
+ int yPos = currentMapForCommand.getInteractY();
+
+ switch (entity) {
+ case CENTAUR:
+ monster = new Centaur(10, 10, 10, xPos, yPos, 10, 10);
+ textBox.setNextDialogue("*the " + monster.getName() + " stares at you menacingly*");
+ battleMap = new BattleInterface(playerStatus, textBox, monster);
+ battleMap.initMap(30, monster.getHeight());
+ storedMaps.add(battleMap);
+ mapIndex.put(CENTAUR, storedMaps.size() - 1);
+ BaseMap.currentMap = mapIndex.get(CENTAUR);
+ break;
+ case DEMON:
+ monster = new Demon(15, 15, 15, xPos, yPos, 15, 15);
+ textBox.setNextDialogue("*the " + monster.getName() + " growls at you menacingly*");
+ battleMap = new BattleInterface(playerStatus, textBox, monster);
+ battleMap.initMap(30, monster.getHeight());
+ storedMaps.add(battleMap);
+ mapIndex.put(DEMON, storedMaps.size() - 1);
+ BaseMap.currentMap = mapIndex.get(DEMON);
+ break;
+ case DRAGON:
+ monster = new Dragon(20, 20, 20, xPos, yPos, 20, 20);
+ textBox.setNextDialogue("*the " + monster.getName() + " breathes a ball of flame menacingly*");
+ battleMap = new BattleInterface(playerStatus, textBox, monster);
+ battleMap.initMap(30, monster.getHeight());
+ storedMaps.add(battleMap);
+ mapIndex.put(DRAGON, storedMaps.size() - 1);
+ BaseMap.currentMap = mapIndex.get(DRAGON);
+ break;
+ case GOBLIN:
+ monster = new Goblin(25, 25, 25, xPos, yPos, 25, 25);
+ textBox.setNextDialogue("*the " + monster.getName() + " laughs maniacally*");
+ battleMap = new BattleInterface(playerStatus, textBox, monster);
+ battleMap.initMap(30, monster.getHeight());
+ storedMaps.add(battleMap);
+ mapIndex.put(GOBLIN, storedMaps.size() - 1);
+ BaseMap.currentMap = mapIndex.get(GOBLIN);
+ break;
+ case GRYPHON:
+ monster = new Gryphon(30, 30, 30, xPos, yPos, 30, 30);
+ textBox.setNextDialogue("*the " + monster.getName() + " screams at you loudly*");
+ battleMap = new BattleInterface(playerStatus, textBox, monster);
+ battleMap.initMap(30, monster.getHeight());
+ storedMaps.add(battleMap);
+ mapIndex.put(GRYPHON, storedMaps.size() - 1);
+ BaseMap.currentMap = mapIndex.get(GRYPHON);
+ break;
+ case SHOP: //some shopkeeper
+ ShopMap shopMap;
+ ShopKeeper shopkeeper = new ShopKeeper("ShopKeeper/ShopKeeper.txt",
+ "*meow* Hi welcome to my shop! *meow*");
+ shopMap = new ShopMap(playerStatus, textBox, shopkeeper, PLAYER_INVENTORY);
+ shopMap.initMap(30, 0); // Set appropriate width and height
+ shopkeeper.addConsumable(20, 0, "The caffeine is so strong, it heals wounds",
+ "Cup of Coffee", 10);
+ shopkeeper.addConsumable(0, 100, "Gun with a single round. Why does a cat have a " +
+ "gun anyway?", "Desert Eagle", 50);
+
+ storedMaps.add(shopMap);
+
+ mapIndex.put(SHOP, storedMaps.size() - 1);
+ BaseMap.currentMap = mapIndex.get(SHOP);
+
+ textBox.setNextNarration("You are greeted by a cat with oddly small eyes.");
+ textBox.setNextInstruction("To enter the shop enter [fight]. To leave now, enter [exit].");
+ break;
+
+ default:
+ battleMap = new BattleInterface(null, null, null);
+ break;
+ }
+ }
+}
diff --git a/src/main/java/command/mapmove/MapMoveCommand.java b/src/main/java/command/mapmove/MapMoveCommand.java
new file mode 100644
index 0000000000..99d80e77f2
--- /dev/null
+++ b/src/main/java/command/mapmove/MapMoveCommand.java
@@ -0,0 +1,24 @@
+package command.mapmove;
+
+import command.Command;
+
+public abstract class MapMoveCommand extends Command {
+ protected int commandModifier;
+
+ public MapMoveCommand() {
+
+ }
+
+ public MapMoveCommand(String userInput) {
+ commandDescription = "MapMove";
+ userInput = userInput.trim();
+ String[] splitUserInput = userInput.split("\\h+");
+ if (splitUserInput.length == 1) {
+ commandModifier = 1;
+ } else {
+ commandModifier = Integer.parseInt(splitUserInput[1]);
+ }
+ }
+
+ public abstract void execute();
+}
diff --git a/src/main/java/command/mapmove/MovingDownwardCommand.java b/src/main/java/command/mapmove/MovingDownwardCommand.java
new file mode 100644
index 0000000000..85359f37c3
--- /dev/null
+++ b/src/main/java/command/mapmove/MovingDownwardCommand.java
@@ -0,0 +1,14 @@
+package command.mapmove;
+
+public class MovingDownwardCommand extends MapMoveCommand {
+ public MovingDownwardCommand(String userInput) {
+ super(userInput);
+ }
+
+ @Override
+ public void execute() {
+ for (int i = 0; i < commandModifier; i++) {
+ currentMapForCommand.movePlayerDownOne();
+ }
+ }
+}
diff --git a/src/main/java/command/mapmove/MovingForwardCommand.java b/src/main/java/command/mapmove/MovingForwardCommand.java
new file mode 100644
index 0000000000..7abd04a6f0
--- /dev/null
+++ b/src/main/java/command/mapmove/MovingForwardCommand.java
@@ -0,0 +1,14 @@
+package command.mapmove;
+
+public class MovingForwardCommand extends MapMoveCommand {
+
+ public MovingForwardCommand(String userInput) {
+ super(userInput);
+ }
+ @Override
+ public void execute() {
+ for (int i = 0; i < commandModifier; i++) {
+ currentMapForCommand.movePlayerUpOne();
+ }
+ }
+}
diff --git a/src/main/java/command/mapmove/MovingLeftCommand.java b/src/main/java/command/mapmove/MovingLeftCommand.java
new file mode 100644
index 0000000000..0ec1d39c26
--- /dev/null
+++ b/src/main/java/command/mapmove/MovingLeftCommand.java
@@ -0,0 +1,15 @@
+package command.mapmove;
+
+public class MovingLeftCommand extends MapMoveCommand {
+
+ public MovingLeftCommand(String userInput) {
+ super(userInput);
+ }
+
+ @Override
+ public void execute() {
+ for (int i = 0; i < commandModifier; i++) {
+ currentMapForCommand.movePlayerLeftOne();
+ }
+ }
+}
diff --git a/src/main/java/command/mapmove/MovingRightCommand.java b/src/main/java/command/mapmove/MovingRightCommand.java
new file mode 100644
index 0000000000..0f4986dc3d
--- /dev/null
+++ b/src/main/java/command/mapmove/MovingRightCommand.java
@@ -0,0 +1,16 @@
+package command.mapmove;
+
+
+public class MovingRightCommand extends MapMoveCommand {
+ public MovingRightCommand(String userInput) {
+ super(userInput);
+ commandDescription = "Right";
+ }
+
+ @Override
+ public void execute() {
+ for (int i = 0; i < commandModifier; i++) {
+ currentMapForCommand.movePlayerRightOne();
+ }
+ }
+}
diff --git a/src/main/java/filereader/FileReader.java b/src/main/java/filereader/FileReader.java
new file mode 100644
index 0000000000..b8f436cb98
--- /dev/null
+++ b/src/main/java/filereader/FileReader.java
@@ -0,0 +1,37 @@
+package filereader;
+
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+
+public class FileReader {
+ private final String filePath;
+
+
+ public FileReader(String filePath) {
+ this.filePath = filePath;
+ }
+
+ public ArrayList> readDesign() throws IOException {
+ ArrayList> map = new ArrayList<>();
+ InputStream inputStream = getClass().getClassLoader().getResourceAsStream(filePath);
+ if (inputStream == null) {
+ throw new IllegalArgumentException("file not found at: " + filePath);
+ }
+ BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ ArrayList row = new ArrayList<>();
+ for (int i = 0; i < line.length(); i += 1) {
+ row.add(line.charAt(i));
+ }
+ map.add(row);
+ }
+ reader.close();
+ inputStream.close();
+ return map;
+ }
+}
diff --git a/src/main/java/filereader/InventoryItemsStorage.java b/src/main/java/filereader/InventoryItemsStorage.java
new file mode 100644
index 0000000000..8e0b9395f9
--- /dev/null
+++ b/src/main/java/filereader/InventoryItemsStorage.java
@@ -0,0 +1,70 @@
+package filereader;
+
+import inventoryitems.Consumable;
+import inventoryitems.Item;
+import map.PlayerInventory;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+import static filereader.filepath.InventoryItemsPath.INVENTORY_ITEMS_PATH;
+import static main.CalculaChroniclesOfTheAlgorithmicKingdom.PLAYER_INVENTORY;
+
+public class InventoryItemsStorage {
+
+ public void readFile() throws IOException {
+ try {
+ Files.createDirectories(Paths.get("./data"));
+ } catch (IOException e) {
+ System.out.println("Fail to create data directory!\n" + e.getMessage());
+ }
+
+ File inventoryItems = new File(INVENTORY_ITEMS_PATH);
+
+ if (!inventoryItems.exists() || inventoryItems.length() == 0) {
+ try {
+ Files.createFile(Paths.get(INVENTORY_ITEMS_PATH));
+ } catch (IOException e) {
+ System.out.println("Fail to create inventory text!\n" + e.getMessage());
+ }
+ return;
+ }
+
+ Scanner fileContent = new Scanner(inventoryItems);
+ try {
+ while (fileContent.hasNext()) {
+ String originalData = fileContent.nextLine();
+ String[] data = originalData.split("\\|");
+ Consumable item = new Consumable(Integer.parseInt(data[0]), Integer.parseInt(data[1]), data[2],
+ data[3], Integer.parseInt(data[4]));
+ item.setQuantity(Integer.parseInt(data[5]));
+ PLAYER_INVENTORY.loadInventory(item);
+ }
+ } catch (ArrayIndexOutOfBoundsException | NumberFormatException | StringIndexOutOfBoundsException e){
+ System.out.println("Inventory data corrupted, cleaning your items : (");
+ new FileWriter(INVENTORY_ITEMS_PATH).close();
+ }
+ fileContent.close();
+ }
+
+ public void saveFile(PlayerInventory playerInventory) throws IOException {
+ ArrayList generalItems = playerInventory.getGeneralItems();
+ new FileWriter(INVENTORY_ITEMS_PATH).close();
+ FileWriter fileWriter = new FileWriter(INVENTORY_ITEMS_PATH);
+ for (Item item : generalItems) {
+ String currentItem = "";
+ currentItem += item.getHealAmt() + "|";
+ currentItem += item.getDamageAmpAmt() + "|";
+ currentItem += item.getDescription() + "|";
+ currentItem += item.getName() + "|";
+ currentItem += item.getSellPrice() + "|";
+ currentItem += item.getQuantity();
+ fileWriter.write(currentItem + System.lineSeparator());
+ }
+ fileWriter.close();
+ }
+}
diff --git a/src/main/java/filereader/MapStorage.java b/src/main/java/filereader/MapStorage.java
new file mode 100644
index 0000000000..542cf67dee
--- /dev/null
+++ b/src/main/java/filereader/MapStorage.java
@@ -0,0 +1,135 @@
+package filereader;
+
+import map.BaseMap;
+import map.FirstMap;
+import map.MapGenerator;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+import static filereader.filepath.MapFilePath.BASE_MAP_PATH;
+import static filereader.filepath.MapFilePath.MAP_PROPERTY_PATH;
+
+public class MapStorage {
+
+ public BaseMap readFile() throws FileNotFoundException, InterruptedException {
+ try {
+ Files.createDirectories(Paths.get("./data"));
+ } catch (IOException e) {
+ System.out.println("Fail to create data directory!\n" + e.getMessage());
+ }
+
+ File mapPicture = new File(BASE_MAP_PATH);
+ File mapProperty = new File(MAP_PROPERTY_PATH);
+
+ if (!mapPicture.exists() || !mapProperty.exists() || mapPicture.length() == 0 ||
+ mapProperty.length() == 0) {
+ try {
+ Files.createFile(Paths.get(BASE_MAP_PATH));
+ } catch (IOException e) {
+ System.out.println("Fail to create map text!\n" + e.getMessage());
+ }
+ try {
+ Files.createFile(Paths.get(MAP_PROPERTY_PATH));
+ } catch (IOException e) {
+ System.out.println("Fail to create map property text!\n" + e.getMessage());
+ }
+ System.out.print("\n\n\nNo local archives found or the map data is corrupted\n\n\n");
+ for (int i = 0; i < 201; i++) {
+ Thread.sleep(20);
+ System.out.print("Generating maps |" + "#".repeat(i / 6) + " ".repeat(33 - i / 6)
+ + "|" + "%" + i / 2 + "\r");
+ }
+ System.out.println();
+ BaseMap map = new FirstMap();
+ MapGenerator.getInstance().generateMap(map);
+ return map;
+ }
+ System.out.print("\n\n\nFind local archive\n\n\n");
+ for (int i = 0; i < 201; i++) {
+ Thread.sleep(20);
+ System.out.print("Loading maps |" + "#".repeat(i / 6) + " ".repeat(33 - i / 6)
+ + "|" + "%" + i / 2 + "\r");
+ }
+ System.out.println();
+ return getBaseMap(mapPicture, mapProperty);
+ }
+
+ private BaseMap getBaseMap(File mapPicture, File mapProperty) throws FileNotFoundException {
+ Scanner fileContent1 = new Scanner(mapPicture);
+
+ BaseMap map = new FirstMap();
+ ArrayList> mapData = new ArrayList<>();
+ while (fileContent1.hasNext()) {
+ ArrayList chars = new ArrayList<>();
+ String content = fileContent1.nextLine();
+ for (char ch : content.toCharArray()) {
+ chars.add(ch);
+ }
+ mapData.add(chars);
+ }
+ map.setMapData(mapData);
+ fileContent1.close();
+ Scanner fileContent2 = new Scanner(mapProperty);
+ int round = 0;
+ while (fileContent2.hasNext()) {
+ int currentData = Integer.parseInt(fileContent2.nextLine());
+ switch (round) {
+ case 0:
+ map.setWidth(currentData);
+ break;
+ case 1:
+ map.setHeight(currentData);
+ break;
+ case 2:
+ map.setPlayerX(currentData);
+ break;
+ case 3:
+ map.setPlayerY(currentData);
+ break;
+ default:
+ }
+ round++;
+ }
+ fileContent2.close();
+ return map;
+ }
+
+ public void saveMap(BaseMap map) throws IOException {
+ new FileWriter(MAP_PROPERTY_PATH).close();
+ FileWriter fileWriter1 = getFileWriter(map);
+
+ fileWriter1.close();
+ FileWriter fileWriter2 = new FileWriter(BASE_MAP_PATH);
+ ArrayList> mapData = map.getMapData();
+ for (ArrayList ch : mapData) {
+ StringBuilder temp = new StringBuilder();
+ for (Character c : ch) {
+ temp.append(c);
+ }
+ fileWriter2.write(temp + System.lineSeparator());
+ }
+ fileWriter2.close();
+ }
+
+ private FileWriter getFileWriter(BaseMap map) throws IOException {
+ FileWriter fileWriter1 = new FileWriter(MAP_PROPERTY_PATH);
+
+ String width = String.valueOf(map.getWidth());
+ String height = String.valueOf(map.getHeight());
+ String playerX = String.valueOf(map.getPlayerX());
+ String playerY = String.valueOf(map.getPlayerY());
+
+ fileWriter1.write(width + System.lineSeparator());
+ fileWriter1.write(height + System.lineSeparator());
+ fileWriter1.write(playerX + System.lineSeparator());
+ fileWriter1.write(playerY + System.lineSeparator());
+ return fileWriter1;
+ }
+}
diff --git a/src/main/java/filereader/PlayerStatusStorage.java b/src/main/java/filereader/PlayerStatusStorage.java
new file mode 100644
index 0000000000..d7495c9640
--- /dev/null
+++ b/src/main/java/filereader/PlayerStatusStorage.java
@@ -0,0 +1,88 @@
+package filereader;
+
+import textbox.PlayerStatus;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Scanner;
+
+import static filereader.filepath.PlayerStatusPath.PLAYER_STATUS_PATH;
+import static main.CalculaChroniclesOfTheAlgorithmicKingdom.START_HEALTH;
+import static main.CalculaChroniclesOfTheAlgorithmicKingdom.START_MONEY;
+import static main.CalculaChroniclesOfTheAlgorithmicKingdom.START_EXP;
+import static main.CalculaChroniclesOfTheAlgorithmicKingdom.START_DAMAGE;
+import static main.CalculaChroniclesOfTheAlgorithmicKingdom.PLAYER_INVENTORY;
+
+public class PlayerStatusStorage {
+ public PlayerStatus readPlayerStatus() throws FileNotFoundException {
+ try {
+ Files.createDirectories(Paths.get("./data"));
+ } catch (IOException e) {
+ System.out.println("Fail to create directory!\n" + e.getMessage());
+ }
+
+ File file = new File(PLAYER_STATUS_PATH);
+ if (!file.exists() || file.length() == 0) {
+ try {
+ Files.createFile(Paths.get(PLAYER_STATUS_PATH));
+ } catch (IOException e) {
+ System.out.println("Fail to create playerStatus File!\n" + e.getMessage());
+ }
+ return new PlayerStatus(START_HEALTH, START_MONEY, START_EXP, START_DAMAGE,
+ PLAYER_INVENTORY);
+ }
+
+ Scanner fileContent = new Scanner(file);
+ int round = 0;
+ int startHealth = -1;
+ int startMoney = -1;
+ int startExp = -1;
+ int startDamage = -1;
+ try {
+ while (fileContent.hasNext()) {
+ int playerStatusData = Integer.parseInt(fileContent.nextLine());
+ switch (round) {
+ case 0:
+ startHealth = playerStatusData;
+ break;
+ case 1:
+ startMoney = playerStatusData;
+ break;
+ case 2:
+ startExp = playerStatusData;
+ break;
+ case 3:
+ startDamage = playerStatusData;
+ break;
+ default:
+ }
+ round++;
+ }
+ } catch (ArrayIndexOutOfBoundsException | NumberFormatException | StringIndexOutOfBoundsException e) {
+ System.out.println("Player status corrupted, resetting it to default : (");
+ return new PlayerStatus(START_HEALTH, START_MONEY, START_EXP, START_DAMAGE,
+ PLAYER_INVENTORY);
+ }
+ return new PlayerStatus(startHealth, startMoney, startExp, startDamage, PLAYER_INVENTORY);
+ }
+
+ public void savePlayerStatus(PlayerStatus playerStatus) throws IOException {
+ new FileWriter(PLAYER_STATUS_PATH).close();
+ FileWriter fileWriter = new FileWriter(PLAYER_STATUS_PATH);
+
+ String startHealth = String.valueOf(playerStatus.getPlayerHealth());
+ String startMoney = String.valueOf(playerStatus.getPlayerMoney());
+ String startExp = String.valueOf(playerStatus.getPlayerExp());
+ String startDamage = String.valueOf(playerStatus.getPlayerDamage());
+
+ fileWriter.write(startHealth + System.lineSeparator());
+ fileWriter.write(startMoney + System.lineSeparator());
+ fileWriter.write(startExp + System.lineSeparator());
+ fileWriter.write(startDamage + System.lineSeparator());
+ fileWriter.close();
+ }
+}
diff --git a/src/main/java/filereader/filepath/EnemiesDesignFilePath.java b/src/main/java/filereader/filepath/EnemiesDesignFilePath.java
new file mode 100644
index 0000000000..d324e385fd
--- /dev/null
+++ b/src/main/java/filereader/filepath/EnemiesDesignFilePath.java
@@ -0,0 +1,14 @@
+package filereader.filepath;
+
+public class EnemiesDesignFilePath {
+
+ public static final String GOBLIN_PATH = "enemiesDesign/goblin.txt";
+ public static final String CENTAUR_PATH = "enemiesDesign/centaur.txt";
+ public static final String DEMON_PATH = "enemiesDesign/demon.txt";
+ public static final String GRYPHON_PATH = "enemiesDesign/gryphon.txt";
+ public static final String DRAGON_PATH = "enemiesDesign/dragon.txt";
+
+ public EnemiesDesignFilePath() {
+ }
+
+}
diff --git a/src/main/java/filereader/filepath/InventoryItemsPath.java b/src/main/java/filereader/filepath/InventoryItemsPath.java
new file mode 100644
index 0000000000..a198338e1d
--- /dev/null
+++ b/src/main/java/filereader/filepath/InventoryItemsPath.java
@@ -0,0 +1,5 @@
+package filereader.filepath;
+
+public class InventoryItemsPath {
+ public static final String INVENTORY_ITEMS_PATH = "./data/inventory.txt";
+}
diff --git a/src/main/java/filereader/filepath/MapFilePath.java b/src/main/java/filereader/filepath/MapFilePath.java
new file mode 100644
index 0000000000..cc0a81e619
--- /dev/null
+++ b/src/main/java/filereader/filepath/MapFilePath.java
@@ -0,0 +1,6 @@
+package filereader.filepath;
+
+public class MapFilePath {
+ public static final String BASE_MAP_PATH = "./data/mapPicture.txt";
+ public static final String MAP_PROPERTY_PATH = "./data/mapData.txt";
+}
diff --git a/src/main/java/filereader/filepath/PlayerStatusPath.java b/src/main/java/filereader/filepath/PlayerStatusPath.java
new file mode 100644
index 0000000000..0544331b17
--- /dev/null
+++ b/src/main/java/filereader/filepath/PlayerStatusPath.java
@@ -0,0 +1,5 @@
+package filereader.filepath;
+
+public class PlayerStatusPath {
+ public static final String PLAYER_STATUS_PATH = "./data/playerStatus.txt";
+}
diff --git a/src/main/java/hint/HintHandler.java b/src/main/java/hint/HintHandler.java
new file mode 100644
index 0000000000..fa8d6f670d
--- /dev/null
+++ b/src/main/java/hint/HintHandler.java
@@ -0,0 +1,53 @@
+package hint;
+
+import map.BaseMap;
+import textbox.TextBox;
+
+import java.util.ArrayList;
+
+public class HintHandler {
+ BaseMap currentMap;
+ TextBox currentTextBox;
+ ArrayList invisibleTriggers;
+
+
+ public HintHandler(BaseMap map, TextBox text){
+ currentMap = map;
+ currentTextBox = text;
+ invisibleTriggers = new ArrayList();
+
+ addTrigger(0, 1, 3, 2, "You should visit the shop sometime. The owner sells many" +
+ " useful items for your journey"); //add all triggers in the map here
+ }
+
+
+ /**
+ * Creates an invisible trigger with a defined area using 2 coordinates such that when a player walks over the
+ * defined area, a message is injected into the Text Box.
+ *
+ * @param xStart starting x coordinate
+ * @param yStart starting y coordinate
+ * @param xEnd ending x coordinate
+ * @param yEnd ending y coordinate
+ * @param message message to be printed
+ */
+ public void addTrigger(int xStart, int yStart, int xEnd, int yEnd, String message){
+ Trigger newTrigger = new Trigger(xStart, yStart, xEnd, yEnd, message);
+ invisibleTriggers.add(newTrigger);
+ }
+
+ private boolean isWithinArea(Trigger trigger){
+ return currentMap.getPlayerX() >= trigger.getXInitial() && currentMap.getPlayerX() <= trigger.getXEnding() &&
+ currentMap.getPlayerY() >= trigger.getYInitial() && currentMap.getPlayerX() <= trigger.getYEnding();
+ }
+
+
+ public void checkMapThenDisplayHint(){ //takes first hint in list within an area and pushes it to the text box
+ for (Trigger trigger : invisibleTriggers) {
+ if (isWithinArea(trigger)){
+ currentTextBox.setNextInstruction(trigger.getMessage());
+ return;
+ }
+ }
+ }
+}
diff --git a/src/main/java/hint/Trigger.java b/src/main/java/hint/Trigger.java
new file mode 100644
index 0000000000..fb49916809
--- /dev/null
+++ b/src/main/java/hint/Trigger.java
@@ -0,0 +1,37 @@
+package hint;
+
+public class Trigger {
+ protected String message;
+ protected int xInitial;
+ protected int yInitial;
+ protected int xEnding;
+ protected int yEnding;
+
+ public Trigger(int xStart, int yStart, int xEnd, int yEnd, String newMessage){
+ message = newMessage;
+ xInitial = xStart;
+ yInitial = yStart;
+ xEnding = xEnd;
+ yEnding = yEnd;
+ }
+
+ public int getXInitial() {
+ return xInitial;
+ }
+
+ public int getYInitial() {
+ return yInitial;
+ }
+
+ public int getXEnding() {
+ return xEnding;
+ }
+
+ public int getYEnding() {
+ return yEnding;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+}
diff --git a/src/main/java/interactable/Enemy.java b/src/main/java/interactable/Enemy.java
new file mode 100644
index 0000000000..e8aa406a99
--- /dev/null
+++ b/src/main/java/interactable/Enemy.java
@@ -0,0 +1,51 @@
+package interactable;
+
+public abstract class Enemy extends InteractableEntity{
+ protected int damage;
+ protected int defence;
+ protected int health;
+ protected String filePath;
+
+
+
+ public Enemy(int dmg, int def, int hp, int xCoordinate, int yCoordinate, int exp, int money){
+ this.damage = dmg;
+ this.defence = def;
+ this.health = hp;
+ this.x = xCoordinate;
+ this.y = yCoordinate;
+ this.expDropped = exp;
+ this.moneyDropped = money;
+ }
+
+ public int getHealth(){
+ return health;
+ }
+ public void setDamage(int dmg){
+ damage = dmg;
+ }
+
+ public void harmHealth(int dmg){
+ health -= dmg;
+ }
+
+ public int getDefence(){
+ return defence;
+ }
+
+ public int getDamage() {
+ return damage;
+ }
+
+ public int getXCoordinate(){
+ return this.x;
+ }
+
+ public int getYCoordinate(){
+ return this.y;
+ }
+
+ public String getFilePath() {
+ return filePath;
+ }
+}
diff --git a/src/main/java/interactable/InteractableEntity.java b/src/main/java/interactable/InteractableEntity.java
new file mode 100644
index 0000000000..7db56cdc9c
--- /dev/null
+++ b/src/main/java/interactable/InteractableEntity.java
@@ -0,0 +1,32 @@
+package interactable;
+
+public abstract class InteractableEntity {
+ protected int x;
+ protected int y;
+ protected int expDropped;
+ protected int moneyDropped;
+ protected String name;
+
+ public abstract int getHealth();
+
+ public abstract int getDefence();
+
+ public abstract int getDamage();
+
+ public abstract String getName();
+
+ public abstract String getFilePath();
+
+ public int getExp_dropped(){
+ return expDropped;
+ }
+
+ public int getMoney_dropped(){
+ return moneyDropped;
+ }
+ public int getHeight() {
+ return 0;
+ }
+
+ public void setHeight() {}
+}
diff --git a/src/main/java/interactable/ShopKeeper.java b/src/main/java/interactable/ShopKeeper.java
new file mode 100644
index 0000000000..7906a16739
--- /dev/null
+++ b/src/main/java/interactable/ShopKeeper.java
@@ -0,0 +1,80 @@
+package interactable;
+
+import inventoryitems.Consumable;
+import inventoryitems.ShopItem;
+
+import java.util.ArrayList;
+
+public class ShopKeeper extends InteractableEntity{
+ protected ArrayList shopItems;
+ protected String defaultMessage; //whatever the guy says to introduce his items
+ protected String filePath;
+
+
+ public ShopKeeper(String filePathway, String message){
+ //addConsumable();
+ this.filePath = filePathway;
+ this.defaultMessage = message;
+ this.shopItems = new ArrayList<>();
+ }
+
+ public ArrayList getShopItems() {
+ return shopItems;
+ }
+
+ public void addConsumable(int heal, int damage, String itemDescription, String itemName, int price){
+ Consumable newConsumable = new Consumable(heal, damage, itemDescription, itemName, price);
+ shopItems.add(newConsumable);
+ }
+
+ public String getDefaultMessage() {
+ return defaultMessage;
+ }
+
+
+ public String formatShop() {
+ if (shopItems != null) {
+ StringBuilder formattedList = new StringBuilder();
+ for (int i = 0; i < shopItems.size(); i += 1) {
+ ShopItem item = shopItems.get(i);
+ formattedList.append(i + 1).append(". ")
+ .append(item.getName())
+ .append(" - ")
+ .append(item.getDescription())
+ .append(" - ")
+ .append(" $")
+ .append(item.getSellPrice())
+ .append("\n");
+ }
+ return formattedList.toString();
+ }
+ return "The shop is empty";
+ }
+
+
+ @Override
+ public int getHealth() {
+ return 0;
+ }
+
+ @Override
+ public int getDefence() {
+ return 0;
+ }
+
+ @Override
+ public int getDamage() {
+ return 0;
+ }
+
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public String getFilePath() {
+ return filePath;
+ }
+
+}
diff --git a/src/main/java/interactable/enemies/Centaur.java b/src/main/java/interactable/enemies/Centaur.java
new file mode 100644
index 0000000000..df92db2b88
--- /dev/null
+++ b/src/main/java/interactable/enemies/Centaur.java
@@ -0,0 +1,22 @@
+package interactable.enemies;
+
+import interactable.Enemy;
+import static filereader.filepath.EnemiesDesignFilePath.CENTAUR_PATH;
+
+public class Centaur extends Enemy {
+
+ public Centaur(int dmg, int def, int hp, int xCoordinate, int yCoordinate, int exp, int money) {
+ super(dmg, def, hp, xCoordinate, yCoordinate, exp, money);
+ this.name = "Centaur";
+ this.filePath = CENTAUR_PATH;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/main/java/interactable/enemies/Demon.java b/src/main/java/interactable/enemies/Demon.java
new file mode 100644
index 0000000000..cd53917405
--- /dev/null
+++ b/src/main/java/interactable/enemies/Demon.java
@@ -0,0 +1,22 @@
+package interactable.enemies;
+
+import interactable.Enemy;
+import static filereader.filepath.EnemiesDesignFilePath.DEMON_PATH;
+
+public class Demon extends Enemy {
+
+ public Demon(int dmg, int def, int hp, int xCoordinate, int yCoordinate, int exp, int money) {
+ super(dmg, def, hp, xCoordinate, yCoordinate, exp, money);
+ this.name = "Demon";
+ this.filePath = DEMON_PATH;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/main/java/interactable/enemies/Dragon.java b/src/main/java/interactable/enemies/Dragon.java
new file mode 100644
index 0000000000..42acc0b34d
--- /dev/null
+++ b/src/main/java/interactable/enemies/Dragon.java
@@ -0,0 +1,22 @@
+package interactable.enemies;
+
+import interactable.Enemy;
+import static filereader.filepath.EnemiesDesignFilePath.DRAGON_PATH;
+
+public class Dragon extends Enemy {
+
+ public Dragon(int dmg, int def, int hp, int xCoordinate, int yCoordinate, int exp, int money) {
+ super(dmg, def, hp, xCoordinate, yCoordinate, exp, money);
+ this.name = "Dragon";
+ this.filePath = DRAGON_PATH;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/main/java/interactable/enemies/Goblin.java b/src/main/java/interactable/enemies/Goblin.java
new file mode 100644
index 0000000000..14f3712d54
--- /dev/null
+++ b/src/main/java/interactable/enemies/Goblin.java
@@ -0,0 +1,22 @@
+package interactable.enemies;
+
+import interactable.Enemy;
+import static filereader.filepath.EnemiesDesignFilePath.GOBLIN_PATH;
+
+public class Goblin extends Enemy {
+
+ public Goblin(int dmg, int def, int hp, int xCoordinate, int yCoordinate, int exp, int money) {
+ super(dmg, def, hp, xCoordinate, yCoordinate, exp, money);
+ this.name = "Goblin";
+ this.filePath = GOBLIN_PATH;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/main/java/interactable/enemies/Gryphon.java b/src/main/java/interactable/enemies/Gryphon.java
new file mode 100644
index 0000000000..713dbc3740
--- /dev/null
+++ b/src/main/java/interactable/enemies/Gryphon.java
@@ -0,0 +1,22 @@
+package interactable.enemies;
+
+import interactable.Enemy;
+import static filereader.filepath.EnemiesDesignFilePath.GRYPHON_PATH;
+
+public class Gryphon extends Enemy {
+
+ public Gryphon(int dmg, int def, int hp, int xCoordinate, int yCoordinate, int exp, int money) {
+ super(dmg, def, hp, xCoordinate, yCoordinate, exp, money);
+ this.name = "Gryphon";
+ this.filePath = GRYPHON_PATH;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/main/java/inventoryitems/Consumable.java b/src/main/java/inventoryitems/Consumable.java
new file mode 100644
index 0000000000..03ce489a32
--- /dev/null
+++ b/src/main/java/inventoryitems/Consumable.java
@@ -0,0 +1,40 @@
+package inventoryitems;
+
+import textbox.PlayerStatus;
+
+import java.util.ArrayList;
+
+public class Consumable extends ShopItem { //we assume all consumables are for 1 turn only
+ protected int healAmt;
+ protected int damageAmpAmt;
+
+ public Consumable(int heal, int damage, String itemDescription, String itemName, int cost) {
+ super.description = itemDescription;
+ healAmt = heal;
+ damageAmpAmt = damage;
+ super.name = itemName;
+ super.price = cost;
+ super.sellPrice = cost;
+ }
+
+
+ //use() assumes damage items heal for 0 and healing items do 0 damage
+ public void use(PlayerStatus currentPlayer, Consumable item, ArrayList generalItems) {
+ for (Item item1 : generalItems){
+ if (item1.equals(item)){
+ currentPlayer.setPlayerDamageAmp(item.getDamageAmpAmt());
+ int currentHealth = currentPlayer.getPlayerHealth();
+ currentPlayer.setPlayerHealth(currentHealth + item.getHealAmt());
+ break;
+ }
+ }
+ }
+
+ public int getDamageAmpAmt() {
+ return damageAmpAmt;
+ }
+
+ public int getHealAmt() {
+ return healAmt;
+ }
+}
diff --git a/src/main/java/inventoryitems/Gear.java b/src/main/java/inventoryitems/Gear.java
new file mode 100644
index 0000000000..486f64d499
--- /dev/null
+++ b/src/main/java/inventoryitems/Gear.java
@@ -0,0 +1,17 @@
+package inventoryitems;
+
+public abstract class Gear extends Item{
+ protected boolean isEquipped;
+
+ public Gear(boolean isEquipped) {
+ this.isEquipped = isEquipped;
+ }
+
+ public boolean isEquipped() {
+ return isEquipped;
+ }
+
+ public void setEquipped(boolean equipped) {
+ isEquipped = equipped;
+ }
+}
diff --git a/src/main/java/inventoryitems/Item.java b/src/main/java/inventoryitems/Item.java
new file mode 100644
index 0000000000..c2094fb16f
--- /dev/null
+++ b/src/main/java/inventoryitems/Item.java
@@ -0,0 +1,44 @@
+package inventoryitems;
+
+public abstract class Item {
+ protected String name;
+ protected String description;
+ protected int quantity;
+ protected int sellPrice;
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public int getQuantity() {
+ return quantity;
+ }
+
+ public void setQuantity(int quantity) {
+ this.quantity = quantity;
+ }
+
+ public void addQuantity(int additional) {
+ this.quantity += additional;
+ }
+
+ public int getSellPrice() {
+ return sellPrice;
+ }
+
+ public int getDamageAmpAmt() {
+ return -1;
+ }
+
+ public int getHealAmt() {
+ return -1;
+ }
+
+ public void setSellPrice(int sellPrice) {
+ this.sellPrice = sellPrice;
+ }
+}
diff --git a/src/main/java/inventoryitems/ShopItem.java b/src/main/java/inventoryitems/ShopItem.java
new file mode 100644
index 0000000000..853be69066
--- /dev/null
+++ b/src/main/java/inventoryitems/ShopItem.java
@@ -0,0 +1,13 @@
+package inventoryitems;
+
+public abstract class ShopItem extends Item{
+ protected int price;
+
+ public ShopItem() {
+
+ }
+
+ public int getPrice() {
+ return price;
+ }
+}
diff --git a/src/main/java/inventoryitems/wearableitems/Armor.java b/src/main/java/inventoryitems/wearableitems/Armor.java
new file mode 100644
index 0000000000..2c74ad8fb9
--- /dev/null
+++ b/src/main/java/inventoryitems/wearableitems/Armor.java
@@ -0,0 +1,22 @@
+package inventoryitems.wearableitems;
+
+import inventoryitems.Gear;
+
+public class Armor extends Gear {
+ protected int additionalHealth;
+
+ public Armor(String name, String description, boolean isEquipped, int additionalHealth) {
+ super(isEquipped);
+ this.name = name;
+ this.description = description;
+ this.additionalHealth = additionalHealth;
+ }
+
+ public int getAdditionalHealth() {
+ return additionalHealth;
+ }
+
+ public void setAdditionalHealth(int additionalHealth) {
+ this.additionalHealth = additionalHealth;
+ }
+}
diff --git a/src/main/java/inventoryitems/wearableitems/Helmet.java b/src/main/java/inventoryitems/wearableitems/Helmet.java
new file mode 100644
index 0000000000..c08b293910
--- /dev/null
+++ b/src/main/java/inventoryitems/wearableitems/Helmet.java
@@ -0,0 +1,21 @@
+package inventoryitems.wearableitems;
+
+import inventoryitems.Gear;
+
+public class Helmet extends Gear {
+ protected int additionalHealth;
+ public Helmet(String name, String description, boolean isEquipped, int additionalHealth) {
+ super(isEquipped);
+ this.name = name;
+ this.description = description;
+ this.additionalHealth = additionalHealth;
+ }
+
+ public int getAdditionalHealth() {
+ return additionalHealth;
+ }
+
+ public void setAdditionalHealth(int additionalHealth) {
+ this.additionalHealth = additionalHealth;
+ }
+}
diff --git a/src/main/java/inventoryitems/wearableitems/Weapon.java b/src/main/java/inventoryitems/wearableitems/Weapon.java
new file mode 100644
index 0000000000..c6979292b8
--- /dev/null
+++ b/src/main/java/inventoryitems/wearableitems/Weapon.java
@@ -0,0 +1,22 @@
+package inventoryitems.wearableitems;
+
+import inventoryitems.Gear;
+
+public class Weapon extends Gear {
+ protected int additionalDamage;
+
+ public Weapon(String name, String description, boolean isEquipped, int additionalDamage) {
+ super(isEquipped);
+ this.name = name;
+ this.description = description;
+ this.additionalDamage = additionalDamage;
+ }
+
+ public int getAdditionalDamage() {
+ return additionalDamage;
+ }
+
+ public void setAdditionalDamage(int additionalDamage) {
+ this.additionalDamage = additionalDamage;
+ }
+}
diff --git a/src/main/java/main/CalculaChroniclesOfTheAlgorithmicKingdom.java b/src/main/java/main/CalculaChroniclesOfTheAlgorithmicKingdom.java
new file mode 100644
index 0000000000..63938e79d9
--- /dev/null
+++ b/src/main/java/main/CalculaChroniclesOfTheAlgorithmicKingdom.java
@@ -0,0 +1,167 @@
+package main;
+
+
+import filereader.InventoryItemsStorage;
+import filereader.MapStorage;
+import filereader.PlayerStatusStorage;
+import hint.HintHandler;
+import command.Command;
+import map.BaseMap;
+import map.ShopMap;
+import map.PlayerInventory;
+import map.battleinterface.BattleInterface;
+import parser.Parser;
+import textbox.PlayerStatus;
+import textbox.TextBox;
+import ui.Ui;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Scanner;
+
+import static map.BaseMap.mapIndex;
+import static map.BaseMap.storedMaps;
+import static map.BaseMap.currentMap;
+import static map.MapGenerator.FIRST_MAP_IDENTITY;
+import static map.MapGenerator.INVENTORY_IDENTITY;
+
+
+public class CalculaChroniclesOfTheAlgorithmicKingdom {
+
+ public static final int START_HEALTH = 100;
+ public static final int START_MONEY = 0;
+ public static final int START_EXP = 0;
+ public static final int START_DAMAGE = 5;
+ public static final PlayerInventory PLAYER_INVENTORY = new PlayerInventory();
+
+ public static void main(String[] args) throws InterruptedException, FileNotFoundException {
+ new CalculaChroniclesOfTheAlgorithmicKingdom().startGame();
+ }
+
+ public void startGame() throws InterruptedException, FileNotFoundException {
+ Scanner in = new Scanner(System.in);
+
+ InventoryItemsStorage inventoryItemsStorage = new InventoryItemsStorage();
+ MapStorage mapStorage = new MapStorage();
+ PlayerStatusStorage playerStatusStorage = new PlayerStatusStorage();
+
+ PlayerStatus playerStatus = null;
+ try {
+ playerStatus = playerStatusStorage.readPlayerStatus();
+ } catch (IOException e) {
+ System.out.println("Can not read playerStatus !!\n" + e.getMessage());
+ }
+
+ try {
+ inventoryItemsStorage.readFile();
+ } catch (IOException e) {
+ System.out.println("Can not read inventory file!\n" + e.getMessage());
+ }
+ storedMaps.add(PLAYER_INVENTORY);
+ mapIndex.put(INVENTORY_IDENTITY, storedMaps.size() - 1);
+ TextBox textBox = new TextBox();
+ Parser parser = new Parser();
+ Ui ui = new Ui();
+
+
+ textBox.initTextBox();
+
+
+ PLAYER_INVENTORY.setPlayerStatus(playerStatus);
+ PLAYER_INVENTORY.setCurrentTextBox(textBox);
+
+ BaseMap map = null;
+ try {
+ map = mapStorage.readFile();
+ } catch (FileNotFoundException e) {
+ System.out.println("\tCan not find your file!!!\n" + e.getMessage());
+ } catch (InterruptedException e) {
+ System.out.println("Timer error !!\n" + e.getMessage());
+ }
+ assert map != null;
+ map.setTextBox(textBox); // so that first map can use the text box
+ HintHandler hints = new HintHandler(map, textBox);
+ storedMaps.add(map);
+ mapIndex.put(FIRST_MAP_IDENTITY, storedMaps.size() - 1);
+ currentMap = mapIndex.get(FIRST_MAP_IDENTITY);
+
+
+ assert playerStatus != null;
+ ui.printPlayerStatus(playerStatus);
+ ui.printMap(storedMaps.get(currentMap));
+ ui.printTextBox(textBox);
+
+ Command userCommand;
+ do {
+
+ String userCommandText = in.nextLine();
+ hints.checkMapThenDisplayHint(); //handles invisible map triggers for hints
+ userCommand = parser.parseCommand(userCommandText);
+ setUserCommand(userCommand, storedMaps.get(currentMap), playerStatus, textBox);
+
+ executeCommand(userCommand, in, playerStatus);
+
+ printMessageUnderMap(userCommand, ui, playerStatus, textBox);
+ saveAllGameFile(mapStorage, playerStatusStorage, playerStatus, userCommand, inventoryItemsStorage);
+ if (storedMaps.get(mapIndex.get(FIRST_MAP_IDENTITY)).isWon()) {
+ ui.printWinMessage(playerStatus);
+ break;
+ }
+ } while (!userCommand.getCommandDescription().equals("TIRED"));
+ }
+
+ private static void saveAllGameFile(MapStorage mapStorage, PlayerStatusStorage playerStatusStorage,
+ PlayerStatus playerStatus, Command userCommand,
+ InventoryItemsStorage inventoryItemsStorage) {
+ try {
+ mapStorage.saveMap(storedMaps.get(mapIndex.get(FIRST_MAP_IDENTITY)));
+ } catch (IOException e) {
+ System.out.println("Can not save the map!\n" + e.getMessage());
+ }
+ try {
+ playerStatusStorage.savePlayerStatus(playerStatus);
+ } catch (IOException e) {
+ System.out.println("Can not save Player Status" + e.getMessage());
+ }
+ try {
+ inventoryItemsStorage.saveFile(PLAYER_INVENTORY);
+ } catch (IOException e) {
+ System.out.println("Can not save inventory items!\n" + e.getMessage());
+ }
+ }
+
+ private static void printMessageUnderMap(Command userCommand, Ui ui, PlayerStatus playerStatus, TextBox textBox) {
+ if (!userCommand.getCommandDescription().equals("HelpMe!!") &&
+ !userCommand.getCommandDescription().equals("TIRED")) {
+ ui.printPlayerStatus(playerStatus);
+ if (storedMaps.get(currentMap) instanceof BattleInterface ||
+ storedMaps.get(currentMap) instanceof ShopMap) {
+ ui.printEnemy(storedMaps.get(currentMap));
+ } else if (storedMaps.get(currentMap) instanceof PlayerInventory) {
+ ui.printInventory(playerStatus.getPlayerInventory().getGeneralItems(),
+ playerStatus.getPlayerInventory().getInventoryNames().get(0),
+ storedMaps.get(currentMap).getWidth(), storedMaps.get(currentMap).getHeight());
+ } else {
+ ui.printMap(storedMaps.get(currentMap));
+ }
+ ui.printTextBox(textBox);
+ }
+ }
+
+ private static void executeCommand(Command userCommand, Scanner in, PlayerStatus playerStatus)
+ throws FileNotFoundException {
+ if (userCommand.getCommandDescription().equals("FIGHT!")) {
+ userCommand.execute(in);
+ } else if (userCommand.getCommandDescription().equals("RESET!")) {
+ userCommand.execute(playerStatus);
+ } else {
+ userCommand.execute();
+ }
+ }
+
+ private static void setUserCommand(Command userCommand, BaseMap map, PlayerStatus playerStatus, TextBox textBox) {
+ userCommand.setCurrentMapForCommand(map);
+ userCommand.setPlayerStatus(playerStatus);
+ userCommand.setTextBox(textBox);
+ }
+}
diff --git a/src/main/java/map/BaseMap.java b/src/main/java/map/BaseMap.java
new file mode 100644
index 0000000000..cf88974d55
--- /dev/null
+++ b/src/main/java/map/BaseMap.java
@@ -0,0 +1,246 @@
+package map;
+
+import textbox.TextBox;
+import ui.Ui;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Scanner;
+
+public abstract class BaseMap {
+
+ public static int currentMap;
+ public static ArrayList storedMaps = new ArrayList<>();
+ public static HashMap mapIndex = new HashMap<>();
+ protected int width;
+ protected int height;
+ protected ArrayList> mapData;
+ protected int playerX;
+ protected int playerY;
+ protected String mapName;
+ protected TextBox textBox;
+
+ public BaseMap() {
+ }
+
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ public void setPlayerX(int playerX) {
+ this.playerX = playerX;
+ }
+
+ public void setPlayerY(int playerY) {
+ this.playerY = playerY;
+ }
+
+ public abstract void enableFight();
+
+ public void enableFight(Scanner in) throws FileNotFoundException {
+ assert in != null;
+ }
+
+ public void initMap(int givenWidth, int givenHeight) {
+ assert givenHeight != 0;
+ assert givenWidth != 0;
+ }
+
+ public void setTextBox(TextBox box){
+ textBox = box;
+ }
+
+ public ArrayList> getMapData() {
+ return mapData;
+ }
+ public void setMapData(ArrayList> mapData) {
+ this.mapData = mapData;
+ }
+
+ public void initPlayerLocation(int x, int y) {
+
+ if (x >= 0 && x < width && y >= 0 && y < height) {
+ mapData.get(y).set(x, 'P');
+ this.playerX = x;
+ this.playerY = y;
+ }
+
+ }
+
+ public void initShopLocation(int x, int y) {
+ if (x >= 0 && x < width && y >= 0 && y < height) {
+ mapData.get(y).set(x, '#');
+ }
+ }
+
+ public void movePlayerUpOne() {
+ Ui ui = new Ui();
+ if (this.playerY - 1 >= 0) {
+ if (mapData.get(playerY - 1).get(playerX) != '.') {
+ ui.insertObjectObstructionMessage(textBox);
+ } else {
+ mapData.get(playerY).set(playerX, '.');
+ mapData.get(playerY - 1).set(playerX, 'P');
+ this.playerY -= 1;
+ }
+ } else {
+ ui.insertOutOfBoundsMessage(textBox);
+ }
+ }
+
+ public void movePlayerDownOne() {
+ Ui ui = new Ui();
+ if (this.playerY + 1 < height) {
+ if (mapData.get(playerY + 1).get(playerX) != '.') {
+ ui.insertObjectObstructionMessage(textBox);
+ } else {
+ mapData.get(playerY).set(playerX, '.');
+ mapData.get(playerY + 1).set(playerX, 'P');
+ this.playerY += 1;
+ }
+ } else {
+ ui.insertOutOfBoundsMessage(textBox);
+ }
+ }
+
+ public void movePlayerLeftOne() {
+ Ui ui = new Ui();
+ if (this.playerX - 1 >= 0) {
+ if (mapData.get(playerY).get(playerX - 1) != '.') {
+ ui.insertObjectObstructionMessage(textBox);
+ } else {
+ mapData.get(playerY).set(playerX, '.');
+ mapData.get(playerY).set(playerX - 1, 'P');
+ this.playerX -= 1;
+ }
+ } else {
+ ui.insertOutOfBoundsMessage(textBox);
+ }
+ }
+
+ public void movePlayerRightOne() {
+ Ui ui = new Ui();
+ if (this.playerX + 1 < width) {
+ if (mapData.get(playerY).get(playerX + 1) != '.') {
+ ui.insertObjectObstructionMessage(textBox);
+ } else {
+ mapData.get(playerY).set(playerX, '.');
+ mapData.get(playerY).set(playerX + 1, 'P');
+ this.playerX += 1;
+ }
+ } else {
+ ui.insertOutOfBoundsMessage(textBox);
+ }
+ }
+
+
+ public ArrayList> getMap() {
+ return mapData;
+ }
+
+ public String handleInteract() {
+ if (playerY > 0 && mapData.get(playerY - 1).get(playerX) != '.') {
+ return String.valueOf(mapData.get(playerY - 1).get(playerX));
+ }
+
+ if (playerX < mapData.get(0).size() - 1 && mapData.get(playerY).get(playerX + 1) != '.') {
+ return String.valueOf(mapData.get(playerY).get(playerX + 1));
+ }
+
+ if (playerY < mapData.size() - 1 && mapData.get(playerY + 1).get(playerX) != '.') {
+ return String.valueOf(mapData.get(playerY + 1).get(playerX));
+ }
+
+ if (playerX > 0 && mapData.get(playerY).get(playerX - 1) != '.') {
+ return String.valueOf(mapData.get(playerY).get(playerX - 1));
+ }
+ return "no interaction";
+ }
+
+ public int getInteractX() {
+ if (playerY > 0 && mapData.get(playerY - 1).get(playerX) != '.') {
+ return playerX;
+ }
+ if (playerX < mapData.get(0).size() - 1 && mapData.get(playerY).get(playerX + 1) != '.') {
+ return playerX + 1;
+ }
+ if (playerY < mapData.size() - 1 && mapData.get(playerY + 1).get(playerX) != '.') {
+ return playerX;
+ }
+ if (playerX > 0 && mapData.get(playerY).get(playerX - 1) != '.') {
+ return playerX - 1;
+ }
+ return -1;
+ }
+
+ public int getInteractY() {
+ if (playerY > 0 && mapData.get(playerY - 1).get(playerX) != '.') {
+ return playerY - 1;
+ }
+ if (playerX < mapData.get(0).size() - 1 && mapData.get(playerY).get(playerX + 1) != '.') {
+ return playerY;
+ }
+ if (playerY < mapData.size() - 1 && mapData.get(playerY + 1).get(playerX) != '.') {
+ return playerY + 1;
+ }
+ if (playerX > 0 && mapData.get(playerY).get(playerX - 1) != '.') {
+ return playerY;
+ }
+ return -1;
+ }
+
+ public void clearSpot(int x, int y) {
+ if (x >= 0 && x < width && y >= 0 && y < height) {
+ mapData.get(y).set(x, '.');
+ }
+ }
+
+ public abstract boolean getEntityDeath();
+
+ public abstract boolean getPlayerDeath();
+
+ public abstract void handleDeath();
+
+ public abstract void handleLootingByPlayer();
+
+ public void placeMonsterInTheMap(int x, int y, char monsterType) {
+ mapData.get(y).set(x, monsterType);
+ }
+
+ public Character getCurrentMapInfo(int x, int y) {
+ return mapData.get(y).get(x);
+ }
+
+ public int getPlayerX() {
+ return playerX;
+ }
+
+ public int getPlayerY() {
+ return playerY;
+ }
+ public void printMap(){
+ for(int i = 0; i < height; i++){
+ for (int j = 0; j < width; j++){
+ System.out.print(mapData.get(i).get(j) + " ");
+ }
+ System.out.println();
+ }
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public boolean isWon() {
+ return false;
+ }
+}
diff --git a/src/main/java/map/FirstMap.java b/src/main/java/map/FirstMap.java
new file mode 100644
index 0000000000..ea45450478
--- /dev/null
+++ b/src/main/java/map/FirstMap.java
@@ -0,0 +1,52 @@
+package map;
+
+import java.util.ArrayList;
+
+public class FirstMap extends BaseMap {
+ protected String difficultyModifier = "easy"; //can use to determine question difficulty
+
+ @Override
+ public void enableFight() {
+ System.out.println("lol");
+ }
+ public boolean getEntityDeath(){
+ return false;
+ }
+ @Override
+ public boolean getPlayerDeath(){
+ return false;
+ }
+ @Override
+ public void handleDeath() {
+ }
+ @Override
+ public void handleLootingByPlayer(){
+
+ }
+ public void initMap(int givenWidth, int givenHeight) { //creates a box of "." of a given width and height and width
+ this.width = givenWidth;
+ this.height = givenHeight;
+ this.mapData = new ArrayList<>(height);
+
+ for (int i = 0; i < height; i += 1) {
+ ArrayList row = new ArrayList<>(width);
+ for (int j = 0; j < width; j += 1) {
+ row.add('.');
+ }
+ mapData.add(row);
+ }
+ }
+
+
+ public boolean isWon() {
+ for (ArrayList row : mapData) {
+ for (char element : row) {
+ if (element != '.' && element != 'P' && element != '#') {
+
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/map/MapGenerator.java b/src/main/java/map/MapGenerator.java
new file mode 100644
index 0000000000..0641a0152d
--- /dev/null
+++ b/src/main/java/map/MapGenerator.java
@@ -0,0 +1,67 @@
+package map;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+public class MapGenerator {
+ public static final char FIRST_MAP_IDENTITY = '!';
+ public static final char SHOP = '#';
+ public static final char CENTAUR = '@';
+ public static final char DEMON = '$';
+ public static final char DRAGON= '%';
+ public static final char GOBLIN = '^';
+ public static final char GRYPHON = '&';
+ public static final char INVENTORY_IDENTITY = 'i';
+
+ private static final int MIN = 0;
+ private static final int MAX = 999;
+ private static MapGenerator mapGen = null;
+
+ private MapGenerator() {
+
+ }
+
+ public static MapGenerator getInstance() {
+ if (mapGen == null) {
+ mapGen = new MapGenerator();
+ }
+ return mapGen;
+ }
+
+ public void generateMap(BaseMap map) {
+ int mapWidth = 30;
+ int mapHeight = 10;
+ int initPlayerX = 0;
+ int initPlayerY = 0;
+ int shopX = ThreadLocalRandom.current().nextInt(0, mapWidth);
+ int shopY = ThreadLocalRandom.current().nextInt(0, mapHeight);
+
+ map.initMap(mapWidth, mapHeight);
+ map.initPlayerLocation(initPlayerX, initPlayerY);
+ map.initShopLocation(shopX, shopY);
+
+ int generateFactor;
+ for (int i = 0; i < mapWidth; i++) {
+ for (int j = 0; j < mapHeight; j++) {
+ generateFactor = ThreadLocalRandom.current().nextInt(MIN, MAX + 1);
+ if(map.getCurrentMapInfo(i, j) == '.'){
+ if(generateFactor == 0){
+ map.placeMonsterInTheMap(i, j, GRYPHON);
+ } else if (generateFactor >= 0 && generateFactor <= 4){
+ map.placeMonsterInTheMap(i, j, GOBLIN);
+ } else if (generateFactor >= 0 && generateFactor <= 9){
+ map.placeMonsterInTheMap(i, j, DRAGON);
+ } else if (generateFactor >= 0 && generateFactor <= 29){
+ map.placeMonsterInTheMap(i, j, DEMON);
+ } else if (generateFactor >= 0 && generateFactor <= 49){
+ map.placeMonsterInTheMap(i, j, CENTAUR);
+ }
+ }
+ }
+ }
+
+ }
+
+ public void setMap(BaseMap mapToGenerate) {
+ getInstance().generateMap(mapToGenerate);
+ }
+}
diff --git a/src/main/java/map/PlayerInventory.java b/src/main/java/map/PlayerInventory.java
new file mode 100644
index 0000000000..0aabd88a93
--- /dev/null
+++ b/src/main/java/map/PlayerInventory.java
@@ -0,0 +1,126 @@
+package map;
+
+import inventoryitems.Consumable;
+import inventoryitems.Item;
+import textbox.PlayerStatus;
+import textbox.TextBox;
+import ui.Ui;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class PlayerInventory extends BaseMap {
+ protected ArrayList inventoryNames;
+ protected ArrayList generalItems;
+ protected Ui ui;
+ protected TextBox currentTextBox;
+ protected PlayerStatus playerStatus;
+
+ public PlayerInventory() {
+ this.generalItems = new ArrayList<>();
+ this.inventoryNames = new ArrayList<>();
+ inventoryNames.add("General");
+ this.ui = new Ui();
+ width = 59;
+ height = 8;
+ }
+
+ public void loadInventory(Consumable item){
+ generalItems.add(item);
+ }
+
+ public void addItems(Consumable item) {
+ if (generalItems.isEmpty()) {
+ item.setQuantity(1);
+ generalItems.add(item);
+ return;
+ }
+ List filteredList = generalItems.stream().filter(x -> x.getName().equalsIgnoreCase(
+ item.getName())).collect(Collectors.toList());
+ if (filteredList.isEmpty()) {
+ item.setQuantity(1);
+ generalItems.add(item);
+ return;
+ }
+ filteredList.get(0).addQuantity(1);
+ }
+
+ public void useItem(Consumable item) {
+ item.use(playerStatus, item, generalItems);
+ int leftover = item.getQuantity() - 1;
+ if (leftover <= 0) {
+ generalItems.remove(item);
+ } else {
+ item.setQuantity(item.getQuantity() - 1);
+ }
+ currentTextBox.setNextDialogue(item.getName() + " has been used.");
+ }
+
+ public void sellItem(Item item) {
+ try {
+ if (item.getSellPrice() == 0) {
+ currentTextBox.setNextError("This item cannot be sold");
+ return;
+ }
+ } catch (Exception e) {
+ currentTextBox.setNextError("This item cannot be sold");
+ }
+ int leftover = item.getQuantity() - 1;
+ if (leftover <= 0) {
+ generalItems.remove(item);
+ } else {
+ item.setQuantity(item.getQuantity() - 1);
+ }
+ playerStatus.addMoney(item.getSellPrice());
+ currentTextBox.setNextDialogue("Congrats, you just sold a " + item.getName() + " for $" + item.getSellPrice());
+ }
+
+ public ArrayList getGeneralItems() {
+ return generalItems;
+ }
+
+ public void setGeneralItems(ArrayList items) {
+ this.generalItems = items;
+ }
+
+ public ArrayList getInventoryNames() {
+ return inventoryNames;
+ }
+
+ public void setInventoryNames(ArrayList inventoryNames) {
+ this.inventoryNames = inventoryNames;
+ }
+
+ public void setPlayerStatus(PlayerStatus playerStatus) {
+ this.playerStatus = playerStatus;
+ }
+
+ public void setCurrentTextBox(TextBox currentTextBox) {
+ this.currentTextBox = currentTextBox;
+ }
+ @Override
+ public void enableFight() {
+
+ }
+
+ @Override
+ public boolean getEntityDeath() {
+ return false;
+ }
+
+ @Override
+ public boolean getPlayerDeath() {
+ return false;
+ }
+
+ @Override
+ public void handleDeath() {
+
+ }
+
+ @Override
+ public void handleLootingByPlayer() {
+
+ }
+}
diff --git a/src/main/java/map/ShopMap.java b/src/main/java/map/ShopMap.java
new file mode 100644
index 0000000000..15a99d02ad
--- /dev/null
+++ b/src/main/java/map/ShopMap.java
@@ -0,0 +1,133 @@
+package map;
+
+import interactable.ShopKeeper;
+import filereader.FileReader;
+import inventoryitems.Consumable;
+import inventoryitems.ShopItem;
+import textbox.PlayerStatus;
+import textbox.TextBox;
+import ui.Ui;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+
+public class ShopMap extends BaseMap{
+ protected PlayerStatus currentPlayer;
+ protected TextBox currentTextBox;
+ protected ShopKeeper currentEntity;
+ protected PlayerInventory inventory;
+
+ public ShopMap(PlayerStatus player, TextBox text, ShopKeeper shopKeeper, PlayerInventory bag){
+ this.currentPlayer = player;
+ this.currentTextBox = text;
+ this.currentEntity = shopKeeper;
+ this.inventory = bag;
+ //this.currentMap = new ArrayList<>(height);
+ //loadShopMap();
+ }
+ @Override
+ public void initMap(int givenWidth, int givenHeight) {
+ this.width = givenWidth;
+ this.height = givenHeight;
+
+ this.mapData = new ArrayList<>(height);
+
+ FileReader fileReader = new FileReader(currentEntity.getFilePath());
+ try {
+ mapData = fileReader.readDesign();
+ } catch (Exception e) {
+ // display exception, see how sihan wants to do.
+ }
+ }
+
+
+ public void queueTextBox(){
+ currentTextBox.setNextNarration("You are greeted by a cat with oddly small eyes.\n");
+ currentTextBox.setNextDialogue(currentEntity.getDefaultMessage() + "\n" + currentEntity.formatShop());
+ currentTextBox.setNextInstruction("Give the shop keeper an [INDEX] to view the item and purchase" +
+ " or enter [exit]" +
+ " to leave the shop.");
+ }
+
+
+
+ public void enableFight(){
+
+ }
+
+
+ @Override
+ public void enableFight(Scanner in) throws FileNotFoundException {
+ String answerCommand = "";
+ Ui ui = new Ui();
+ queueTextBox();
+ while (true) {
+
+ ui.printPlayerStatus(currentPlayer);
+ ui.printShopKeeper(currentEntity);
+ ui.printTextBox(currentTextBox);
+
+ answerCommand = in.nextLine().trim();
+ answerCommand = (answerCommand.length() > 10) ? answerCommand.substring(0, 10) : answerCommand;
+
+ // Check if the command is "exit" to break the loop
+ if (answerCommand.equalsIgnoreCase("exit")) {
+ break; // Exit the loop if the command is "exit"
+ }
+
+ // Check if the input is numeric and not 'run'
+ if (answerCommand.matches("\\d+")) {
+ int index = Integer.parseInt(answerCommand) - 1;
+ ArrayList shopItems = currentEntity.getShopItems();
+
+ if (index >= 0 && index < shopItems.size()) {
+ ShopItem item = shopItems.get(index);
+ if (currentPlayer.getPlayerMoney() >= item.getPrice()) {
+ int currentMoney = currentPlayer.getPlayerMoney();
+ currentPlayer.setPlayerMoney(currentMoney - item.getPrice());
+ currentTextBox.setNextNarration("NEW ITEM ADDED TO INVENTORY");
+ inventory.addItems((Consumable) item);
+ } else {
+ currentTextBox.setNextNarration("The cat silently judged your broke ass.\n");
+ }
+ } else {
+ currentTextBox.setNextError("Invalid index. Please enter a valid item index or 'exit'.");
+ }
+ } else if (answerCommand.equalsIgnoreCase("run")) {
+ // Handle "run" as an invalid input, maybe logging or just ignoring
+ currentTextBox.setNextError("Invalid command. The word 'run' is not recognized in this context.");
+ } else {
+ currentTextBox.setNextError("Invalid command. Please enter a valid item index or 'exit'.");
+ }
+
+ currentTextBox.setNextDialogue(currentEntity.getDefaultMessage() + "\n" + currentEntity.formatShop());
+ currentTextBox.setNextInstruction("Give the shopkeeper an [INDEX] to view the item and purchase or " +
+ "enter [exit]" +
+ " to leave the shop.");
+ }
+ currentTextBox.clearAll();
+ currentTextBox.setNextNarration("You exited the shop!!");
+ }
+
+
+
+ @Override
+ public boolean getEntityDeath() {
+ return false;
+ }
+
+ @Override
+ public boolean getPlayerDeath() {
+ return false;
+ }
+
+ @Override
+ public void handleDeath() {
+ }
+
+ @Override
+ public void handleLootingByPlayer() {
+ }
+}
diff --git a/src/main/java/map/battleinterface/BattleInterface.java b/src/main/java/map/battleinterface/BattleInterface.java
new file mode 100644
index 0000000000..b460f25f54
--- /dev/null
+++ b/src/main/java/map/battleinterface/BattleInterface.java
@@ -0,0 +1,142 @@
+package map.battleinterface;
+
+import interactable.Enemy;
+import interactable.InteractableEntity;
+import filereader.FileReader;
+import map.BaseMap;
+import textbox.PlayerStatus;
+import textbox.TextBox;
+import ui.Ui;
+import math.MathQuestion;
+import math.MathPool;
+
+import java.util.ArrayList;
+import java.util.Scanner;
+import java.util.regex.Pattern;
+
+public class BattleInterface extends BaseMap {
+ protected PlayerStatus currentPlayer;
+ protected TextBox currentTextBox;
+ protected InteractableEntity currentEntity;
+
+
+ public BattleInterface(PlayerStatus player, TextBox text, InteractableEntity entity) {
+ this.currentPlayer = player;
+ this.currentTextBox = text;
+ this.currentEntity = entity;
+ }
+
+ @Override
+ public void enableFight() {
+
+ }
+
+ @Override
+ public void enableFight(Scanner in) {
+ MathPool mathPool = new MathPool();
+ mathPool.init();
+ Ui ui = new Ui();
+ int difficulty = 0;
+ while (currentPlayer.getPlayerHealth() > 0 && currentEntity.getHealth() > 0) {
+ int answer;
+ Pattern pattern = Pattern.compile("^[--]?[0-9]+$"); // Pattern to check if the input is numeric
+ ui.printPlayerStatus(currentPlayer);
+ ui.printMap(mapData, (Enemy) currentEntity);
+ MathQuestion mathQuestion = mathPool.getQuestionByDifficulty(difficulty);
+ currentTextBox.setNextNarration(mathQuestion.getQuestion());
+ ui.printTextBox(currentTextBox);
+ String answerCommand = in.nextLine().trim();
+ if (answerCommand.length() > 5) { // Check if input length exceeds 5 characters
+ answerCommand = answerCommand.substring(0, 5); // Take only the first 5 characters
+ }
+ while (!pattern.matcher(answerCommand).matches()) { // Validate the trimmed input
+ currentTextBox.setNextError("Answer must be an integer.");
+ currentTextBox.setNextInstruction(mathQuestion.getQuestion());
+ ui.printTextBox(currentTextBox);
+ answerCommand = in.nextLine().trim();
+ if (answerCommand.length() > 5) {
+ answerCommand = answerCommand.substring(0, 5); // Again trim input if needed
+ }
+ }
+ answer = Integer.parseInt(answerCommand); // Parse the possibly truncated input
+ if (mathQuestion.checkAns(answer)) {
+ currentTextBox.setNextDialogue("You got the question CORRECT. You then proceed to swing as " +
+ "hard as you can");
+ playerHitEnemy();
+ difficulty += 1;
+ } else {
+ currentTextBox.setNextDialogue("You got the question WRONG. The enemy proceeds to attack you.");
+ enemyHitPlayer();
+ }
+ }
+ }
+
+
+ public void initMap(int givenWidth, int givenHeight) {
+ this.width = givenWidth;
+ this.height = givenHeight;
+ this.mapData = new ArrayList<>(height);
+
+ FileReader fileReader = new FileReader(currentEntity.getFilePath());
+ try {
+ mapData = fileReader.readDesign();
+ } catch (Exception e) {
+ currentTextBox.setNextError("Unable to read file from local");
+ }
+ }
+
+
+ public void playerHitEnemy() {
+ if (currentEntity instanceof Enemy) {
+ int dmgDone = currentPlayer.getPlayerDamage() + currentPlayer.getPlayerDamageAmp();
+ ((Enemy) currentEntity).harmHealth(dmgDone);
+ if (currentPlayer.getPlayerDamageAmp() != 0){
+ currentPlayer.setPlayerDamageAmp(0);
+ }
+ }
+ }
+
+ public void enemyHitPlayer() {
+ if (currentEntity instanceof Enemy) {
+ int dmgDone = ((Enemy) currentEntity).getDamage();
+ currentPlayer.harmHealth(dmgDone);
+ }
+ }
+
+
+ public InteractableEntity getCurrentEntity() {
+ return currentEntity;
+ }
+
+ @Override
+ public boolean getEntityDeath() {
+ return currentEntity.getHealth() <= 0;
+ }
+
+ @Override
+ public boolean getPlayerDeath() {
+ return currentPlayer.getPlayerHealth() <= 0;
+ }
+
+ @Override
+ public void handleDeath(){
+ Ui ui = new Ui();
+ ui.printDeathMessage();
+ }
+
+ public PlayerStatus getCurrentPlayer() {
+ return currentPlayer;
+ }
+
+ public void handleLootingByPlayer(){
+ int exp = this.currentEntity.getExp_dropped();
+ int money = this.currentEntity.getMoney_dropped();
+ this.currentPlayer.addExp(exp);
+ this.currentPlayer.addMoney(money);
+ this.currentTextBox.setNextNarration("The beast was slain. You looted its cold dead corpse and found $" + money
+ + " and gained " + exp + " exp.");
+ }
+
+
+
+}
diff --git a/src/main/java/math/MathPool.java b/src/main/java/math/MathPool.java
new file mode 100644
index 0000000000..035b5fc53e
--- /dev/null
+++ b/src/main/java/math/MathPool.java
@@ -0,0 +1,105 @@
+package math;
+
+import java.util.Random;
+import java.util.ArrayList;
+import java.util.Collections;
+
+
+public class MathPool {
+ private ArrayList poolOfQuestions;
+ private final Random random;
+
+
+ public MathPool() {
+ poolOfQuestions = new ArrayList();
+ random = new Random();
+ }
+
+ public void addMathQuestion(String wordProblem, int solution, int difficulty) {
+ MathQuestion problem = new MathQuestion(wordProblem, solution, difficulty);
+ poolOfQuestions.add(problem);
+ }
+
+ /*public MathQuestion getQuestionByDifficulty(int targetDifficulty) {
+ ArrayList filteredQuestions = new ArrayList<>();
+ for (MathQuestion question : poolOfQuestions) {
+ if (question.getDifficulty() == targetDifficulty) {
+ filteredQuestions.add(question);
+ }
+ }
+ if (!filteredQuestions.isEmpty()) {
+ int index = random.nextInt(filteredQuestions.size());
+ return filteredQuestions.get(index);
+ } else {
+ return null;
+ }
+ }*/
+
+ public MathQuestion getQuestionByDifficulty(int targetDifficulty) {
+ ArrayList filteredQuestions = new ArrayList<>();
+ for (MathQuestion question : poolOfQuestions) {
+ if (question.getDifficulty() == targetDifficulty) {
+ filteredQuestions.add(question);
+ }
+ }
+ if (!filteredQuestions.isEmpty()) {
+ // Shuffle the list of questions
+ Collections.shuffle(filteredQuestions);
+ // Iterate through shuffled questions
+ for (MathQuestion question : filteredQuestions) {
+ // Return the first question found (after shuffling)
+ return question;
+ }
+ }
+ return null; // Return null if no questions of the specified difficulty are found
+ }
+
+
+ public void init() {
+
+
+ // Difficulty 2
+ addMathQuestion("6 * 4 = ", 24, 0);
+ addMathQuestion("12 / 3 = ", 4, 0);
+ addMathQuestion("9 * 5 = ", 45, 0);
+ addMathQuestion("20 / 4 = ", 5, 0);
+ addMathQuestion("8 * 7 = ", 56, 0);
+
+ // Difficulty 3
+ addMathQuestion("5^2 = ", 25, 1);
+ addMathQuestion("square root of 144 = ", 12, 1);
+ addMathQuestion("3^3 = ", 27, 1);
+ addMathQuestion("square root of 81 = ", 9, 1);
+ addMathQuestion("7^2 = ", 49, 1);
+
+ // Difficulty 4
+ addMathQuestion("What is the sum of all angles in a triangle?", 180, 2);
+ addMathQuestion("How many sides does a hexagon have?", 6, 2);
+ addMathQuestion("What is the area of a square with side length 5?", 25, 2);
+ addMathQuestion("What is the perimeter of a rectangle with sides 4 and 6?", 20, 2);
+ // Difficulty 3
+ addMathQuestion("What is 2 times the square root of 64?", 16, 3);
+ addMathQuestion("How many degrees are in a right angle?", 90, 3);
+ addMathQuestion("If a square has an area of 25 square units, what is the length of one side?", 5, 3);
+ addMathQuestion("What is the sum of the first 10 positive integers?", 55, 3);
+ addMathQuestion("How many edges does a cube have?", 12, 3);
+
+ // Difficulty 4
+ addMathQuestion("What is the value of 5 factorial (5!)?", 120, 4);
+ addMathQuestion("What is the next prime number after 31?", 37, 4);
+ addMathQuestion("How many vertices does a tetrahedron have?", 4, 4);
+ addMathQuestion("How many diagonals does a hexagon have?", 9, 4);
+ addMathQuestion("How many millimeters are in a meter?", 1000, 4);
+
+ // Difficulty 5
+ addMathQuestion("What is the value of 7 choose 3 (7C3)?", 35, 5);
+ addMathQuestion("How many faces does a dodecahedron have?", 12, 5);
+ addMathQuestion("How many sides does a regular polygon have if each exterior angle measures 30 " +
+ "degrees?", 12, 5);
+ addMathQuestion("What is the 20th Fibonacci number?", 6765, 5);
+ addMathQuestion("What is the value of 2^10?", 1024, 5);
+
+
+ }
+
+}
diff --git a/src/main/java/math/MathQuestion.java b/src/main/java/math/MathQuestion.java
new file mode 100644
index 0000000000..6a0edde19e
--- /dev/null
+++ b/src/main/java/math/MathQuestion.java
@@ -0,0 +1,25 @@
+package math;
+
+public class MathQuestion {
+ private final String question;
+ private final int answer;
+ private final int difficulty;
+
+ public MathQuestion(String qn, int ans, int diff){
+ this.question = qn;
+ this.answer = ans;
+ this.difficulty = diff;
+ }
+
+ public String getQuestion(){
+ return question;
+ }
+
+ public int getDifficulty() {
+ return difficulty;
+ }
+
+ public boolean checkAns(int userAns){
+ return answer == userAns;
+ }
+}
diff --git a/src/main/java/parser/Parser.java b/src/main/java/parser/Parser.java
new file mode 100644
index 0000000000..ad7241d374
--- /dev/null
+++ b/src/main/java/parser/Parser.java
@@ -0,0 +1,115 @@
+package parser;
+
+import command.Command;
+import command.HelpCommand;
+import command.CommandType;
+import command.ResetCommand;
+import command.ErrorCommand;
+import command.QuitCommand;
+import command.fight.FightingCommand;
+import command.fight.RunningCommand;
+import command.inventory.OpenInventoryCommand;
+import command.inventory.CloseInventoryCommand;
+import command.inventory.UseCommand;
+import command.mapmove.InteractingCommand;
+import command.mapmove.MovingDownwardCommand;
+import command.mapmove.MovingForwardCommand;
+import command.mapmove.MovingLeftCommand;
+import command.mapmove.MovingRightCommand;
+import command.mapmove.ExitShop;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+import static map.BaseMap.currentMap;
+import static map.BaseMap.mapIndex;
+import static map.MapGenerator.FIRST_MAP_IDENTITY;
+import static map.MapGenerator.SHOP;
+import static map.MapGenerator.INVENTORY_IDENTITY;
+
+public class Parser {
+
+ private static final int FIRST_MAP = 0;
+
+ public CommandType analyseCommand(String userCommand) {
+ Pattern pattern;
+ Matcher matcher;
+ for (CommandType commandType : CommandType.values()) {
+ pattern = Pattern.compile(commandType.getRegExpression());
+ matcher = pattern.matcher(userCommand);
+ if (matcher.matches()) {
+ return commandType;
+ }
+ }
+ return CommandType.ERROR;
+ }
+
+ public Command parseCommand(String userCommand) {
+ Command command;
+ CommandType commandType = analyseCommand(userCommand);
+
+ switch (commandType) {
+ case FIGHT:
+ command = (currentMap != mapIndex.get(FIRST_MAP_IDENTITY)) ? new FightingCommand() : new ErrorCommand();
+ break;
+ case EXIT:
+ try {
+ command = (currentMap == mapIndex.get(SHOP)) ? new ExitShop() : new ErrorCommand();
+ } catch (NullPointerException e){
+ command = new ErrorCommand();
+ }
+ break;
+ case RUN:
+ command = (currentMap != mapIndex.get(FIRST_MAP_IDENTITY)) ? new RunningCommand() : new ErrorCommand();
+ break;
+ case MOVE_FORWARD:
+ command = (currentMap == mapIndex.get(FIRST_MAP_IDENTITY)) ?
+ new MovingForwardCommand(userCommand) : new ErrorCommand();
+ break;
+ case MOVE_DOWNWARD:
+ command = (currentMap == mapIndex.get(FIRST_MAP_IDENTITY)) ?
+ new MovingDownwardCommand(userCommand) : new ErrorCommand();
+ break;
+ case MOVE_LEFT:
+ command = (currentMap == mapIndex.get(FIRST_MAP_IDENTITY)) ?
+ new MovingLeftCommand(userCommand) : new ErrorCommand();
+ break;
+ case MOVE_RIGHT:
+ command = (currentMap == mapIndex.get(FIRST_MAP_IDENTITY)) ?
+ new MovingRightCommand(userCommand) : new ErrorCommand();
+ break;
+ case QUIT:
+ command = new QuitCommand();
+ break;
+ case INTERACT:
+ command = (currentMap == mapIndex.get(FIRST_MAP_IDENTITY)) ? new InteractingCommand() : new ErrorCommand();
+ break;
+ case HELP:
+ command = new HelpCommand();
+ break;
+ case ERROR:
+ command = new ErrorCommand();
+ break;
+ case INVENTORY:
+ command = (currentMap == mapIndex.get(FIRST_MAP_IDENTITY)) ?
+ new OpenInventoryCommand() : new ErrorCommand();
+ break;
+ case USE_ITEM:
+ command = (currentMap == mapIndex.get(INVENTORY_IDENTITY)) ?
+ new UseCommand(userCommand) : new ErrorCommand();
+ break;
+ case CLOSE_INV:
+ command = (currentMap == mapIndex.get(INVENTORY_IDENTITY)) ?
+ new CloseInventoryCommand() : new ErrorCommand();
+ break;
+ case RESET:
+ command = new ResetCommand();
+ break;
+ default:
+ command = new ErrorCommand();
+ }
+ return command;
+ }
+
+}
diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java
deleted file mode 100644
index 5c74e68d59..0000000000
--- a/src/main/java/seedu/duke/Duke.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package seedu.duke;
-
-import java.util.Scanner;
-
-public class Duke {
- /**
- * Main entry-point for the java.duke.Duke application.
- */
- public static void main(String[] args) {
- String logo = " ____ _ \n"
- + "| _ \\ _ _| | _____ \n"
- + "| | | | | | | |/ / _ \\\n"
- + "| |_| | |_| | < __/\n"
- + "|____/ \\__,_|_|\\_\\___|\n";
- System.out.println("Hello from\n" + logo);
- System.out.println("What is your name?");
-
- Scanner in = new Scanner(System.in);
- System.out.println("Hello " + in.nextLine());
- }
-}
diff --git a/src/main/java/textbox/PlayerStatus.java b/src/main/java/textbox/PlayerStatus.java
new file mode 100644
index 0000000000..8cc78ce1c4
--- /dev/null
+++ b/src/main/java/textbox/PlayerStatus.java
@@ -0,0 +1,109 @@
+package textbox;
+
+import map.PlayerInventory;
+
+public class PlayerStatus {
+ private static final int MAX_HEALTH = 100000;
+ private static final int MIN_VALUE = 0;
+ private static final int DEFAULT_HEALTH = 100;
+
+ private int playerHealth;
+ private int playerMoney;
+ private int playerExp;
+ private int playerDamage;
+ private PlayerInventory playerInventory;
+ private int playerDamageAmp;
+
+ public PlayerStatus(int startHealth, int startMoney, int startExp, int startDamage,
+ PlayerInventory playerInventory) {
+ this.playerHealth = setValidHealth(startHealth);
+ this.playerMoney = Math.max(startMoney, MIN_VALUE);
+ this.playerExp = Math.max(startExp, MIN_VALUE);
+ this.playerDamage = Math.max(startDamage, MIN_VALUE);
+ this.playerInventory = playerInventory;
+ this.playerDamageAmp = 0;
+ }
+
+ private int setValidHealth(int health) {
+ if (health <= 1 || health > MAX_HEALTH) {
+ System.out.println("INVALID HEALTH DETECTED. RESETTING TO DEFAULT");
+ return DEFAULT_HEALTH;
+
+ }
+ return health;
+ }
+
+ public int getPlayerHealth() {
+ return this.playerHealth;
+ }
+
+ public int getPlayerMoney() {
+ return this.playerMoney;
+ }
+
+ public int getPlayerExp() {
+ return this.playerExp;
+ }
+
+ public void setPlayerExp(int playerExp) {
+ this.playerExp = playerExp;
+ }
+
+ public void setPlayerHealth(int playerHealth) {
+ this.playerHealth = playerHealth;
+ }
+
+ public void setPlayerMoney(int playerMoney) {
+ this.playerMoney = playerMoney;
+ }
+
+ public int getPlayerDamage() {
+ return playerDamage;
+ }
+
+ public void setPlayerDamage(int playerDamage) {
+ this.playerDamage = playerDamage;
+ }
+
+ public void harmHealth(int dmg) {
+ int newHealth = this.playerHealth - dmg;
+ setPlayerHealth(newHealth);
+ }
+
+ public void addMoney(int money) {
+ long newMoney = (long) this.playerMoney + money;
+ if (newMoney > Integer.MAX_VALUE) {
+ this.playerMoney = Integer.MAX_VALUE;
+ } else {
+ this.playerMoney = (int) newMoney;
+ }
+ }
+
+ public void addExp(int exp) {
+ long newExp = (long) this.playerExp + exp;
+ if (newExp > Integer.MAX_VALUE) {
+ this.playerExp = Integer.MAX_VALUE;
+ } else {
+ this.playerExp = (int) newExp;
+ }
+ }
+
+ public PlayerInventory getPlayerInventory() {
+ return playerInventory;
+ }
+
+ public void setPlayerInventory(PlayerInventory playerInventory) {
+ if (playerInventory == null) {
+ throw new NullPointerException("Player inventory cannot be null.");
+ }
+ this.playerInventory = playerInventory;
+ }
+
+ public int getPlayerDamageAmp() {
+ return playerDamageAmp;
+ }
+
+ public void setPlayerDamageAmp(int dmg) {
+ this.playerDamageAmp = Math.max(dmg, MIN_VALUE);
+ }
+}
diff --git a/src/main/java/textbox/TextBox.java b/src/main/java/textbox/TextBox.java
new file mode 100644
index 0000000000..afd469a0cb
--- /dev/null
+++ b/src/main/java/textbox/TextBox.java
@@ -0,0 +1,58 @@
+package textbox;
+
+import command.Command;
+import map.BaseMap;
+
+public class TextBox {
+ protected static String nextInstruction;
+ protected static String nextNarration;
+ protected static String nextDialogue;
+ protected static String nextError;
+ public void initTextBox(){
+ nextInstruction = "Type 'h' to get the help menu.";
+ nextDialogue = " ";
+ nextNarration = "Welcome to Calcula: Chronicles of the Algorithmic Kingdom";
+ nextError = "";
+ }
+ public void nextTextBoxBasedOnMapAndCommand(Command userCommand, BaseMap map){
+
+ }
+
+ public void setNextInstruction(String message){
+ nextInstruction = message;
+ }
+ public void setNextNarration(String message){
+ nextNarration = message;
+ }
+
+ public void setNextDialogue(String message) {
+ nextDialogue = message;
+ }
+
+ public void setNextError(String message){
+ nextError = message;
+ }
+
+ public String getNextDialogue() {
+ return nextDialogue;
+ }
+
+ public String getNextInstruction() {
+ return nextInstruction;
+ }
+
+ public String getNextNarration() {
+ return nextNarration;
+ }
+
+ public String getNextError() {
+ return nextError;
+ }
+
+ public void clearAll(){
+ nextNarration = "";
+ nextInstruction = "";
+ nextDialogue = "";
+ nextError = "";
+ }
+}
diff --git a/src/main/java/ui/Ui.java b/src/main/java/ui/Ui.java
new file mode 100644
index 0000000000..d4e0915fa7
--- /dev/null
+++ b/src/main/java/ui/Ui.java
@@ -0,0 +1,256 @@
+package ui;
+
+import interactable.Enemy;
+import interactable.ShopKeeper;
+import inventoryitems.Item;
+import map.BaseMap;
+import textbox.PlayerStatus;
+import textbox.TextBox;
+import math.MathQuestion;
+import filereader.FileReader;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+
+
+public class Ui {
+ private static final int DEFAULT_WIDTH_OF_BATTLE_INTERFACE = 50;
+ private static final int DEFAULT_HEIGHT_OF_BATTLE_INTERFACE = 50;
+
+ public void printDividingLine() {
+ System.out.println("===========================================================");
+ }
+
+ public void printPlayerStatus(PlayerStatus statusBar) {
+ printDividingLine();
+ System.out.print("HEALTH: " + statusBar.getPlayerHealth() + " ");
+ System.out.print("MONEY: $" + statusBar.getPlayerMoney() + " ");
+ System.out.println("EXP: " + statusBar.getPlayerExp() + " ");
+ printDividingLine();
+ }
+
+
+ public void printTextBox(TextBox box) {
+ assert box.getNextDialogue() != null : "next dialogue is null";
+ assert box.getNextError() != null : "next error is null";
+ assert box.getNextInstruction() != null : "next instruction is null";
+ assert box.getNextNarration() != null : "next narration is null";
+
+
+ printDividingLine();
+ if (!box.getNextError().isEmpty()) {
+ System.out.println(box.getNextError());
+ }
+ if (!box.getNextNarration().isEmpty()) {
+ System.out.println(box.getNextNarration());
+ System.out.println("\n");
+ }
+ if (!box.getNextDialogue().isEmpty()) {
+ System.out.println(box.getNextDialogue());
+ }
+ if (!box.getNextInstruction().isEmpty()) {
+ System.out.println(box.getNextInstruction());
+ }
+ printDividingLine();
+ box.clearAll();
+ }
+
+ public void printTextbox(String message){ //for custom messages
+ printDividingLine();
+ System.out.println(message);
+ printDividingLine();
+ }
+
+ private static StringBuilder getStringBuilder(ArrayList row, String healthInfo) {
+ StringBuilder firstRowWithHealth = new StringBuilder();
+ for (int cellIndex = 0; cellIndex < row.size(); cellIndex++) {
+ // Append the art character until reaching the position to overlay health info
+ if (cellIndex < row.size() - healthInfo.length()) {
+ firstRowWithHealth.append(row.get(cellIndex));
+ } else {
+ // Start overlaying health info onto the map
+ int healthInfoIndex = cellIndex - (row.size() - healthInfo.length());
+ firstRowWithHealth.append(healthInfo.charAt(healthInfoIndex));
+ }
+ }
+ return firstRowWithHealth;
+ }
+
+
+ public void printMap(BaseMap map) {
+ printDividingLine();
+ for (ArrayList row : map.getMapData()) {
+ for (char cell : row) {
+ System.out.print(cell + " ");
+ }
+ System.out.println();
+ }
+ printDividingLine();
+ }
+
+ public void printMap(ArrayList> map, Enemy monster) {
+ printDividingLine();
+ String healthInfo = " Health: " + monster.getHealth(); // Health information as a string
+
+ for (int rowIndex = 0; rowIndex < map.size(); rowIndex++) {
+ ArrayList row = map.get(rowIndex);
+
+ // Overlay the health information on the first row directly within the ASCII art
+ if (rowIndex == 0) {
+ StringBuilder firstRowWithHealth = getStringBuilder(row, healthInfo);
+ System.out.println(firstRowWithHealth.toString());
+ } else {
+ for (char cell : row) {
+ System.out.print(cell);
+ }
+ System.out.println();
+ }
+ }
+ printDividingLine();
+ }
+
+
+ public void printEnemy(BaseMap map) {
+ printDividingLine();
+ for (ArrayList row : map.getMapData()) {
+ for (char cell : row) {
+ System.out.print(cell);
+ }
+ System.out.println();
+ }
+ printDividingLine();
+ }
+
+ public void printShopKeeper(ShopKeeper cat) throws FileNotFoundException {
+ FileReader fileReader = new FileReader(cat.getFilePath());
+ ArrayList> mapData = new ArrayList<>();
+ try {
+ mapData = fileReader.readDesign();
+ } catch (Exception e) {
+ System.out.println("Unable to read file from local");
+ }
+ for (ArrayList row : mapData) {
+ for (Character ch : row) {
+ System.out.print(ch); // Print each character without a newline
+ }
+ System.out.println(); // Print a newline after each row
+ }
+ }
+
+ public void printInventoryLine(String text, int quantity, int width) {
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("|");
+ stringBuilder.append(text);
+ int itemQuantityCharacters = quantity <= 0 ? 0 : (String.valueOf(quantity).length() + 3);
+ int length = width - text.length() - itemQuantityCharacters - 2;
+ stringBuilder.append(" ".repeat(Math.max(0, length)));
+ if (quantity > 0) {
+ stringBuilder.append("x");
+ stringBuilder.append(" ");
+ stringBuilder.append(quantity);
+ stringBuilder.append(" ");
+ }
+
+ stringBuilder.append("|");
+ System.out.println(stringBuilder.toString());
+ }
+
+ public void printInventory(ArrayList inventory, String name, int width, int height) {
+ printDividingLine();
+ StringBuilder header = buildHeader(name, width);
+ System.out.println(header);
+ printInventoryLine("", 0, width);
+ if (inventory.isEmpty()) {
+ for (int i = 0; i < height - 1; i += 1) {
+ System.out.print("|");
+ for (int j = 0; j < width - 2; j += 1) {
+ System.out.print(" ");
+ }
+ System.out.println("|");
+ }
+ return;
+ }
+ for (Item item : inventory) {
+ int itemIndex = inventory.indexOf(item) + 1;
+ printInventoryLine(" " + itemIndex + ". " + item.getName(), item.getQuantity(), width);
+ }
+ if (inventory.size() < height - 1) {
+ for (int i = 0; i < height - inventory.size() - 1; i += 1) {
+ printInventoryLine(" ", 0, width);
+ }
+ }
+ printDividingLine();
+ }
+
+ private static StringBuilder buildHeader(String inventoryName, int width) {
+ StringBuilder header = new StringBuilder();
+ int length = width - inventoryName.length() - 2;
+ header.append("|");
+ for (int i = 0; i <= length; i += 1) {
+ if (i == 1) {
+ header.append("<");
+ } else if (i == length - 1) {
+ header.append(">");
+ } else if (i == length / 2 - 1) {
+ header.append(inventoryName);
+ } else {
+ header.append(" ");
+ }
+ }
+ header.append("|");
+ return header;
+ }
+
+ public void printHelpMenu() {
+ printDividingLine();
+ System.out.println("'w' 'a' 's' 'd' to move around");
+ System.out.println("'e' to interact");
+ System.out.println("'i' to open inventory");
+ System.out.println("'q' to quit");
+ System.out.println("'h' to print help menu");
+ System.out.println("'run' to escape the battle interface");
+ printDividingLine();
+ }
+ public void printQuestion(MathQuestion mathQuestion){
+ System.out.println(mathQuestion.getQuestion());
+ }
+
+
+ public void printDeathMessage(){
+ System.out.println(" _______ ______ ________ ______ _____ ");
+ System.out.println("|\\ /|( ___ )|\\ /| ( __ \\ \\__ __/( ____ \\( __ \\ ");
+ System.out.println("( \\ / )| ( ) || ) ( | | ( \\ ) ) ( | ( \\/| ( \\ )");
+ System.out.println(" \\ (_) / | | | || | | | | | ) | | | | (__ | | ) |");
+ System.out.println(" \\ / | | | || | | | | | | | | | | __) | | | |");
+ System.out.println(" ) ( | | | || | | | | | ) | | | | ( | | ) |");
+ System.out.println(" | | | (___) || (___) | | (__/ )___) (___| (____/\\| (__/ )");
+ System.out.println(" \\_/ (_______)(_______) (______/ \\_______/(_______/(______/ ");
+ }
+
+
+ public void printWinMessage(PlayerStatus player) throws InterruptedException {
+ System.out.println(" __ __ ______ __ __ __ __ ______ __ __ \n" +
+ "| \\ / \\ / \\ | \\ | \\ | \\ _ | \\| \\| \\ | \\\n" +
+ " \\$$\\ / $$| $$$$$$\\| $$ | $$ | $$ / \\ | $$ \\$$$$$$| $$\\ | $$\n" +
+ " \\$$\\/ $$ | $$ | $$| $$ | $$ | $$/ $\\| $$ | $$ | $$$\\| $$\n" +
+ " \\$$ $$ | $$ | $$| $$ | $$ | $$ $$$\\ $$ | $$ | $$$$\\ $$\n" +
+ " \\$$$$ | $$ | $$| $$ | $$ | $$ $$\\$$\\$$ | $$ | $$\\$$ $$\n" +
+ " | $$ | $$__/ $$| $$__/ $$ | $$$$ \\$$$$ _| $$_ | $$ \\$$$$\n" +
+ " | $$ \\$$ $$ \\$$ $$ | $$$ \\$$$| $$ \\| $$ \\$$$\n" +
+ " \\$$ \\$$$$$$ \\$$$$$$ \\$$ \\$$ \\$$$$$$ \\$$ \\$$\n" +
+ " ");
+ Thread.sleep(3000);
+ System.out.println("You Completed the game with $" + player.getPlayerMoney() + " remaining and a total" +
+ " of " + player.getPlayerExp() + " exp!!");
+ Thread.sleep(3000);
+ System.out.println("Thank you for playing!!!");
+ }
+
+ public void insertOutOfBoundsMessage(TextBox box){
+ box.setNextNarration("You ran straight into a wall");
+ }
+
+ public void insertObjectObstructionMessage(TextBox box){
+ box.setNextNarration("Something appears to be blocking your way");
+ }
+}
diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..13eae68f38
--- /dev/null
+++ b/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: main.CalculaChroniclesOfTheAlgorithmicKingdom
+
diff --git a/src/main/resources/ShopKeeper/ShopKeeper.txt b/src/main/resources/ShopKeeper/ShopKeeper.txt
new file mode 100644
index 0000000000..15c47bd731
--- /dev/null
+++ b/src/main/resources/ShopKeeper/ShopKeeper.txt
@@ -0,0 +1,12 @@
+= = = = = = = = = = = = = = = = = = = = = = =
+| |
+| /\ /\ |
+| ( o o ) |
+| \ >-< / |
+| / \ |
+| / \ ^ |
+| | | // |
+| \ / // |
+| /// /// -- |
+| |
+= = = = = = = = = = = = = = = = = = = = = = =
\ No newline at end of file
diff --git a/src/main/resources/enemiesDesign/centaur.txt b/src/main/resources/enemiesDesign/centaur.txt
new file mode 100644
index 0000000000..07e917ddb9
--- /dev/null
+++ b/src/main/resources/enemiesDesign/centaur.txt
@@ -0,0 +1,12 @@
+= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+| <=======]}====== |
+| --. /| |
+| _\"/_.'/ |
+| .'._._,.' |
+| :/ \{}/ |
+| (L /--',----._ |
+| | \\ |
+| : /-\ .'-'\ / | |
+| \\, || \| |
+| \/ || || |
+= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
\ No newline at end of file
diff --git a/src/main/resources/enemiesDesign/demon.txt b/src/main/resources/enemiesDesign/demon.txt
new file mode 100644
index 0000000000..9414fb7fbb
--- /dev/null
+++ b/src/main/resources/enemiesDesign/demon.txt
@@ -0,0 +1,12 @@
+= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+| |
+| , , /\ /\ |
+| /( /\ )\ _\ \_/ /_ |
+| |\_||_/| < \_ _/ > |
+| \______/ \|0 0|/ |
+| _\/_ _(_ ^ _)_ |
+| ( () ) /`\|V"""V|/`\ |
+| {} \ \_____/ / |
+| () /\ )=( /\ |
+| {} / \_/\=/\_/ \ |
+= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
\ No newline at end of file
diff --git a/src/main/resources/enemiesDesign/dragon.txt b/src/main/resources/enemiesDesign/dragon.txt
new file mode 100644
index 0000000000..bd8581104f
--- /dev/null
+++ b/src/main/resources/enemiesDesign/dragon.txt
@@ -0,0 +1,39 @@
+= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+| / ) |
+| ( |\ |
+| /| \\ |
+| // \\ |
+| /// \| |
+| /( \ )\ |
+| \\ \_ //) |
+| \\ :\__ /// |
+| \\ ) // \ |
+| \\: / // |/ |
+| \\ / \ // \ |
+| /) \ ___..-' (| \_| |
+| // / _.' \ \ \ |
+| /| \ \________ \ | / |
+| (| _ _ __/ '-. ) /.' |
+| \\ . '-.__ \_ / / \ |
+| \\_'. > --._ '. \ / / / |
+| \ \ \ \ \ .' /.' |
+| \ \ '._ / \ ) / .' | |
+| \ \_ \_ | .'_/ __/ |
+| \ \ \_ | / / _/ \_ |
+| \ \ / _.' / / \ |
+| \ | /.' / .' '-,_ |
+| \ \ .' _.'_/ \ |
+| /\ /\ ) ___( /_.' \ | |
+| | _\__// \ (.' _/ | | |
+| \/_ __ /--'` , __/ / |
+| (o ) /o) \ '. : \___.-'_/ \__/ |
+| /:/: , ) : ( /_.'__/-'|_ _ / |
+| /:/: __/\ > __,_.----.__\ / (/(/(/ |
+| (_(,_/V .'/--' _/ __/ | / |
+| VvvV //` _.-' _.' \ \ |
+| n_n// (((/->/ | / |
+| '--' ~=' \ | |
+| | |_,,, |
+| \ \ / |
+| '.__) |
+= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
\ No newline at end of file
diff --git a/src/main/resources/enemiesDesign/goblin.txt b/src/main/resources/enemiesDesign/goblin.txt
new file mode 100644
index 0000000000..b97ffaf887
--- /dev/null
+++ b/src/main/resources/enemiesDesign/goblin.txt
@@ -0,0 +1,12 @@
+= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+| _____ |
+| .-,;='';_),-. |
+| \_\(),()/_/ |
+| (,___,) |
+| ,-/`~`\-,___ |
+| / /).:.('--._) |
+| {_[ (_,_) |
+| | Y | |
+| / | \ |
+| """ """ |
+= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
\ No newline at end of file
diff --git a/src/main/resources/enemiesDesign/gryphon.txt b/src/main/resources/enemiesDesign/gryphon.txt
new file mode 100644
index 0000000000..6d9924c53d
--- /dev/null
+++ b/src/main/resources/enemiesDesign/gryphon.txt
@@ -0,0 +1,15 @@
+= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+| ______ |
+| ______,---'__,---' |
+| _,-'---_---__,---' |
+| /_ (, ---____', |
+| / ',, `, ,-' |
+| ;/) ,',,_/,' |
+| | /\ ,.'//\ |
+| `-` \ ,,' `. |
+| `', ,-- `. |
+| '/ / | `, _ |
+| //'',.\_ .\\ ,{==>- |
+| __// __;_`- \ `;.__,;' |
+| ((,--,) (((,------; `--' |
+= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
\ No newline at end of file
diff --git a/src/test/java/command/CommandTest.java b/src/test/java/command/CommandTest.java
new file mode 100644
index 0000000000..fc88973629
--- /dev/null
+++ b/src/test/java/command/CommandTest.java
@@ -0,0 +1,11 @@
+package command;
+
+import org.junit.jupiter.api.BeforeEach;
+
+public class CommandTest {
+ Command a;
+ @BeforeEach
+ void setup(){
+
+ }
+}
diff --git a/src/test/java/command/fight/FightCommandTest.java b/src/test/java/command/fight/FightCommandTest.java
new file mode 100644
index 0000000000..66292c1299
--- /dev/null
+++ b/src/test/java/command/fight/FightCommandTest.java
@@ -0,0 +1,20 @@
+package command.fight;
+
+import command.Command;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class FightCommandTest {
+ Command a;
+ @BeforeEach
+ void setup() {
+ a = new FightingCommand();
+ }
+
+ @Test
+ void fightExecuteCorrectly() {
+ assertEquals("FIGHT!", a.getCommandDescription());
+ }
+}
diff --git a/src/test/java/command/mapmove/MapMoveCommandTest.java b/src/test/java/command/mapmove/MapMoveCommandTest.java
new file mode 100644
index 0000000000..35186ec533
--- /dev/null
+++ b/src/test/java/command/mapmove/MapMoveCommandTest.java
@@ -0,0 +1,4 @@
+package command.mapmove;
+
+public class MapMoveCommandTest {
+}
diff --git a/src/test/java/main/CalculaChroniclesOfTheAlgorithmicKingdom.java b/src/test/java/main/CalculaChroniclesOfTheAlgorithmicKingdom.java
new file mode 100644
index 0000000000..ab72d54c16
--- /dev/null
+++ b/src/test/java/main/CalculaChroniclesOfTheAlgorithmicKingdom.java
@@ -0,0 +1,4 @@
+package main;
+
+public class CalculaChroniclesOfTheAlgorithmicKingdom {
+}
diff --git a/src/test/java/map/MapTest.java b/src/test/java/map/MapTest.java
new file mode 100644
index 0000000000..fa0b8a65e1
--- /dev/null
+++ b/src/test/java/map/MapTest.java
@@ -0,0 +1,69 @@
+package map;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import java.util.ArrayList;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class MapTest {
+
+ private FirstMap map;
+
+ @BeforeEach
+ void setUp() {
+ map = new FirstMap();
+ map.initMap(5, 5);
+ map.initPlayerLocation(2, 2);
+ }
+
+ @Test
+ void mapShouldBeCorrectlyInitialized() {
+ ArrayList> expectedMap = new ArrayList<>();
+ for (int i = 0; i < 5; i++) {
+ ArrayList row = new ArrayList<>();
+ for (int j = 0; j < 5; j++) {
+ if (i == 2 && j == 2) {
+ row.add('P');
+ } else {
+ row.add('.');
+ }
+ }
+ expectedMap.add(row);
+ }
+
+ assertEquals(expectedMap, map.getMap(), "Map should be initialized correctly with player at (2,2)");
+ }
+
+ @Test
+ void playerShouldMoveUpCorrectly() {
+ map.movePlayerUpOne();
+ assertEquals('P', map.getMapData().get(1).get(2), "Player should move up 1 place");
+ assertEquals('.', map.getMapData().get(2).get(2),
+ "Original player position should be empty after moving up");
+ }
+
+ @Test
+ void playerShouldMoveDownCorrectly() {
+ map.movePlayerDownOne();
+ assertEquals('P', map.getMapData().get(3).get(2), "Player should move down 1 place");
+ assertEquals('.', map.getMapData().get(2).get(2),
+ "Original player position should be empty after moving down");
+ }
+
+ @Test
+ void playerShouldMoveLeftCorrectly() {
+ map.movePlayerLeftOne();
+ assertEquals('P', map.getMapData().get(2).get(1), "Player should move left 1 place");
+ assertEquals('.', map.getMapData().get(2).get(2),
+ "Original player position should be empty after moving left");
+ }
+
+ @Test
+ void playerShouldMoveRightCorrectly() {
+ map.movePlayerRightOne();
+ assertEquals('P', map.getMapData().get(2).get(3), "Player moves right 1 place");
+ assertEquals('.', map.getMapData().get(2).get(2),
+ "Original player position should be empty after moving right");
+ }
+}
+
diff --git a/src/test/java/parser/ParserTest.java b/src/test/java/parser/ParserTest.java
new file mode 100644
index 0000000000..3d734295c5
--- /dev/null
+++ b/src/test/java/parser/ParserTest.java
@@ -0,0 +1,29 @@
+package parser;
+
+
+import command.Command;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class ParserTest {
+
+ private Parser parser;
+
+ @BeforeEach
+ public void setup() {
+ this.parser = new Parser();
+ }
+
+ @Test
+ public void parse_emptyInput_returnsIncorrect() {
+ final String[] emptyInputs = { "", " ", "\n \n" };
+ parseAndAssertEmpty(emptyInputs);
+ }
+
+ public void parseAndAssertEmpty(String[] inputs) {
+ for (String input : inputs) {
+ final Command result = parser.parseCommand(input);
+ //assertEquals(result, new ErrorCommand());
+ }
+ }
+}
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 892cb6cae7..e69de29bb2 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,9 +0,0 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
-
-What is your name?
-Hello James Gosling
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index f6ec2e9f95..c502eafb86 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -1 +1,3 @@
-James Gosling
\ No newline at end of file
+s 3
+d
+quit
\ No newline at end of file