Skip to content

Commit

Permalink
Merge pull request #1 from JeffinsonDarmawan/fuzzylogic-enhancement
Browse files Browse the repository at this point in the history
Fuzzylogic enhancement
  • Loading branch information
JeffinsonDarmawan committed Apr 10, 2024
2 parents fe1c5fd + 0829906 commit d81b239
Show file tree
Hide file tree
Showing 19 changed files with 690 additions and 195 deletions.
8 changes: 4 additions & 4 deletions docs/DeveloperGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Removing Bouquets follows a similar logic, just that instead of calling `Bouquet

`info <flowerName>` command prints information about the specified flower

![Info Command Sequence Diagram](/docs/UML-diagrams/Ian/InfoCommandUML.png)
![Info Command Sequence Diagram](UML-diagrams/Ian/InfoCommandUML.png)

Step 1: Flower information mechanism utilize the `parser` class to parse user command for a specific flower name inputted.

Expand Down Expand Up @@ -85,7 +85,7 @@ Help command utilises the `parser` class to identify the keyword `help`

`add <flower> /q <quantity> /to <targetBouquet>` command adds specified number of flower to a bouquet

![Add Flower Command Diagram](/docs/UML-diagrams/Ijaaz/Ijaaz-UML.png)
![Add Flower Command Diagram](UML-diagrams/Ijaaz/Ijaaz-UML.png)

Step 1: Firstly the input is put into the `Parser.parse()` method to identify that it is infact an add flower command.

Expand All @@ -103,7 +103,7 @@ Step 5: A confirmation message is then sent back to the user

The proposed storage mechanism will utilize a class `storage` who is in charge of getting the file, `encoder` which will encode current model into a .txt file format, `decoder` which will decode .txt file into a usable model.

![Storage Class Diagram](/docs/UML-diagrams/Ian/storage.png)
![Storage Class Diagram](UML-diagrams/Ian/storage.png)

#### Design Considerations:
- Alternative 1 (current choice): use .txt files as storage
Expand Down Expand Up @@ -159,7 +159,7 @@ Priorities: High (must have) `* * *`, Medium (nice to have) `* *`, Low (unlikely

## Use cases

(For all all use cases below, the System is `Florizz` and the Actor is the `user`, unless specified otherwise)
(For all use cases below, the System is `Florizz` and the Actor is the `user`, unless specified otherwise)

**Use case: Create a new bouquet named "for valentine" and add 3 stalks of rose into the bouquet**

Expand Down
Binary file modified docs/UML-diagrams/Samuel/AddBouquets.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/UML-diagrams/Samuel/AddBouquets.puml
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ deactivate AddBouquetCommand
destroy AddBouquetCommand

Florizz-->user : "added valentines"
deactivate Florizz
@enduml
61 changes: 61 additions & 0 deletions docs/team/samuel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Samuel Ong - Project Portfolio Page

## Overview
Florizz is a digital florist replacement that helps users choose appropriate
flowers to put into a bouquet for various occasions.

### Summary of Contributions
* Code contributed: [RepoSense Link](https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=samuelory&breakdown=true&sort=groupTitle%20dsc&sortWithin=title&since=2024-02-23&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other&tabOpen=true&tabType=authorship&tabAuthor=samuelory&tabRepo=AY2324S2-CS2113-T11-3%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code~other&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false)


* **New feature**: Overall OOP of the product
* Wrote the overall flow of the product, i.e. having Ui take in inputs from the user,
have them be parsed by Parser, which then creates a Command to be executed by the core Florizz class.
* By setting the overall structure of the code for my teammates, it made it easier for them to implement
their features as they just had to create the Command as well how to parse information from the users input to the Command.


* **New feature**: Creating reading and deleting bouquets
* What it does: Allows the user to create and delete bouquets.
* Justification: This feature allows the user to arrange their own bouquets with their own flowers,
and also delete any unnecessary bouquets.
* Highlights: This feature involved overriding the equals method of the Bouquet class for it to only
be equals if the name of the Bouquet is the same, so that removing and adding to the Bouquet ArrayList would be much easier.


* **New feature**: Flower pages
* What it does: When viewing a list of flowers, instead of viewing the entire list of flowers,
the user would only see "pages" of max five flowers at once. The user would then be able to type "next" or "back"
to go forward or backwards respectively.
* Justification: This would make the code more future ready, as if the list of flowers gets too long,
the user would have to scroll up to view all the flowers if it was printed in one long list, which would
be really inconvenient.
* Highlights: This implementation was challenging as it required adding a memory of what list of flowers was last
printed to the users as well as what page they were currently on.


* **New Feature**: Ability to choose flower colour when adding/removing flowers to Bouquets.
* What it does: When adding flowers, if there is more than one colour available for a flower that the user wants to add,
the user has to choose the correct colour to add the flower. This can be achieved in two ways, including the colour in the
original command by including the /c <colour> field after the name, or if the user omitted that field, by viewing a list of
available colours for that flower after inputting the original command and choosing which colour they meant.
* Justification: In flower language, some flowers have vastly different meanings and can convey different intentions
if you simply change the colour. As such, it is important to specify the colour of the flower in the bouquets, lest the user
accidentally convey the wrong message to their target audience.
* Highlights: This command required two separate ways to implement the same feature as the storage of bouquets to memory involved
writing the command to the file, hence it was more efficient to condense all the relevant flower information into one command. On the
other hand, having too many fields in one command makes it inconvenient for the user to add or remove flowers, as well as the fact that
many flowers only have one flower. Hence, I decided to make putting the colour in the original command optional and allow the user to decide the colour later.


* **Enhancement to existing features**:
* Made flower colours and occasions enums within the Flower class. (Pull request [#62](https://github.com/AY2324S2-CS2113-T11-3/tp/pull/62))
* Updated info command to show flowers with different meanings and occasions for different colours. (Pull request [#89](https://github.com/AY2324S2-CS2113-T11-3/tp/pull/89))


* **Documentation**:
* User Guide:
* Added documentation for features `new bouquet`, `mybouquets` and `delete bouquet`
* Updated documentation for `info` and `flowers` features
* Developer Guide:
* Added implementation details for `new bouquet` feature
59 changes: 41 additions & 18 deletions src/main/java/florizz/command/AddFlowerCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
public class AddFlowerCommand extends Command{
private static Logger logger = Logger.getLogger(AddFlowerCommand.class.getName());
private String flowerName;
private Flower.Colour colour;
private boolean hasColour = false;
private Integer quantity;
private String bouquetName;
private boolean enableUi;
Expand All @@ -22,7 +24,15 @@ public AddFlowerCommand(String flowerName, int quantity, String bouquetName, boo
this.bouquetName = bouquetName;
this.enableUi = enableUi;
}

public AddFlowerCommand(String flowerName, Flower.Colour colour,
int quantity, String bouquetName, boolean enableUi) {
this.flowerName = flowerName;
this.colour = colour;
this.quantity = quantity;
this.bouquetName = bouquetName;
this.enableUi = enableUi;
this.hasColour = true;
}
@Override
public boolean execute(ArrayList<Bouquet> bouquetList, Ui ui) throws FlorizzException {
logger.entering(AddFlowerCommand.class.getName(), "execute");
Expand All @@ -39,28 +49,41 @@ public boolean execute(ArrayList<Bouquet> bouquetList, Ui ui) throws FlorizzExce
throw new FlorizzException("No such bouquet is found.");
}

boolean doesFlowerExist = false;
Flower flowerToBeAdded = new Flower();
for (int i = 0; !doesFlowerExist && i < FlowerDictionary.size(); i++) {
if (FlowerDictionary.get(i).getFlowerName().toLowerCase().equals(flowerName)) {
//TODO should be extracted to its own function getFlower(String name, String colour)
flowerToBeAdded = FlowerDictionary.get(i);
doesFlowerExist = true;
ArrayList<Flower> matchingFlowers = FlowerDictionary.filterByName(flowerName);
Flower flowerToAdd;
if (hasColour){
ArrayList<Flower> matchedFlowerAndColour = FlowerDictionary.filterByColour(matchingFlowers, colour);
if (!matchedFlowerAndColour.isEmpty()){
flowerToAdd = matchedFlowerAndColour.get(0);
bouquetToAddFlower.addFlower(flowerToAdd,this.quantity);
if (enableUi) {
ui.printAddFlowerSuccess(bouquetList, flowerToAdd.getNameAndColour(), quantity, bouquetName);
}
} else {
throw new FlorizzException("This flower does not exist in that colour. " +
"Type info <flower> to view all available colours for this flower");
}
} else if (matchingFlowers.size()==1){
flowerToAdd = matchingFlowers.get(0);
bouquetToAddFlower.addFlower(matchingFlowers.get(0), this.quantity);
if (enableUi) {
ui.printAddFlowerSuccess(bouquetList, flowerToAdd.getNameAndColour(), quantity, bouquetName);
}
} else {
flowerToAdd = ui.chooseColour(matchingFlowers, flowerName);
if (!flowerToAdd.getFlowerName().isBlank()){
bouquetToAddFlower.addFlower(flowerToAdd, this.quantity);
if (enableUi) {
ui.printAddFlowerSuccess(bouquetList, flowerToAdd.getNameAndColour(), quantity, bouquetName);
}
} else {
ui.printCancelCommand();
}
}

if (!doesFlowerExist) {
throw new FlorizzException("Mentioned flower is not in our database." + System.lineSeparator() +
"Check available flowers: `flower` " + System.lineSeparator() +
"Add custom flowers: {{TO BE DONE}}");
}

bouquetToAddFlower.addFlower(flowerToBeAdded, this.quantity);
if (enableUi) {
ui.printAddFlowerSuccess(bouquetList, flowerName, quantity, bouquetName);
}

logger.exiting(AddFlowerCommand.class.getName(), "execute");
return true;
}

}
24 changes: 16 additions & 8 deletions src/main/java/florizz/command/RecommendCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,13 @@ public boolean execute(ArrayList<Bouquet> bouquetList, Ui ui) throws FlorizzExce
* @param bouquetList List that contains all bouquets
* @return The chosen valid bouquetName
*/
public String askBouquetName(Ui ui, ArrayList<Bouquet> bouquetList) {
public String askBouquetName(Ui ui, ArrayList<Bouquet> bouquetList) throws FlorizzException {
boolean isValidName = false;
String bouquetName = "placeHolder";
ui.printAskBouquetName();
while (!isValidName) {
bouquetName = ui.getInput();
Parser.checkRecommendExitCondition(bouquetName);
if (bouquetList.contains(new Bouquet(bouquetName))) {
System.out.println("Sorry a bouquet with this name already exists, please enter another name");
} else {
Expand Down Expand Up @@ -91,18 +92,22 @@ private void addRandomFlowers(ArrayList<Flower> eligibleFlowers, Bouquet recomme
* Asks user for occasion
* @return Occasion enum
*/
private Flower.Occasion askOccasion(Ui ui) {

private Flower.Occasion askOccasion(Ui ui) throws FlorizzException{
logger.entering(RecommendCommand.class.getName(), "askOccasion");
boolean isValidFormat = false;
boolean isValidOccasion = false;
String occasionInput = "placeholder";
ui.printAskOccasion();
while (!(isValidFormat && isValidOccasion)) {
occasionInput = ui.printAskOccasion();
occasionInput = ui.getInput();
Parser.checkRecommendExitCondition(occasionInput);
isValidFormat = Parser.parseOccasion(occasionInput);
isValidOccasion = Flower.isValidOccasion(occasionInput);
// check if occasion is in our dictionary
if (!isValidOccasion) {
System.out.println("This occasion does not exist.");
System.out.println("This occasion does not exist." +
"Type 'cancel' if you would like to exit the recommendation page");
}
}

Expand All @@ -116,20 +121,23 @@ private Flower.Occasion askOccasion(Ui ui) {
* @param eligibleFlowers list of flowers to choose from
* @return Colour enum
*/
private Flower.Colour askColour(Ui ui, ArrayList<Flower> eligibleFlowers) {
private Flower.Colour askColour(Ui ui, ArrayList<Flower> eligibleFlowers) throws FlorizzException{
assert !eligibleFlowers.isEmpty() : "Eligible flowers should not be empty";
logger.entering(RecommendCommand.class.getName(), "askColour");
String colourInput = "placeHolder";
boolean isValidFormat = false;
boolean isValidColour = false;
ui.printAskColour(eligibleFlowers);
while (!(isValidColour && isValidFormat)) {
colourInput = ui.printAskColour(eligibleFlowers);
colourInput = ui.getInput();
Parser.checkRecommendExitCondition(colourInput);
isValidFormat = Parser.parseColour(colourInput);
isValidColour = Flower.isValidColour(colourInput);

// check if colour is in our dictionary
if (!isValidColour) {
System.out.println("This colour does not exist.");
System.out.println("This colour does not exist. " +
"Type 'cancel' if you would like to exit the recommendation page");
}
}

Expand All @@ -144,7 +152,7 @@ private void askSaveBouquet(Ui ui, ArrayList<Bouquet> bouquetList,
boolean isValidFormat = false;
boolean isValidInput = false;
while (!(isValidInput && isValidFormat)) {
saveInput = ui.printAskSaveBouquet(recommendedBouquet);
saveInput = ui.printAskSaveBouquet(recommendedBouquet).toLowerCase();
isValidFormat = Parser.parseSaveBouquet(saveInput);
isValidInput = (saveInput.equalsIgnoreCase("yes") || saveInput.equalsIgnoreCase("no"));
}
Expand Down
51 changes: 35 additions & 16 deletions src/main/java/florizz/command/RemoveFlowerCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,22 @@ public class RemoveFlowerCommand extends Command {
private String flowerName;
private Integer quantity;
private String bouquetName;
private Flower.Colour colour;
private boolean hasColour = false;

public RemoveFlowerCommand(String flowerName, int quantity, String bouquetName) {
this.flowerName = flowerName;
this.quantity = quantity;
this.bouquetName = bouquetName;
}

public RemoveFlowerCommand(String flowerName, Flower.Colour colour, int quantity, String bouquetName) {
this.flowerName = flowerName;
this.quantity = quantity;
this.bouquetName = bouquetName;
this.colour = colour;
hasColour = true;
}
@Override
public boolean execute(ArrayList<Bouquet> bouquetList, Ui ui) throws FlorizzException {
logger.entering(RemoveFlowerCommand.class.getName(), "execute");
Expand All @@ -39,28 +48,38 @@ public boolean execute(ArrayList<Bouquet> bouquetList, Ui ui) throws FlorizzExce
"Create a bouquet by using 'new <bouquetName>`");
}

boolean doesFlowerExist = false;
Flower flowerToBeAdded = new Flower();
for (int i = 0; !doesFlowerExist && i < FlowerDictionary.size(); i++) {
if (FlowerDictionary.get(i).getFlowerName().toLowerCase().equals(flowerName)) {
flowerToBeAdded = FlowerDictionary.get(i);
doesFlowerExist = true;
ArrayList<Flower> matchingFlowers = FlowerDictionary.filterByName(
bouquetToRemoveFlower.getFlowerList(), flowerName);
Flower flowerToRemove;
if (hasColour){
ArrayList<Flower> matchedFlowerAndColour = FlowerDictionary.filterByColour(matchingFlowers, colour);
if (!matchedFlowerAndColour.isEmpty()){
flowerToRemove = matchedFlowerAndColour.get(0);
bouquetToRemoveFlower.removeFlower(flowerToRemove,this.quantity);
ui.printRemoveFlowerSuccess(bouquetList, flowerToRemove.getNameAndColour(), quantity, bouquetName);
} else {
throw new FlorizzException("This bouquet does not contain that colour" +
"Type mybouquets to view all your bouquets.");
}
}
} else if (matchingFlowers.size()==1){
flowerToRemove = matchingFlowers.get(0);
bouquetToRemoveFlower.removeFlower(flowerToRemove, this.quantity);
ui.printRemoveFlowerSuccess(bouquetList, flowerToRemove.getNameAndColour(), quantity, bouquetName);

if (!doesFlowerExist) {
throw new FlorizzException("Mentioned flower is not in our database." + System.lineSeparator() +
"Check available flowers: `flower` " + System.lineSeparator() +
"Add custom flowers: {{TO BE DONE}}");
}

if (bouquetToRemoveFlower.removeFlower(flowerToBeAdded, this.quantity)) {
ui.printRemoveFlowerSuccess(bouquetList, flowerName, quantity, bouquetName);
} else {
ui.printRemoveFlowerUnsuccessful(bouquetList, flowerName, bouquetName);
flowerToRemove = ui.chooseColour(matchingFlowers, flowerName);
if (!flowerToRemove.getFlowerName().isBlank()){
bouquetToRemoveFlower.removeFlower(flowerToRemove, this.quantity);
ui.printRemoveFlowerSuccess(bouquetList, flowerToRemove.getNameAndColour(), quantity, bouquetName);
} else {
ui.printCancelCommand();
}

}

logger.exiting(RemoveFlowerCommand.class.getName(), "execute");
return true;
}


}
3 changes: 2 additions & 1 deletion src/main/java/florizz/command/SaveCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ public SaveCommand(String bouquetName) {
*/
@Override
public boolean execute(ArrayList<Bouquet> bouquetList, Ui ui) throws FlorizzException {
assert !bouquetName.isEmpty() : "bouquet name cannot be empty";
int bouquetIdx = bouquetList.indexOf(new Bouquet(bouquetName));
if (bouquetIdx == -1) {
throw new FlorizzException("This bouquet does not exist. Create it by typing 'new <BOUQUETNAME>'");
throw new FlorizzException("This bouquet does not exist. Create it by typing 'new <bouquetName>'");
}
Storage storage = new Storage();
try {
Expand Down
Loading

0 comments on commit d81b239

Please sign in to comment.