diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..13566b81b --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 000000000..56784efc1 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 000000000..aa00ffab7 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 000000000..7d2f77bf9 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,212 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 000000000..e0844bc7b --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 000000000..2b63946d5 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 000000000..2131f53ad --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + { + "associatedIndex": 2 +} + + + + { + "keyToString": { + "Application.GameOverView.executor": "Run", + "Application.GameView.executor": "Run", + "Application.Login.executor": "Run", + "Application.LoginViewTest.executor": "Run", + "Application.Login_view.executor": "Run", + "Application.Main.executor": "Run", + "Application.MainNoteApplication.executor": "Run", + "Application.MainView.executor": "Run", + "Application.RankingView.executor": "Run", + "Application.SignUpView.executor": "Run", + "RunOnceActivity.OpenProjectViewOnStart": "true", + "RunOnceActivity.ShowReadmeOnStart": "true", + "git-widget-placeholder": "main", + "kotlin-language-version-configured": "true", + "last_opened_file_path": "D:/csc236" + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1731266409449 + + + + \ No newline at end of file diff --git a/README.md b/README.md index 5e1d8b77c..93156e076 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,136 @@ -# Note Application +# **60 Days to Survive** -This is a minimal example demonstrating usage of the -password-protected user part of the API used in lab 5. +## **Table of Contents** +- [Project Overview](#project-overview) +- [Features](#features) +- [Installation Instructions](#installation-instructions) +- [Usage Guide](#usage-guide) +- [Contribution Guidelines](#contribution-guidelines) +- [Authors](#authors) +- [License](#license) +- [Feedback](#feedback) -You can find more information about the API endpoints in -[the documentation](https://www.postman.com/cloudy-astronaut-813156/csc207-grade-apis-demo/documentation/fg3zkjm/5-password-protected-user). +--- -If your team is considering an application for which it would be convenient to -store data in something like a database, you may find that the API calls demonstrated -here will be useful in your project, as this will allow you to store -an arbitrary JSON object associated with a username and password. +## **Project Overview** +**60 Days to Survive** is a text-based strategy game set in a post-apocalyptic zombie world. Players must manage resources, handle daily random events, and survive for 60 days. This project is built using **Clean Architecture (CA)** for modularity, maintainability, and ease of future enhancements. -In this application, a single note has a name (the "username" in terms of the API) and the note -can be read by anyone who knows the name — but only edited by someone who -knows the password for it. +**Why This Project?** +- Provides an engaging and challenging survival experience. +- Demonstrates the practical application of Clean Architecture. +- Aims to create a modular game that is easy to extend and maintain. -You can see the documentation in the various files for more information. +--- -## Testing +## **Features** +1. **Resource Management**: + - Players must manage resources like food, water, weapons, and action points. + - Resource availability influences survival outcomes. -The repo also includes an example of a use case interactor test, as well as -an example of an end-to-end test which automates button clicks and inspects -the contents of the actual views. This is something we discussed in the lectures -about testing in CA but had not provided a code example of before. Note, one -could also inspect the contents of the ViewModel objects instead when testing -CA to make a similar test which would be less dependent on the details of the -specific UI implementation. +2. **Random Events**: + - Handle events such as ambushes, blizzards, and encounters with traders. + - Each event has choices, risks, and rewards. -## Project Starter Code +3. **Map Navigation**: + - Players can move around the map to explore different terrains and gather resources. -Your team may choose to use this repo as starter code for your project. You could -also use the lab 5 code — or start from an empty repo if your team prefers. +4. **Daily Updates**: + - Each day introduces new challenges, including resource depletion and potential encounters. + +5. **Leaderboard**: + - Track your performance and compare with other players. + +--- + +## **Installation Instructions** +### **Environment Requirements** +- **JDK**: Java 11 or higher. +- **IDE**: IntelliJ IDEA or any Java-compatible IDE. +- **Dependencies**: + - **Jackson**: For JSON data manipulation. + +### **Setup Steps** +1. Clone the repository: + ```bash + git clone https://github.com/Adidazdoge/NoteApplication.git +2. Import the project into your IDE and configure the JDK. +3. Install dependencies via your IDE's package manager. +4. Run the main application: + src/app/JsonApplication.java +## **Usage Guide** +1. Login or Register: + - Use the login interface to sign in or create a new account. +2. Main Menu Options: + - New Game: Start a new survival challenge. + - Leaderboard: View rankings of players. + - Quit: Exit the game. +3. Gameplay: + - Daily Actions: + - Manage resources. + - Move around the map. + - Handle random events. + - Survive 60 Days: + - Balance risks and resources to outlast the apocalypse. +### **Contribution Guidelines** +We welcome contributions to improve 60 Days to Survive. Here’s how you can contribute: +**Steps to Contribute** +1. Fork the repository: + ```bash + git fork https://github.com/Adidazdoge/NoteApplication.git +2. Create a new branch: + ```bash + git checkout -b feature/your-feature +3. Commit your changes: + ```bash + git commit -m "Add your feature" +4. Push your branch: + ```bash + git push origin feature/your-feature +5. Create a Pull Request and await review. +**Contribution Guidelines** + - Provide clear commit messages. + - Follow the project's coding standards. + - Ensure all tests pass before submitting your changes. + - Include documentation for any new features. +### **Authors** + - Yitong An - vinkoos + - Haoze Li - FlashYDirOX + - Ze Kun Song - UTSGJohnsonSong + - Owen Hexiang Wang- Adidazdoge + - Xiaoshu Lin - Michael-lin6677 +### **License** + This project is licensed under the CC0 1.0 Universal license. See the LICENSE file for details. +## **Feedback** +We value your feedback and encourage you to share your thoughts to help us improve the game! Here's how you can give feedback: + +1. **Email Us**: + If you have suggestions, feature requests, or bug reports, please email [dooolly647@gmail.com]. + +### Feedback Guidelines +- Ensure your feedback is clear, concise, and respectful. +- Use the following template when reporting issues: + ```plaintext + **Subject: Feedback/Issue Report - 60 Days to Survive** + + **Description:** + Provide a clear and concise description of the issue or suggestion. + + **Steps to Reproduce (if applicable):** + 1. Step one + 2. Step two + 3. Step three + + **Expected Behavior (if applicable):** + Describe what you expected to happen. + + **Actual Behavior (if applicable):** + Describe what actually happened. + + **Environment:** + - OS: (e.g., Windows 10, macOS Monterey) + - Java Version: (e.g., Java 11) + - IDE: (e.g., IntelliJ IDEA 2022) + + **Additional Notes:** + Add any other relevant information or context here. -If you choose to use one of the repositories we have provided, you can either make -a fork of it or copy the subset of code you want into a completely new repository. diff --git a/accessibility-report.md b/accessibility-report.md new file mode 100644 index 000000000..3c8b0705d --- /dev/null +++ b/accessibility-report.md @@ -0,0 +1,43 @@ +# **Project Accessibility Report** + +## **Principles of Universal Design** + +### 1. **Equitable Use** +- **Adherence**: The program provides the same gameplay experience for all users without discrimination. Every player, regardless of skill level, can engage with the game equally. +- **Future Improvements**: Implement features like adjustable difficulty levels to further cater to a wider range of user abilities. + +### 2. **Flexibility in Use** +- **Adherence**: The game allows players to make strategic decisions, providing multiple ways to survive (e.g., resource management, map navigation, or focusing on event handling). +- **Future Improvements**: Introduce settings to customize gameplay, such as enabling or disabling certain types of events. + +### 3. **Simple and Intuitive Use** +- **Adherence**: The game uses straightforward text-based commands, making it accessible even for users with minimal technical experience. +- **Future Improvements**: Provide an in-game tutorial or tooltips to explain mechanics to new players. + +### 4. **Perceptible Information** +- **Adherence**: Information about resources, events, and player status is clearly displayed in the UI. +- **Future Improvements**: Add audio cues for key actions to support users with visual impairments. + +### 5. **Tolerance for Error** +- **Adherence**: Players can retry actions or adapt their strategy based on outcomes without immediate penalties. +- **Future Improvements**: Introduce a save-and-load system to allow players to recover from critical mistakes. + +### 6. **Low Physical Effort** +- **Adherence**: The program requires minimal input, as most actions are performed through simple text commands or button presses. +- **Future Improvements**: Add voice recognition features for hands-free gameplay. + +### 7. **Size and Space for Approach and Use** +- **Adherence**: The text-based interface works well on various screen sizes and resolutions. +- **Future Improvements**: Develop mobile-friendly versions or adaptive layouts for different screen dimensions. + +--- + +## **Target Market** +If marketed, **60 Days to Survive** would appeal to fans of text-based strategy games, particularly those who enjoy post-apocalyptic survival scenarios. The game is suitable for players seeking a challenging, story-driven experience with resource management and decision-making elements. It would also attract hobbyists interested in games designed with Clean Architecture, as well as students learning about modular software design. + +In addition, the game could target casual gamers who prefer low-intensity, text-based gameplay that doesn't require high-end hardware. By maintaining simplicity in its user interface and gameplay, the game can cater to a diverse audience, including those new to the strategy or survival genres. + +--- + +## **Potential Demographic Barriers** +The program might be less accessible to players with certain disabilities, such as visual impairments, due to its reliance on a text-based interface. Future updates could incorporate accessibility features like text-to-speech or screen reader support to mitigate this issue. Additionally, the game’s English-only interface might limit access for non-English speakers. diff --git a/data/players.json b/data/players.json new file mode 100644 index 000000000..869394386 --- /dev/null +++ b/data/players.json @@ -0,0 +1,12 @@ +[ + { + "id": "1", + "username": "user1", + "password": "password1" + }, + { + "id": "2", + "username": "user2", + "password": "password2" + } +] diff --git a/data/rankings.json b/data/rankings.json new file mode 100644 index 000000000..bfe0b9545 --- /dev/null +++ b/data/rankings.json @@ -0,0 +1,14 @@ +[ + { + "playerId": "1", + "score": 200, + "daysSurvived": 30, + "won": true + }, + { + "playerId": "2", + "score": 150, + "daysSurvived": 20, + "won": false + } +] diff --git a/note-application.iml b/note-application.iml new file mode 100644 index 000000000..9e3449c9d --- /dev/null +++ b/note-application.iml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 527f61e36..42e4b8306 100644 --- a/pom.xml +++ b/pom.xml @@ -21,6 +21,7 @@ okhttp 4.12.0 + junit junit @@ -28,9 +29,33 @@ test - - + + com.fasterxml.jackson.core + jackson-databind + 2.15.2 + + + com.fasterxml.jackson.core + jackson-core + 2.15.2 + + + com.fasterxml.jackson.core + jackson-annotations + 2.15.2 + + + com.squareup.okhttp3 + okhttp + 4.10.0 + + + com.google.code.gson + gson + 2.8.9 + + 11 @@ -38,4 +63,4 @@ UTF-8 - \ No newline at end of file + diff --git a/src/main/java/app/JsonApplication.java b/src/main/java/app/JsonApplication.java new file mode 100644 index 000000000..20793d42e --- /dev/null +++ b/src/main/java/app/JsonApplication.java @@ -0,0 +1,367 @@ +package app; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; + +import entities.*; +import frameworks.database.InMemoryUnifiedDataAccess; +import frameworks.database.JsonLoginDataAccess; +import frameworks.database.JsonSignupDataAccess; +import frameworks.database.JsonRankingDataAccess; +import interface_adapters.EventManager; +import interface_adapters.NavigationManager; +import interface_adapters.NavigationManagerJson; +import interface_adapters.broadcast.BroadcastController; +import interface_adapters.broadcast.BroadcastPresenter; +import interface_adapters.dailygather.DailyGatherController; +import interface_adapters.dailygather.DailyGatherPresenter; +import interface_adapters.dailymove.DailyMoveController; +import interface_adapters.dailymove.DailyMovePresenter; +import interface_adapters.endprocesshorde.HordeController; +import interface_adapters.endprocesshorde.HordePresenter; +import interface_adapters.eventdecide.EventDecideController; +import interface_adapters.eventdecide.EventDecidePresenter; +import interface_adapters.eventinitializer.EventInitializerController; +import interface_adapters.eventinitializer.EventInitializerPresenter; +import interface_adapters.eventrespond.ambush.AmbushResponseController; +import interface_adapters.eventrespond.ambush.AmbushResponsePresenter; +import interface_adapters.eventrespond.blizzard.BlizzardResponseController; +import interface_adapters.eventrespond.blizzard.BlizzardResponsePresenter; +import interface_adapters.eventrespond.flood.FloodResponseController; +import interface_adapters.eventrespond.flood.FloodResponsePresenter; +import interface_adapters.eventrespond.survivor.SurvivorResponseController; +import interface_adapters.eventrespond.survivor.SurvivorResponsePresenter; +import interface_adapters.eventrespond.trader.TraderResponseController; +import interface_adapters.eventrespond.trader.TraderResponsePresenter; +import interface_adapters.fetchcurrentevent.FetchEventController; +import interface_adapters.fetchcurrentevent.FetchEventPresenter; +import interface_adapters.fetchresource.FetchController; +import interface_adapters.fetchresource.FetchPresenter; +import interface_adapters.gamelosedetecter.LoseController; +import interface_adapters.gamelosedetecter.LosePresenter; +import interface_adapters.gameminimap.MinimapController; +import interface_adapters.gameminimap.MinimapPresenter; +import interface_adapters.gamenewday.NewdayController; +import interface_adapters.gamenewday.NewdayPresenter; +import interface_adapters.gameplacedescription.PlaceDescriptionController; +import interface_adapters.gameplacedescription.PlaceDescriptionPresenter; +import interface_adapters.login.LoginController; +import interface_adapters.login.LoginPresenter; +import interface_adapters.nevagateallowcatepage.NevagateAllowcateController; +import interface_adapters.nevagateallowcatepage.NevagateAllowcatePresenter; +import interface_adapters.nevagateevent.NevagateEventController; +import interface_adapters.nevagateevent.NevagateEventPresenter; +import interface_adapters.nevagategame.NevagateGameController; +import interface_adapters.nevagategame.NevagateGamePresenter; +import interface_adapters.nevagategameover.NevagateGameOverController; +import interface_adapters.nevagategameover.NevagateGameOverPresenter; +import interface_adapters.nevagatemainview.NevagateMainController; +import interface_adapters.nevagatemainview.NevagateMainPresenter; +import interface_adapters.rankinglist.RankingController; +import interface_adapters.rankinglist.RankingPresenter; +import interface_adapters.signup.SignupController; +import interface_adapters.signup.SignupPresenter; +import interface_adapters.startallowcatepoint.AllowcateController; +import interface_adapters.startallowcatepoint.AllowcatePresenter; +import usecases.accountlogin.LoginInteractor; +import usecases.accountsignup.SignupInteractor; +import usecases.accountranking.RankingInteractor; +import usecases.chatgpt.ChatGptResponseParser; +import usecases.chatgpt.ChatGptService; +import usecases.dailybroadcast.BroadcastInteractor; +import usecases.dailygather.GatherInteractor; +import usecases.dailymove.MoveInteractor; +import usecases.endprocesshorde.HordeInteractor; +import usecases.eventdecide.DecideEventInteractor; +import usecases.eventinitialize.EventInitializeInteractor; +import usecases.eventrespond.ambush.AmbushEventInteractor; +import usecases.eventrespond.blizzard.BlizzardEventInteractor; +import usecases.eventrespond.flood.FloodEventInteractor; +import usecases.eventrespond.survivor.SurvivorEventInteractor; +import usecases.eventrespond.trader.TraderEventInteractor; +import usecases.fetchcurrentevent.CurrentEventInteractor; +import usecases.fetchresource.FetchInteractor; +import usecases.gamelosedetecter.LoseInteractor; +import usecases.gameminimap.MinimapInteractor; +import usecases.gamenewday.NewdayInteractor; +import usecases.gameplacedescription.PlaceDescriptionInteractor; +import usecases.nevagateAllowcatePage.NevagateAllowcateInteractor; +import usecases.nevagateEventPage.NevagateEventInteractor; +import usecases.nevagateGame.NevagateGameInteractor; +import usecases.nevagateGameover.NevagateGameOverInteractor; +import usecases.navigateMain.NavigateMainInteractor; +import usecases.startallowcate.AllowcateInteractor; +import view.*; + +public class JsonApplication { + private final NavigationManagerJson navigationManagerJson; + private final LoginController loginController; + private final SignupController signupController; + private final RankingController rankingController; + private final LoginView loginView; + private final SignUpView signUpView; + private final RankingView rankingView; + private final MainView mainView; + private final RestartGameController restartGameController = new RestartGameController(this); + + /** + * Initializes the integrated application. + * + * @param loginFilePath Path to the login JSON file. + * @param signupFilePath Path to the signup JSON file. + * @param rankingFilePath Path to the ranking JSON file. + * @throws IOException If there is an issue accessing the JSON files. + */ + public JsonApplication(String loginFilePath, String signupFilePath, String rankingFilePath) throws IOException { + // Initialize Views + this.loginView = new LoginView(); + this.signUpView = new SignUpView(); + this.rankingView = new RankingView(); + this.mainView = new MainView(); + + // Navigation Manager + navigationManagerJson = new NavigationManagerJson(loginView, signUpView, mainView, rankingView); + + // Login Initialization + final JsonLoginDataAccess loginDataAccess = new JsonLoginDataAccess(loginFilePath); + final LoginPresenter loginPresenter = new LoginPresenter(loginView, navigationManagerJson); + final LoginInteractor loginInteractor = new LoginInteractor(loginDataAccess, loginPresenter); + loginController = new LoginController(loginInteractor); + loginView.setLoginController(loginController); + + // Signup Initialization + final JsonSignupDataAccess signupDataAccess = new JsonSignupDataAccess(signupFilePath); + final SignupPresenter signupPresenter = new SignupPresenter(signUpView); + final SignupInteractor signupInteractor = new SignupInteractor(signupDataAccess, signupPresenter); + signupController = new SignupController(signupInteractor); + signUpView.setSignupController(signupController); + + // Ranking Initialization + final JsonRankingDataAccess rankingDataAccess = new JsonRankingDataAccess(rankingFilePath); + final RankingPresenter rankingPresenter = new RankingPresenter(rankingView); + final RankingInteractor rankingInteractor = new RankingInteractor(rankingDataAccess, rankingPresenter); + rankingController = new RankingController(rankingInteractor); + rankingView.setRankingController(rankingController); + + // Link navigation manager to login view + loginView.setNavigationManager(navigationManagerJson); + signUpView.setNavigationManager(navigationManagerJson); + rankingView.setNavigationManager(navigationManagerJson); + mainView.setNavigationManager(navigationManagerJson); + mainView.setRestartGameController(this.restartGameController); + + // Start login view + loginView.render(); + } + public void startnewgame() { + gameApplication(mainView, navigationManagerJson); + } + + private void gameApplication(MainView mainView, NavigationManagerJson navigationManagerJson) { + // initialized map + final ArrayList environments = new ArrayList<>(Arrays.asList(EntityConstants.PLAIN, + EntityConstants.CITY, EntityConstants.FOREST, EntityConstants.DESERT, EntityConstants.ICELAND)); + final MapFactory mapfact = new MapFactory(); + final ArrayList>>> cores = + mapfact.getCores(EntityConstants.MAPWIDTH, EntityConstants.MAPHEIGHT, environments); + final ArrayList> grids = mapfact.getGrids(EntityConstants.MAPWIDTH, + EntityConstants.MAPHEIGHT, cores); + final Maps gameMap = new Maps(grids); + // initialize player and their info. + final PlayerAttributes playerAttributes = new PlayerAttributes(); + final PlayerInfo playerInfo = new PlayerInfo("Currentplayer"); + final PlayerLocation playerLocation = new PlayerLocation(); + final Inventory playerInventory = new Inventory(); + final Location currentlocation = grids.get(playerLocation.getYcoordinate()) + .get(playerLocation.getXcoordinate()); + // initialize events and horde + final EventAmbush ambush = new EventAmbush(); + final EventFlood flood = new EventFlood(); + final EventBlizzard blizzard = new EventBlizzard(); + final EventSurvivorJoins survivor = new EventSurvivorJoins(); + final EventTraderEncounter traderEncounter = new EventTraderEncounter(); + final Horde horde = new Horde(); + // initialize ingame in memory database/dataaccess. + final InMemoryUnifiedDataAccess gamedatabase = + new InMemoryUnifiedDataAccess(playerAttributes, playerInventory, new ArrayList<>(), currentlocation, + horde, playerInfo, playerLocation, gameMap, ambush, blizzard, flood, survivor, traderEncounter); + // initialize each gameing view. + final CharacterCreationView attributeview = new CharacterCreationView(); + final GameView gameView = new GameView(); + final EventView eventView = new EventView(); + final GameOverView gameOverView = new GameOverView(); + final InformationView informationView = new InformationView("Daily log"); + // initialize nevagation manager + final NavigationManager navigationManager = + new NavigationManager(mainView, attributeview, gameView, eventView, informationView, gameOverView); + // initialize each usecase. + // Nevagate to allowcate page usecase. + final NevagateAllowcatePresenter nevagateAllowcatePresenter = new NevagateAllowcatePresenter(navigationManager); + final NevagateAllowcateInteractor nevagateAllowcateInteractor = new NevagateAllowcateInteractor( + gamedatabase, nevagateAllowcatePresenter); + final NevagateAllowcateController nevagateAllowcateController = new NevagateAllowcateController( + nevagateAllowcateInteractor); + + final ChatGptService chatGptService = new ChatGptService(); + final ChatGptResponseParser responseParser = new ChatGptResponseParser(); + // Allowcate points ussecase. + final AllowcatePresenter allowcatePresenter = new AllowcatePresenter(attributeview, navigationManager); + final AllowcateInteractor allowcateInteractor = new AllowcateInteractor(gamedatabase, allowcatePresenter); + final AllowcateController allowcateController = new AllowcateController(allowcateInteractor); + // Nevagate Main usecase. + final NevagateMainPresenter nevagateMainPresenter = new NevagateMainPresenter(navigationManager); + final NavigateMainInteractor nevagateMainInteractor = + new NavigateMainInteractor(gamedatabase, nevagateMainPresenter); + final NevagateMainController nevagateMainController = new NevagateMainController(nevagateMainInteractor); + // Fetch Usecase + final FetchPresenter fetchPresenter = new FetchPresenter(gameView); + final FetchInteractor fetchInteractor = new FetchInteractor(gamedatabase, fetchPresenter); + final FetchController fetchController = new FetchController(fetchInteractor); + // Broadcast Usecase + final BroadcastPresenter broadcastPresenter = new BroadcastPresenter(gameView); + final BroadcastInteractor broadcastInteractor = new BroadcastInteractor(gamedatabase, broadcastPresenter); + final BroadcastController broadcastController = new BroadcastController(broadcastInteractor); + // Place description usecase + final PlaceDescriptionPresenter placeDescriptionPresenter = new PlaceDescriptionPresenter(gameView); + final PlaceDescriptionInteractor placeDescriptionInteractor = + new PlaceDescriptionInteractor(gamedatabase, placeDescriptionPresenter); + final PlaceDescriptionController placeDescriptionController = + new PlaceDescriptionController(placeDescriptionInteractor); + + // gather description usecase + final DailyGatherPresenter dailyGatherPresenter = new DailyGatherPresenter(gameView); + final GatherInteractor gatherInteractor = new GatherInteractor(gamedatabase, dailyGatherPresenter); + final DailyGatherController dailyGatherController = new DailyGatherController(gatherInteractor); + + // Move usecase. + final DailyMovePresenter dailyMovePresenter = new DailyMovePresenter(gameView); + final MoveInteractor moveInteractor = new MoveInteractor(gamedatabase, dailyMovePresenter); + final DailyMoveController dailyMoveController = new DailyMoveController(moveInteractor); + + // Nevagate Event usecase + final NevagateEventPresenter nevagateEventPresenter = new NevagateEventPresenter(navigationManager, gameView); + final NevagateEventInteractor nevagateEventInteractor = + new NevagateEventInteractor(gamedatabase, nevagateEventPresenter); + final NevagateEventController nevagateEventController = new NevagateEventController(nevagateEventInteractor); + + // Event Initialize usecase + final EventInitializerPresenter eventInitializerPresenter = new EventInitializerPresenter(eventView); + final EventInitializeInteractor eventInitializeInteractor = + new EventInitializeInteractor(gamedatabase, eventInitializerPresenter); + final EventInitializerController eventInitializerController = + new EventInitializerController(eventInitializeInteractor); + + // Event Decide usecase + final EventDecidePresenter eventDecidePresenter = new EventDecidePresenter(gameView); + final DecideEventInteractor decideEventInteractor = + new DecideEventInteractor(gamedatabase, eventDecidePresenter); + final EventDecideController eventDecideController = new EventDecideController(decideEventInteractor); + + // Event Respond usecase ambush + final AmbushResponsePresenter ambushresponsePresenter = new AmbushResponsePresenter(eventView); + final AmbushEventInteractor ambushEventInteractor = + new AmbushEventInteractor(gamedatabase, ambushresponsePresenter, chatGptService); + final AmbushResponseController ambushResponseController = new AmbushResponseController(ambushEventInteractor); + + // Event Respond usecase blizzard + final BlizzardResponsePresenter blizzardResponsePresenter = new BlizzardResponsePresenter(eventView); + final BlizzardEventInteractor blizzardEventInteractor = + new BlizzardEventInteractor(gamedatabase, blizzardResponsePresenter, chatGptService); + final BlizzardResponseController blizzardResponseController = + new BlizzardResponseController(blizzardEventInteractor); + + // Event Respond usecase flood + final FloodResponsePresenter floodResponsePresenter = new FloodResponsePresenter(eventView); + final FloodEventInteractor floodEventInteractor = + new FloodEventInteractor(gamedatabase, floodResponsePresenter, chatGptService); + final FloodResponseController floodResponseController = new FloodResponseController(floodEventInteractor); + + // Event Respond usecase survivor + final SurvivorResponsePresenter survivorResponsePresenter = new SurvivorResponsePresenter(eventView); + final SurvivorEventInteractor survivorEventInteractor = + new SurvivorEventInteractor(gamedatabase, survivorResponsePresenter, chatGptService); + final SurvivorResponseController survivorResponseController = + new SurvivorResponseController(survivorEventInteractor); + + // Event Respond usecase trader + final TraderResponsePresenter traderResponsePresenter = new TraderResponsePresenter(eventView); + final TraderEventInteractor traderEventInteractor = + new TraderEventInteractor(gamedatabase, traderResponsePresenter, chatGptService); + final TraderResponseController traderResponseController = new TraderResponseController(traderEventInteractor); + + // Initialize Event manager + final EventManager eventManager = new EventManager(ambushResponseController, blizzardResponseController, + floodResponseController, survivorResponseController, traderResponseController); + + // Fetch Event usecase + final FetchEventPresenter fetchEventPresenter = new FetchEventPresenter(eventView); + final CurrentEventInteractor currentEventInteractor = + new CurrentEventInteractor(gamedatabase, fetchEventPresenter); + final FetchEventController fetchEventController = new FetchEventController(currentEventInteractor); + + // Nevagate Game usecase + final NevagateGamePresenter nevagateGamePresenter = new NevagateGamePresenter(navigationManager); + final NevagateGameInteractor nevagateGameInteractor = + new NevagateGameInteractor(gamedatabase, nevagateGamePresenter); + final NevagateGameController nevagateGameController = new NevagateGameController(nevagateGameInteractor); + + // Newday Game usecase + final NewdayPresenter newdayPresenter = new NewdayPresenter(gameView); + final NewdayInteractor newdayInteractor = new NewdayInteractor(gamedatabase, newdayPresenter); + final NewdayController newdayController = new NewdayController(newdayInteractor); + + // Minimap update usecase + final MinimapPresenter minimapPresenter = new MinimapPresenter(gameView); + final MinimapInteractor minimapInteractor = new MinimapInteractor(gamedatabase, minimapPresenter); + final MinimapController minimapController = new MinimapController(minimapInteractor); + + // Lose detect usecase + final LosePresenter losePresenter = new LosePresenter(gameOverView, navigationManager, gameView); + final LoseInteractor loseInteractor = new LoseInteractor(gamedatabase, losePresenter); + final LoseController loseController = new LoseController(loseInteractor); + + // End process horde usecase + final HordePresenter hordePresenter = new HordePresenter(gameOverView, navigationManager, gameView); + final HordeInteractor hordeInteractor = new HordeInteractor(gamedatabase, hordePresenter); + final HordeController hordeController = new HordeController(hordeInteractor); + + // Navigate Game Over view usecase + final NevagateGameOverPresenter nevagateGameOverPresenter = + new NevagateGameOverPresenter(navigationManager); + final NevagateGameOverInteractor nevagateGameOverInteractor = + new NevagateGameOverInteractor(gamedatabase, nevagateGameOverPresenter); + final NevagateGameOverController nevagateGameOverController = + new NevagateGameOverController(nevagateGameOverInteractor); + + + // Example of how to use the endGame method + // endGame("path/to/rankings.json", "Player1", score, daysSurvived, won); + gameView.setController(fetchController, broadcastController, + placeDescriptionController, dailyGatherController, dailyMoveController, + nevagateEventController, eventDecideController, newdayController, minimapController, loseController, + hordeController, nevagateGameOverController); + attributeview.setAllowcateController(allowcateController, nevagateMainController); + eventView.setController(eventInitializerController, fetchEventController, nevagateGameController); + eventView.setManager(eventManager); + gameOverView.setController(nevagateMainController); + gameOverView.setNavigationManager(navigationManagerJson); + gameOverView.setRestartGameController(this.restartGameController); + mainView.setNevagateAllowcateController(nevagateAllowcateController); + } + + /** + * Entry point to initialize the application. + * + * @param args Command-line arguments. + */ + public static void main(String[] args) { + try { + new JsonApplication("PlayerFile", "PlayerFile", "RankingFile"); + } + catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/app/MainNoteApplication.java b/src/main/java/app/MainNoteApplication.java deleted file mode 100644 index c37860156..000000000 --- a/src/main/java/app/MainNoteApplication.java +++ /dev/null @@ -1,56 +0,0 @@ -package app; - -import data_access.DBNoteDataAccessObject; -import use_case.note.NoteDataAccessInterface; - -/** - * An application where we can view and add to a note stored by a user. - *

- * This is a minimal example of using the password-protected user API from lab 5, - * but demonstrating the endpoint allowing you to store an arbitrary JSON object. - * This functionality could be used in any project where your team wants to persist - * data which is then accessible across devices.

- *

The code is intentionally somewhat incomplete to leave work to be done if your - * team were to choose to work on a project which would require similar functionality. - * For example, we have intentionally not created a full "Note" entity here, but - * rather just represented a note as a string. - *

- * The ViewManager code has also been removed, since this minimal program only requires a single - * view. Your team may wish to bring back the ViewManager or make your own implementation of supporting - * switching between views depending on your project. - */ -public class MainNoteApplication { - - /** - * The main entry point of the application. - *

- * The program will show you the note currently saved in the system. - * You are able to edit it and then save it to the system. You can refresh - * to update the note to reflect what was saved most recently. This - * uses the API from lab, so there is one database storing the note, - * which means that if anyone updates the note, that is what you will - * see when you refresh. - *

- * You can generalize the code to allow you to - * specify which "user" to save the note for, which will allow your team - * to store information specific to your team which is password-protected. - * The username and password used in this application are currently for - * user jonathan_calver2, but you can change that. As you did in lab 3, - * you will likely want to store password information locally rather than - * in your repo. Or you can require the user to enter their credentials - * in your application; it just depends on what your program's main - * functionality. - *

- * @param args commandline arguments are ignored - */ - public static void main(String[] args) { - - // create the data access and inject it into our builder! - final NoteDataAccessInterface noteDataAccess = new DBNoteDataAccessObject(); - - final NoteAppBuilder builder = new NoteAppBuilder(); - builder.addNoteDAO(noteDataAccess) - .addNoteView() - .addNoteUseCase().build().setVisible(true); - } -} diff --git a/src/main/java/app/NoteAppBuilder.java b/src/main/java/app/NoteAppBuilder.java deleted file mode 100644 index a68cb9ad6..000000000 --- a/src/main/java/app/NoteAppBuilder.java +++ /dev/null @@ -1,83 +0,0 @@ -package app; - -import javax.swing.JFrame; -import javax.swing.WindowConstants; - -import interface_adapter.note.NoteController; -import interface_adapter.note.NotePresenter; -import interface_adapter.note.NoteViewModel; -import use_case.note.NoteDataAccessInterface; -import use_case.note.NoteInteractor; -import use_case.note.NoteOutputBoundary; -import view.NoteView; - -/** - * Builder for the Note Application. - */ -public class NoteAppBuilder { - public static final int HEIGHT = 300; - public static final int WIDTH = 400; - private NoteDataAccessInterface noteDAO; - private NoteViewModel noteViewModel = new NoteViewModel(); - private NoteView noteView; - private NoteInteractor noteInteractor; - - /** - * Sets the NoteDAO to be used in this application. - * @param noteDataAccess the DAO to use - * @return this builder - */ - public NoteAppBuilder addNoteDAO(NoteDataAccessInterface noteDataAccess) { - noteDAO = noteDataAccess; - return this; - } - - /** - * Creates the objects for the Note Use Case and connects the NoteView to its - * controller. - *

This method must be called after addNoteView!

- * @return this builder - * @throws RuntimeException if this method is called before addNoteView - */ - public NoteAppBuilder addNoteUseCase() { - final NoteOutputBoundary noteOutputBoundary = new NotePresenter(noteViewModel); - noteInteractor = new NoteInteractor( - noteDAO, noteOutputBoundary); - - final NoteController controller = new NoteController(noteInteractor); - if (noteView == null) { - throw new RuntimeException("addNoteView must be called before addNoteUseCase"); - } - noteView.setNoteController(controller); - return this; - } - - /** - * Creates the NoteView and underlying NoteViewModel. - * @return this builder - */ - public NoteAppBuilder addNoteView() { - noteViewModel = new NoteViewModel(); - noteView = new NoteView(noteViewModel); - return this; - } - - /** - * Builds the application. - * @return the JFrame for the application - */ - public JFrame build() { - final JFrame frame = new JFrame(); - frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - frame.setTitle("Note Application"); - frame.setSize(WIDTH, HEIGHT); - - frame.add(noteView); - - // refresh so that the note will be visible when we start the program - noteInteractor.executeRefresh(); - - return frame; - - } -} diff --git a/src/main/java/app/RankingApplication.java b/src/main/java/app/RankingApplication.java new file mode 100644 index 000000000..b8321d63b --- /dev/null +++ b/src/main/java/app/RankingApplication.java @@ -0,0 +1,43 @@ +package app; + +import java.io.IOException; + +import frameworks.database.JsonRankingDataAccess; +import interface_adapters.rankinglist.RankingController; +import interface_adapters.rankinglist.RankingInterface; +import interface_adapters.rankinglist.RankingPresenter; +import usecases.accountranking.RankingInputBoundary; +import usecases.accountranking.RankingInteractor; +import usecases.accountranking.RankingOutputBoundary; + +/** + * Application class for Ranking Use Case. + * Responsible for assembling and initializing the components for the ranking feature. + */ +public class RankingApplication { + private static String filePath = "RankingFile"; + + /** + * Initializes and assembles the components for the Ranking use case. + * + * @param rankingView The interface representing the view layer of the ranking feature. + * @return A RankingController instance that is connected to the use case. + * @throws IOException if there is an issue accessing ranking data files. + */ + public static RankingController initializeRanking(RankingInterface rankingView) throws IOException { + // Data access layer + final JsonRankingDataAccess rankingDataAccess = new JsonRankingDataAccess(filePath); + + // Presenter + final RankingPresenter rankingPresenter = new RankingPresenter(rankingView); + + // Output boundary is the presenter + final RankingOutputBoundary outputBoundary = rankingPresenter; + + // Use case interactor + final RankingInputBoundary rankingInteractor = new RankingInteractor(rankingDataAccess, outputBoundary); + + // Controller + return new RankingController(rankingInteractor); + } +} diff --git a/src/main/java/app/RestartGameController.java b/src/main/java/app/RestartGameController.java new file mode 100644 index 000000000..8ec747e86 --- /dev/null +++ b/src/main/java/app/RestartGameController.java @@ -0,0 +1,14 @@ +package app; + +public class RestartGameController { + + private final JsonApplication jsonApplication; + + public RestartGameController(JsonApplication jsonApplication) { + this.jsonApplication = jsonApplication; + } + + public void resetGame() { + jsonApplication.startnewgame(); + } +} diff --git a/src/main/java/data_access/DBNoteDataAccessObject.java b/src/main/java/data_access/DBNoteDataAccessObject.java deleted file mode 100644 index dadb0cab0..000000000 --- a/src/main/java/data_access/DBNoteDataAccessObject.java +++ /dev/null @@ -1,107 +0,0 @@ -package data_access; - -import java.io.IOException; - -import org.json.JSONException; -import org.json.JSONObject; - -import entity.User; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import use_case.note.DataAccessException; -import use_case.note.NoteDataAccessInterface; - -/** - * The DAO for accessing notes stored in the database. - *

This class demonstrates how your group can use the password-protected user - * endpoints of the API used in lab 5 to store persistent data in your program. - *

- *

You can also refer to the lab 5 code for signing up a new user and other use cases. - *

- * See - * - * the documentation - * of the API for more details. - */ -public class DBNoteDataAccessObject implements NoteDataAccessInterface { - private static final int SUCCESS_CODE = 200; - private static final int CREDENTIAL_ERROR = 401; - private static final String CONTENT_TYPE_LABEL = "Content-Type"; - private static final String CONTENT_TYPE_JSON = "application/json"; - private static final String STATUS_CODE_LABEL = "status_code"; - private static final String USERNAME = "username"; - private static final String PASSWORD = "password"; - private static final String MESSAGE = "message"; - - @Override - public String saveNote(User user, String note) throws DataAccessException { - final OkHttpClient client = new OkHttpClient().newBuilder() - .build(); - - // POST METHOD - final MediaType mediaType = MediaType.parse(CONTENT_TYPE_JSON); - final JSONObject requestBody = new JSONObject(); - requestBody.put(USERNAME, user.getName()); - requestBody.put(PASSWORD, user.getPassword()); - final JSONObject extra = new JSONObject(); - extra.put("note", note); - requestBody.put("info", extra); - final RequestBody body = RequestBody.create(requestBody.toString(), mediaType); - final Request request = new Request.Builder() - .url("http://vm003.teach.cs.toronto.edu:20112/modifyUserInfo") - .method("PUT", body) - .addHeader(CONTENT_TYPE_LABEL, CONTENT_TYPE_JSON) - .build(); - try { - final Response response = client.newCall(request).execute(); - - final JSONObject responseBody = new JSONObject(response.body().string()); - - if (responseBody.getInt(STATUS_CODE_LABEL) == SUCCESS_CODE) { - return loadNote(user); - } - else if (responseBody.getInt(STATUS_CODE_LABEL) == CREDENTIAL_ERROR) { - throw new DataAccessException("message could not be found or password was incorrect"); - } - else { - throw new DataAccessException("database error: " + responseBody.getString(MESSAGE)); - } - } - catch (IOException | JSONException ex) { - throw new DataAccessException(ex.getMessage()); - } - } - - @Override - public String loadNote(User user) throws DataAccessException { - // Make an API call to get the user object. - final String username = user.getName(); - final OkHttpClient client = new OkHttpClient().newBuilder().build(); - final Request request = new Request.Builder() - .url(String.format("http://vm003.teach.cs.toronto.edu:20112/user?username=%s", username)) - .addHeader("Content-Type", CONTENT_TYPE_JSON) - .build(); - try { - final Response response = client.newCall(request).execute(); - - final JSONObject responseBody = new JSONObject(response.body().string()); - - if (responseBody.getInt(STATUS_CODE_LABEL) == SUCCESS_CODE) { - final JSONObject userJSONObject = responseBody.getJSONObject("user"); - final JSONObject data = userJSONObject.getJSONObject("info"); - return data.getString("note"); - } - else { - throw new DataAccessException(responseBody.getString(MESSAGE)); - } - } - catch (IOException | JSONException ex) { - throw new RuntimeException(ex); - } - } -} diff --git a/src/main/java/entities/EntityConstants.java b/src/main/java/entities/EntityConstants.java new file mode 100644 index 000000000..866da2ac7 --- /dev/null +++ b/src/main/java/entities/EntityConstants.java @@ -0,0 +1,154 @@ +package entities; + +/** + * Constants used in this program. + * Notice, by changing these constant, we can alter game dramatically. + * This could be used to achieve game balance as well as for difficulty setting implementation. + */ +public class EntityConstants { + public static final int NEWDAYSCORE = 100; + public static final int STARTERFOOD = 100; + public static final int STARTERWATER = 100; + public static final int STARTWEAPON = 5; + public static final int STARTERPEOPLE = 10; + public static final int STARTERACTIONPOINT = 3; + public static final int BROADCASTGAIN = 7; + public static final double SOCIALIMPACTBROADCAST = 0.05; + public static final int STARTERATRIBUTEPOINT = 20; + public static final double STARTERRESOURCESCALAR = 1; + public static final double RESOUCEDECREASERATIO = 0.7; + public static final double DEFAULTTEMP = 25; + public static final int CORERANGE = 16; + public static final double DEFAULTTHREAT = 1; + public static final double MAXTEMPDIFF = 50; + public static final double MAXTHREATDIFF = 0.5; + + // Map information and calculation scalar settings. + public static final String ICELAND = "Iceland"; + public static final int ICELANDCOLD = 0; + public static final int ICELANDEXTREMECOLD = -20; + public static final String DESERT = "Desert"; + public static final int DESERTHOTDEGREE = 35; + public static final int DESERTUNBAREABLEDEGREE = 65; + public static final String FOREST = "Forest"; + public static final double FORESTRICH = 1.25; + public static final double FORESTEXTREMERICH = 1.75; + public static final String CITY = "City"; + public static final double CITYDANGER = 1.25; + public static final double CITYEXTREMEDANGER = 1.75; + public static final String PLAIN = "Plain"; + + // Name we gonna use. + public static final String SOCIAL = "Social"; + public static final String LUCK = "Luck"; + public static final String MOBILIZATION = "Mobilization"; + public static final String THRIFT = "Thrift"; + public static final String GENERALSHIP = "GeneralShip"; + + public static final int MAPHEIGHT = 100; + public static final int MAPWIDTH = 100; + public static final int SPAWNXCOOR = MAPWIDTH / 2; + public static final int SPAWNYCOOR = MAPHEIGHT / 2; + public static final int BIOMERADIUS = 16; + public static final int MINIMAPRADIUS = 4; + public static final int FIRSTCHOICE = 1; + public static final int SECONDCHOICE = 2; + public static final int THIRDCHOICE = 3; + public static final int FOURTHCHOICE = 4; + + // Base event probability (probability at default at start). + public static final double COMMONEVENTBASEPROB = 0.1; + public static final double RAREEVENTBASEPROB = 0.05; + + // Horde starter setting. + public static final int STARTERHORDEMAGNITUDE = 3000; + public static final int HORDEMAGNITUDELARGE = 4000; + public static final int HORDEMAGNITUDEEXTREME = 5000; + public static final int STARTERHORDEDURATION = 10; + public static final int HORDEDURATIONLONG = 8; + public static final int HORDEDURATIONSHORT = 6; + public static final double TEMPIMPACTHORDE = 0.5; + + // Player attribute impacts. + public static final int MOBILIZATIONIMPACTSPEED = 10; + public static final double THRIFTIMPACTRESOURCELOSS = 0.03; + + // Newday resource loss module + public static final double PEOPLELOSSPERFOOD = 1; + public static final double PEOPLELOSSPERWATER = 1; + public static final double PEOPLEBASEDEATHRATE = 0.05; + + // Newday resource gain module + public static final double PEOPLEGAINPERFOOD = 0.4; + public static final double PEOPLEGAINPERWEAPON = 0.04; + public static final double PEOPLEGAINPERWATER = 0.4; + public static final double PEOPLEBASEJOINRATE = 0.04; + public static final double WEAPONBASELOSERATE = 0.04; + + // Directions. + public static final String UP = "up"; + public static final String DOWN = "down"; + public static final String LEFT = "left"; + public static final String RIGHT = "right"; + + // Firepower calculation settings. + public static final int UNARMPEOPLEPOWER = 1; + public static final int ARMEDPEOPLEPOWER = 5; + + // Ambush constants. + public static final int AMBUSHPOWER = 35; + public static final int AMBUSHNEGOTIATE = 4; + public static final int AMBUSHFIGHTSUCCESSRESOURCEFOOD = 15; + public static final int AMBUSHFIGHTSUCCESSRESOURCEWATER = 15; + public static final int AMBUSHFIGHTSUCCESSRESOURCEPEOPLE = 0; + public static final int AMBUSHFIGHTSUCCESSRESOURCEWEAPON = 4; + public static final int AMBUSHFAILRESOURCEFOOD = -30; + public static final int AMBUSHFAILRESOURCEWATER = -30; + public static final int AMBUSHFAILRESOURCEPEOPLE = -5; + public static final int AMBUSHFAILRESOURCEWEAPON = -10; + // for event ambush, resource lost for failed. + // for any general escape choice, the distance move randomly at max. + public static final int LENGTHMESSAGECOMMA = 17; + + // Flood event constants + public static final int FLOODRESOURCELOSSFOOD = -10; + public static final int FLOODRESOURCELOSSSECURE = -15; + public static final int FLOODRESOURCELOSSHIGH = -20; + + public static final int FLOODPEOPLELOSSLOW = -1; + public static final int FLOODPEOPLELOSSMODERATE = -3; + public static final int FLOODPEOPLELOSSHIGH = -5; + + // Blizzard constants. + public static final int BLIZZARDRESOURCELOSSFOOD = -15; + public static final int BLIZZARDRESOURCELOSSWATER = -15; + + // Add these constants under the event-specific section + // TraderEncounter thresholds + public static final int TRADERNEGOTIATE = 5; + public static final int TRADERROBBERYPOWER = 30; + + // TraderEncounter resource changes + public static final int TRADERTRADEGAINFOOD = 15; + public static final int TRADERTRADEGAINWATER = 10; + public static final int TRADERTRADEFAILLOSSFOOD = -5; + public static final int TRADERTRADEFAILLOSSWATER = -3; + + public static final int TRADERROBBERYGAINFOOD = 20; + public static final int TRADERROBBERYGAINSUPPLIES = 5; + public static final int TRADERROBBERYFAILLOSSFOOD = -10; + public static final int TRADERROBBERYFAILLOSSPEOPLE = -2; + + public static final int TRADERIGNORELOSS = 0; + public static final int MAXNUMDAY = 60; + + // Survivor constants + public static final int SURVIVORACCEPTPEOPLEGAIN = 5; + public static final int SURVIVORROBBERYPOWER = 20; + public static final int SURVIVORROBBERYGAINFOOD = 10; + public static final int SURVIVORROBBERYGAINSUPPLIES = 5; + public static final int SURVIVORROBBERYFAILLOSSFOOD = -10; + public static final int SURVIVORROBBERYFAILLOSSPEOPLE = -2; + + public static final String NEWLINE = "\n"; +} diff --git a/src/main/java/entities/Event.java b/src/main/java/entities/Event.java new file mode 100644 index 000000000..96a7e8065 --- /dev/null +++ b/src/main/java/entities/Event.java @@ -0,0 +1,48 @@ +package entities; + +import java.util.ArrayList; +import java.util.Map; + +/** + * The random events of the game, this is an interface, all events should implement this. + */ +public interface Event { + + /** + * Method for getting the probability. + * @return probability of this event occurring in the given location, time, etc. + */ + double getprobability(); + + /** + * Method for setting the probability of this event. + * @param probability probability of this event, + */ + void setprobability(double probability); + + /** + * Getter method for the choices of the event, in map of int, string. String is the "facial" representation + * of the event, but actually for player's input, and response determine step, we use the int. + * @return Choices in map of int string. + */ + Map getchoices(); + + /** + * Getter method for the brief description of the event. + * @return brief description of this event. + */ + String getdescription(); + + /** + * Return of this is an positive event, we need this to determine how luck affect it's probability. + * @return Return positive or not. + */ + boolean getispositive(); + + /** + * Return the only possible locations for this event to happen. + * @return return the occuring locations. + */ + ArrayList getOccuringlocation(); + +} diff --git a/src/main/java/entities/EventAmbush.java b/src/main/java/entities/EventAmbush.java new file mode 100644 index 000000000..15f7b5f93 --- /dev/null +++ b/src/main/java/entities/EventAmbush.java @@ -0,0 +1,106 @@ +package entities; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** + * Event of ambush, player decide they want to fight back, pay, or negotiate. Different actions have different + * results as well as result descriptions. This entity is designed to remain simple, avoiding coupling and + * complex logic, which is handled in the use case interactor. + */ +public class EventAmbush implements Event { + + private final Boolean isPositive; + private final ArrayList occuringlocation; + private final String description; + private final Map choices; + private double probability; + private final String fightoutcomesuccess; + private final String fightoutcomefailed; + private final String payoutcome; + private final String negotiatesuccessoutcome; + private final String negotiatefailedoutcome; + + public EventAmbush() { + this.isPositive = false; + this.occuringlocation = new ArrayList<>(); + occuringlocation.add(EntityConstants.PLAIN); + occuringlocation.add(EntityConstants.ICELAND); + occuringlocation.add(EntityConstants.DESERT); + occuringlocation.add(EntityConstants.CITY); + occuringlocation.add(EntityConstants.FOREST); + this.description = "Your group is ambushed by a small band of desperate bandits demanding your " + + "food supplies. Their ragged appearance suggests they're struggling to survive. What will you do?"; + this.choices = new HashMap<>(); + choices.put(EntityConstants.FIRSTCHOICE, "Fight back"); + choices.put(EntityConstants.SECONDCHOICE, "Pay the bandits"); + choices.put(EntityConstants.THIRDCHOICE, "Negotiate"); + this.probability = EntityConstants.COMMONEVENTBASEPROB; + this.fightoutcomesuccess = "You successfully beat the bandits and secured their supplies."; + this.fightoutcomefailed = "You fought hard but were overpowered, losing some supplies."; + this.payoutcome = "You handed over some of your food to avoid conflict with the bandits."; + this.negotiatesuccessoutcome = "You successfully negotiated with the bandits, convincing" + + " them to leave peacefully."; + this.negotiatefailedoutcome = "Your negotiation failed, and the bandits" + + " took a portion of your supplies by force."; + } + + @Override + public double getprobability() { + return this.probability; + } + + @Override + public void setprobability(double prob) { + this.probability = prob; + } + + @Override + public Map getchoices() { + return this.choices; + } + + @Override + public String getdescription() { + return this.description; + } + + @Override + public boolean getispositive() { + return isPositive; + } + + @Override + public ArrayList getOccuringlocation() { + return occuringlocation; + } + + public String getFightoutcomesuccess() { + return fightoutcomesuccess; + } + + public String getFightoutcomefailed() { + return fightoutcomefailed; + } + + public String getPayoutcome() { + return payoutcome; + } + + public String getNegotiatesuccessoutcome() { + return negotiatesuccessoutcome; + } + + public String getNegotiatefailedoutcome() { + return negotiatefailedoutcome; + } + + /** + * Return the name of this event. + * @return the event name. + */ + public String toString() { + return "Ambush"; + } +} diff --git a/src/main/java/entities/EventBlizzard.java b/src/main/java/entities/EventBlizzard.java new file mode 100644 index 000000000..03a6a094e --- /dev/null +++ b/src/main/java/entities/EventBlizzard.java @@ -0,0 +1,94 @@ +package entities; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** + * Event of a Blizzard. Represents a harsh blizzard that impacts resources and morale. + */ +public class EventBlizzard implements Event { + + private final Boolean isPositive; + private final ArrayList occurringLocation; + private final String description; + private final Map choices; + private double probability; + + private final String fightOutcome; + private final String negotiateOutcome; + private final String fleeOutcome; + + public EventBlizzard() { + this.isPositive = false; + this.occurringLocation = new ArrayList<>(); + occurringLocation.add(EntityConstants.ICELAND); + + this.description = "A harsh blizzard strikes, blanketing the area in ice and snow. The biting cold " + + "and lack of visibility make survival challenging. What will you do?"; + this.choices = new HashMap<>(); + this.choices.put(EntityConstants.FIRSTCHOICE, "Secure shelter"); + this.choices.put(EntityConstants.SECONDCHOICE, "Prepare supplies"); + this.choices.put(EntityConstants.THIRDCHOICE, "Do nothing"); + + this.probability = EntityConstants.RAREEVENTBASEPROB; + + this.fightOutcome = "You secured shelter from the blizzard, minimizing resource loss."; + this.negotiateOutcome = "You prepared supplies, but the blizzard still consumed some resources."; + this.fleeOutcome = "You did nothing, and the blizzard wreaked havoc on your group."; + } + + @Override + public double getprobability() { + return this.probability; + } + + @Override + public void setprobability(double prob) { + this.probability = prob; + } + + @Override + public Map getchoices() { + return this.choices; + } + + @Override + public String getdescription() { + return this.description; + } + + @Override + public boolean getispositive() { + return isPositive; + } + + @Override + public ArrayList getOccuringlocation() { + return occurringLocation; + } + + public ArrayList getOccurringLocation() { + return occurringLocation; + } + + public String getFightOutcome() { + return fightOutcome; + } + + public String getNegotiateOutcome() { + return negotiateOutcome; + } + + public String getFleeOutcome() { + return fleeOutcome; + } + + /** + * Return the name of this event. + * @return the event name. + */ + public String toString() { + return "Blizzard"; + } +} diff --git a/src/main/java/entities/EventFlood.java b/src/main/java/entities/EventFlood.java new file mode 100644 index 000000000..51d133fa0 --- /dev/null +++ b/src/main/java/entities/EventFlood.java @@ -0,0 +1,91 @@ +package entities; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** + * Event of a flood. This is a negative event that occurs in Plains, Woods, or Cities. + * The flood causes a loss of resources or requires immediate action to mitigate damages. + */ +public class EventFlood implements Event { + + private final Boolean isPositive; + private final ArrayList occuringlocation; + private final String description; + private final Map choices; + private double probability; + private final String evacuateOutcome; + private final String secureSuppliesOutcome; + private final String doNothingOutcome; + + public EventFlood() { + this.isPositive = false; + this.occuringlocation = new ArrayList<>(); + occuringlocation.add(EntityConstants.PLAIN); + occuringlocation.add(EntityConstants.FOREST); + occuringlocation.add(EntityConstants.CITY); + + this.description = "Heavy rains have caused nearby rivers to overflow, threatening your group with a flood. " + + "You must act quickly to avoid losing supplies and people. What will you do?"; + this.choices = new HashMap<>(); + choices.put(EntityConstants.FIRSTCHOICE, "Evacuate"); + choices.put(EntityConstants.SECONDCHOICE, "Secure supplies"); + choices.put(EntityConstants.THIRDCHOICE, "hope subsides"); + + this.probability = EntityConstants.RAREEVENTBASEPROB; + this.evacuateOutcome = "You successfully evacuated, saving most of your group but losing some supplies."; + this.secureSuppliesOutcome = "You secured your supplies but lost time and some members to the flood."; + this.doNothingOutcome = "The flood devastated your group, causing heavy losses in supplies and morale."; + } + + @Override + public double getprobability() { + return this.probability; + } + + @Override + public void setprobability(double prob) { + this.probability = prob; + } + + @Override + public Map getchoices() { + return this.choices; + } + + @Override + public String getdescription() { + return this.description; + } + + @Override + public boolean getispositive() { + return isPositive; + } + + @Override + public ArrayList getOccuringlocation() { + return occuringlocation; + } + + public String getEvacuateOutcome() { + return evacuateOutcome; + } + + public String getSecureSuppliesOutcome() { + return secureSuppliesOutcome; + } + + public String getDoNothingOutcome() { + return doNothingOutcome; + } + + /** + * Return the name of this event. + * @return the event name. + */ + public String toString() { + return "Flood"; + } +} diff --git a/src/main/java/entities/EventSurvivorJoins.java b/src/main/java/entities/EventSurvivorJoins.java new file mode 100644 index 000000000..cb92e8f15 --- /dev/null +++ b/src/main/java/entities/EventSurvivorJoins.java @@ -0,0 +1,99 @@ +package entities; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** + * Event of a group of survivors wanting to join the player. The player can choose to accept, reject, or negotiate terms + * for joining. Different actions have different outcomes, and descriptions for each are provided. This class avoids + * coupling logic and leaves complex calculations to the use case interactor. + */ + +public class EventSurvivorJoins implements Event { + + private final Boolean isPositive; + private final ArrayList occuringlocation; + private final String description; + private final Map choices; + private double probability; + private final String acceptoutcome; + private final String rejectoutcome; + private final String roboutcomesuccess; + private final String roboutcomefail; + + public EventSurvivorJoins() { + this.isPositive = true; + this.occuringlocation = new ArrayList<>(); + occuringlocation.add(EntityConstants.PLAIN); + occuringlocation.add(EntityConstants.FOREST); + occuringlocation.add(EntityConstants.CITY); + this.description = "You encounter a small group of survivors who ask to join your group. They appear skilled " + + "but wary. What will you do?"; + this.choices = new HashMap<>(); + choices.put(EntityConstants.FIRSTCHOICE, "Accept them"); + choices.put(EntityConstants.SECONDCHOICE, "reject them"); + choices.put(EntityConstants.THIRDCHOICE, "rob them..?"); + this.probability = EntityConstants.COMMONEVENTBASEPROB; + this.acceptoutcome = "You've accept them into the group"; + this.rejectoutcome = "You've reject them into the group"; + this.roboutcomesuccess = "You've robbed the survivor, they dear not to fight back as your group overpowered" + + "them, taking their supplies and leaving them helpless."; + this.roboutcomefail = "The robbery failed as they escaped."; + + } + + @Override + public double getprobability() { + return this.probability; + } + + @Override + public void setprobability(double prob) { + this.probability = prob; + } + + @Override + public Map getchoices() { + return this.choices; + } + + @Override + public String getdescription() { + return this.description; + } + + @Override + public boolean getispositive() { + return isPositive; + } + + @Override + public ArrayList getOccuringlocation() { + return occuringlocation; + } + + public String getAcceptoutcome() { + return acceptoutcome; + } + + public String getRejectoutcome() { + return rejectoutcome; + } + + public String getRoboutcomesuccess() { + return roboutcomesuccess; + } + + public String getRoboutcomefail() { + return roboutcomefail; + } + + /** + * Return the name of this event. + * @return the event name. + */ + public String toString() { + return "SurvivorsJoins"; + } +} diff --git a/src/main/java/entities/EventTraderEncounter.java b/src/main/java/entities/EventTraderEncounter.java new file mode 100644 index 000000000..ecdd00bb7 --- /dev/null +++ b/src/main/java/entities/EventTraderEncounter.java @@ -0,0 +1,104 @@ +package entities; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** + * Event of a trader encounter. The player can trade, ignore, or rob the trader, + * each leading to specific outcomes. This class is designed to store outcomes + * and allow interaction logic to remain in the use case layer. + */ +public class EventTraderEncounter implements Event { + + private final Boolean isPositive; + private final ArrayList occuringLocation; + private final String description; + private final Map choices; + private double probability; + private final String tradeOutcomeSuccess; + private final String tradeOutcomeScam; + private final String ignoreOutcome; + private final String robOutcomeSuccess; + private final String robOutcomeFail; + + public EventTraderEncounter() { + this.isPositive = true; + this.occuringLocation = new ArrayList<>(); + occuringLocation.add(EntityConstants.PLAIN); + occuringLocation.add(EntityConstants.CITY); + occuringLocation.add(EntityConstants.DESERT); + + this.description = "You encounter a wandering trader offering supplies in exchange for your resources. " + + "What will you do?"; + this.choices = new HashMap<>(); + choices.put(EntityConstants.FIRSTCHOICE, "Trade"); + choices.put(EntityConstants.SECONDCHOICE, "Ignore"); + choices.put(EntityConstants.THIRDCHOICE, "rob"); + + this.probability = EntityConstants.RAREEVENTBASEPROB; + this.tradeOutcomeSuccess = "You traded successfully and gained valuable supplies."; + this.tradeOutcomeScam = "The trader scammed you, taking your resources and leaving you with nothing."; + this.ignoreOutcome = "You ignored the trader and moved on."; + this.robOutcomeSuccess = "You successfully robbed the trader, taking their supplies."; + this.robOutcomeFail = "The robbery attempt failed, and you lost resources in the scuffle."; + } + + @Override + public double getprobability() { + return this.probability; + } + + @Override + public void setprobability(double prob) { + this.probability = prob; + } + + @Override + public Map getchoices() { + return this.choices; + } + + @Override + public String getdescription() { + return this.description; + } + + @Override + public boolean getispositive() { + return isPositive; + } + + @Override + public ArrayList getOccuringlocation() { + return occuringLocation; + } + + public String getTradeOutcomeSuccess() { + return tradeOutcomeSuccess; + } + + public String getTradeOutcomeScam() { + return tradeOutcomeScam; + } + + public String getIgnoreOutcome() { + return ignoreOutcome; + } + + public String getRobOutcomeSuccess() { + return robOutcomeSuccess; + } + + public String getRobOutcomeFail() { + return robOutcomeFail; + } + + /** + * Return the name of this event. + * @return the event name. + */ + public String toString() { + return "TradeEncounter"; + } +} diff --git a/src/main/java/entities/EventsDecided.java b/src/main/java/entities/EventsDecided.java new file mode 100644 index 000000000..dca1cd6fe --- /dev/null +++ b/src/main/java/entities/EventsDecided.java @@ -0,0 +1,22 @@ +package entities; + +import java.util.ArrayList; + +/** + * Events that has been decided and not yet processed by player. + */ +public class EventsDecided { + private ArrayList events; + + public EventsDecided() { + events = new ArrayList<>(); + } + + public ArrayList getEvents() { + return events; + } + + public void setEvents(ArrayList events) { + this.events = events; + } +} diff --git a/src/main/java/entities/Horde.java b/src/main/java/entities/Horde.java new file mode 100644 index 000000000..b6386b1cf --- /dev/null +++ b/src/main/java/entities/Horde.java @@ -0,0 +1,102 @@ +package entities; + +/** + * The class represent the horde by it's magnitude and duration. specific calculation involves other class info are for + * Use case interact. + */ +public class Horde { + private int magnitude; + // people and firepower requirement. + private double duration; + // food and water requirement. + + public Horde() { + this.magnitude = EntityConstants.STARTERHORDEMAGNITUDE; + this.duration = EntityConstants.STARTERHORDEDURATION; + } + + public Horde(int magnitude, double duration) { + this.magnitude = magnitude; + this.duration = duration; + } + + public double getDuration() { + return duration; + } + + public void setDuration(double duration) { + this.duration = duration; + } + + public int getMagnitude() { + return magnitude; + } + + public void setMagnitude(int magnitude) { + this.magnitude = magnitude; + } + + /** + * Get the description for the horde, based on threatlevel and temperature of which player ended up on. + * @param threatLevel threat level, normal at 1, peak at 2 + * @param temperature temperature, normal at 25, max diff at 50 + * @return the description. + */ + public String getDescription(double threatLevel, double temperature) { + // Adjust magnitude based on threat level + this.magnitude = (int) (magnitude * threatLevel); + + // Adjust duration based on how far the temperature is from the ideal (25°C) + final double tempDifference = Math.abs(temperature - EntityConstants.DEFAULTTEMP); + this.duration = duration * (1 - ((EntityConstants.TEMPIMPACTHORDE * tempDifference) + / EntityConstants.MAXTEMPDIFF)); + + // Generate descriptions + final String magnitudeDescription; + if (this.magnitude < EntityConstants.HORDEMAGNITUDELARGE) { + magnitudeDescription = "around " + EntityConstants.HORDEMAGNITUDELARGE + + " zombies, scattered into smaller groups."; + } + else if (this.magnitude < EntityConstants.HORDEMAGNITUDEEXTREME) { + magnitudeDescription = "approximately " + EntityConstants.HORDEMAGNITUDEEXTREME + + " zombies, moving with relentless determination."; + } + else { + magnitudeDescription = "an overwhelming mass of about " + this.magnitude + + " zombies, consuming everything in their path."; + } + + final String durationHint; + if (temperature < EntityConstants.ICELANDEXTREMECOLD) { + durationHint = "The bitter cold seems to sap their endurance, they won't last long out here."; + } + else if (temperature < EntityConstants.ICELANDCOLD) { + durationHint = "The cool air keeps them moving steadily, but they may tire eventually."; + } + else if (temperature > EntityConstants.DESERTUNBAREABLEDEGREE) { + durationHint = "The searing heat is taking its toll, they wont hold out for long under these conditions."; + } + else if (temperature > EntityConstants.DESERTHOTDEGREE) { + durationHint = "The heat made them active, but not for too long they'll dehydrate."; + } + else { + durationHint = "The perfect temperature not only make your group comfortable," + + " but also made the horde lasting longer."; + } + + final String durationDescription; + if (this.duration >= EntityConstants.HORDEDURATIONLONG) { + durationDescription = "It lingers for days, taking advantage of the weather."; + } + else if (this.duration >= EntityConstants.HORDEDURATIONSHORT) { + durationDescription = "It stays for a few days, but conditions will soon force it to dissipate."; + } + else { + durationDescription = "It is fleeting, scattered quickly by the harsh environment."; + } + + // Combine descriptions + return "The horde consists of " + magnitudeDescription + " " + durationHint + " " + durationDescription; + } + +} diff --git a/src/main/java/entities/Inventory.java b/src/main/java/entities/Inventory.java new file mode 100644 index 000000000..f0626d0b1 --- /dev/null +++ b/src/main/java/entities/Inventory.java @@ -0,0 +1,141 @@ +package entities; + +/** + * Class reponsible for representing inventory and inventory only, provide initial resources, getter and change method. + */ +public class Inventory { + + private int food; + private int water; + private int weapon; + private int people; + + // Default constructor (no parameters) + public Inventory() { + this(EntityConstants.STARTERFOOD, + EntityConstants.STARTERWATER, + EntityConstants.STARTWEAPON, + EntityConstants.STARTERPEOPLE); + } + + // Constructor with parameters + public Inventory(int food, int water, int weapon, int people) { + this.food = food; + this.water = water; + this.weapon = weapon; + this.people = people; + } + + public int getFood() { + return food; + } + + /** + * Changing food in inventory, can be pos or neg. + * @param foodChange the change which is happening. + */ + public void changeFood(int foodChange) { + this.food = this.food + foodChange; + } + + public int getWater() { + return water; + } + + /** + * Changing water in inventory, can be pos or neg. + * @param waterChange the change which is happening. + */ + public void changeWater(int waterChange) { + this.water = this.water + waterChange; + } + + public int getWeapon() { + return weapon; + } + + /** + * Changing firearm in inventory, can be pos or neg. + * @param weaponChange the change which is happening. + */ + public void changeweapon(int weaponChange) { + this.weapon = this.weapon + weaponChange; + } + + public int getPeople() { + return people; + } + + /** + * Changing people in inventory, can be pos or neg. + * @param peopleChange the change which is happening. + */ + public void changePeople(int peopleChange) { + this.people = this.people + peopleChange; + } + + /** + * Calculatign the firepower of the group. + * @return firepower total. + */ + public double getfirepower() { + // Calculate the number of people with weapon. + final int pairs = Math.min(people, weapon); + // Remaining people who are unarmed + final int unarmedPeople = people - pairs; + + // Firepower: each pair contributes 5, and each unarmed person contributes 1 + return (pairs * EntityConstants.ARMEDPEOPLEPOWER) + + unarmedPeople * EntityConstants.UNARMPEOPLEPOWER; + } + + /** + * Method of generating string description on the change of inventory. + * @param foodChange change of food. + * @param waterChange change of water. + * @param peopleChange change of people. + * @param weaponChange change of weapon. + * @return String of the description. + */ + public String generateResourceChangeMessage(final int foodChange, final int waterChange, + final int weaponChange, final int peopleChange) { + final StringBuilder message = new StringBuilder("Your group has "); + boolean hasChanges = false; + + hasChanges |= appendChange(message, "food", foodChange); + hasChanges |= appendChange(message, "water", waterChange); + hasChanges |= appendChange(message, "people", peopleChange); + hasChanges |= appendChange(message, "weapons", weaponChange); + + final String ans; + if (!hasChanges) { + ans = "Nothing has changed for your group."; + } + else { + message.append("."); + ans = message.toString(); + } + + return ans; + } + + private boolean appendChange(final StringBuilder message, final String resourceName, final int change) { + boolean ans = false; + + if (change != 0) { + if (message.length() > EntityConstants.LENGTHMESSAGECOMMA) { + message.append(", "); + } + if (change > 0) { + message.append("gained ").append(change).append(" units of ").append(resourceName); + } + else { + message.append("lost ").append(Math.abs(change)).append(" units of ").append(resourceName); + } + ans = true; + } + + return ans; + } + +} diff --git a/src/main/java/entities/Location.java b/src/main/java/entities/Location.java new file mode 100644 index 000000000..f18a2e8a2 --- /dev/null +++ b/src/main/java/entities/Location.java @@ -0,0 +1,122 @@ +package entities; + +/** + * Interface for location (each specific xy coordinate), any environment should implement these. + * Notice, these are just basic and essential functions satisfying Interface segregation(no unnecessary implement) + * Notice as I said scalar closer to something increases is only for map construction step where each location + * starts with a higher or lower scalar. The only time resource scalar change is when player stay in same spot, decrease + * each day by some proportion. + */ +public interface Location { + + /** + * Temperature is crucial for calculating food/water consumption. ideally, closer to core of iceland, + * Colder it is, as well as desert, specific calculation are for later. + * @param distance distance of location from its core. + * @return temperature. + */ + Double getsettemperature(int distance); + + /** + * Getter method of temperature. + * @return Temperature of that location. + */ + Double gettemperature(); + + /** + * Crucial to the number people joins, in a double represent the number we'll use as scalar for people increase + * Method. + * Ideally, closer to core of city (center as more populated), it will be higher. + * And the longer they stay in same spot, the scalar decrease(people already joined or don't wanna join so decrease) + * @param distance distance from its core. + * @return people resource scalar. + */ + Double getsetpeopleresourceavailable(int distance); + + /** + * Getter method of people resource scalar. + * @return people resource scalar of that location. + */ + Double getpeopleresourceavailable(); + + /** + * Crucial to the number of food gathers act as scalar. Ideally, make it high in city and woods, the scalar decrease + * as the longer they stayed. + * @param distance distance from its core. + * @return food resource scalar + */ + Double getsetfoodresourceavailable(int distance); + + /** + * Getter method of food resource scalar. + * @return food resource scalar of that location. + */ + Double getfoodresourceavailable(); + + /** + * Crucial to the number of water gathers act as scalar. Ideally, make it high in iceland and wood + * the scalar decrease as the longer they stayed. + * @param distance distance from its core. + * @return water resource scalar + */ + Double getsetwaterresourceavailable(int distance); + + /** + * Getter method of water resource scalar. + * @return water resource scalar of that location. + */ + Double getwaterresourceavailable(); + + /** + * Crucial to number of firearm gathered. Closer to city center, this scalar will be higher. + * Same spot, decrease this. + * @param distance distance from its core. + * @return firearm resource scalar + */ + Double getsetweaponresourceavailable(int distance); + + /** + * Getter method of firearm resource scalar. + * @return firearm resource scalar of that location. + */ + Double getweaponresourceavailable(); + + /** + * The method responsible for decrease the scalar of the location if they stayed, by some proportion, determined + * by player's selected move ex: if player gathered, food weapon and water resource drop + * This is for food weapon and water drop. + */ + void decreaseresourceavailable(); + + /** + * Decrease the scalar by some proportion, which is gonna happen if player broadcast, so what's left is less. + */ + void decreaserepeopleavailable(); + + + /** + * The threat level of this location, used for calculating power of the horde, and people decrease. + * Closer to city core, more threat level, Closer to iceland/desert,(as they are more isolated) lower threat. + * @param distance distance from its core. + * @return threat level. + */ + Double getsetthreatlevel(int distance); + + /** + * Getter method of threat scalar. + * @return people threat scalar of that location. + */ + Double getthreatlevel(); + + /** + * String representing this place, Iceland, City etc. + * @return String representation. + */ + String toString(); + + /** + * String for a description of the biome. + * @return brief description. + */ + String getDescription(); +} diff --git a/src/main/java/entities/LocationCity.java b/src/main/java/entities/LocationCity.java new file mode 100644 index 000000000..0a43b32cf --- /dev/null +++ b/src/main/java/entities/LocationCity.java @@ -0,0 +1,134 @@ +package entities; + +/** + * This is city subtype of location. + */ +public class LocationCity implements Location { + private double foodresource; + private double waterresource; + private double weaponresource; + private double peopleresource; + private double temperature; + private double threat; + + public LocationCity(int dist) { + this.foodresource = EntityConstants.STARTERRESOURCESCALAR; + this.waterresource = EntityConstants.STARTERRESOURCESCALAR; + this.weaponresource = getsetweaponresourceavailable(dist); + this.peopleresource = getsetpeopleresourceavailable(dist); + this.temperature = EntityConstants.STARTERRESOURCESCALAR; + this.threat = getsetthreatlevel(dist); + } + + @Override + public Double getsettemperature(int dist) { + return this.temperature; + } + + @Override + public Double gettemperature() { + return this.temperature; + } + + @Override + public Double getsetpeopleresourceavailable(int dist) { + return EntityConstants.STARTERRESOURCESCALAR + (1 / (dist + 1)); + } + + @Override + public Double getpeopleresourceavailable() { + return this.peopleresource; + } + + @Override + public Double getsetfoodresourceavailable(int dist) { + return this.foodresource; + } + + @Override + public Double getfoodresourceavailable() { + return this.foodresource; + } + + @Override + public Double getsetwaterresourceavailable(int dist) { + return this.waterresource; + } + + @Override + public Double getwaterresourceavailable() { + return this.waterresource; + } + + @Override + public Double getsetweaponresourceavailable(int dist) { + return EntityConstants.STARTERRESOURCESCALAR + (1 / (dist + 1)); + } + + @Override + public Double getweaponresourceavailable() { + return this.weaponresource; + } + + @Override + public void decreaseresourceavailable() { + this.foodresource = this.foodresource * EntityConstants.RESOUCEDECREASERATIO; + this.waterresource = this.waterresource * EntityConstants.RESOUCEDECREASERATIO; + this.weaponresource = this.weaponresource * EntityConstants.RESOUCEDECREASERATIO; + + } + + @Override + public void decreaserepeopleavailable() { + this.peopleresource = this.peopleresource * EntityConstants.RESOUCEDECREASERATIO; + } + + @Override + public Double getsetthreatlevel(int dist) { + return EntityConstants.STARTERRESOURCESCALAR + (1 / (dist + 1)); + } + + @Override + public Double getthreatlevel() { + return this.threat; + } + + @Override + public String toString() { + return EntityConstants.CITY; + } + + @Override + public String getDescription() { + final String baseDescription = + "The city is a graveyard of skyscrapers, their windows shattered and facades crumbling. " + + "The streets are littered with rusting cars and decaying bodies, " + + "and the distant sound of groaning " + + "echoes down the alleyways."; + + // Add threat-based phrasing + final String threatDescription; + if (this.threat <= EntityConstants.CITYDANGER) { + threatDescription = + "For now, the streets seem calm. Shadows shift in the distance, but it is quiet enough to risk " + + "searching for supplies. Your group moves cautiously, always watching for danger."; + } + else if (this.threat >= EntityConstants.CITYEXTREMEDANGER) { + threatDescription = + "The city is swarming with the infected. Groans and shuffling footsteps echo from every direction, " + + "and the danger is impossible to ignore. " + + "Every turn feels like an ambush waiting to happen, and your " + + "group knows it must escape quickly or risk being overwhelmed."; + } + else { + threatDescription = + "The city feels tense and unpredictable. While not overrun, signs of the infected are everywhere. " + + "Your group must tread carefully, " + + "as any sound or movement could draw unwanted attention."; + } + + // Combine base and dynamic threat descriptions + return baseDescription + " " + threatDescription; + } + +} diff --git a/src/main/java/entities/LocationDesert.java b/src/main/java/entities/LocationDesert.java new file mode 100644 index 000000000..ea643404f --- /dev/null +++ b/src/main/java/entities/LocationDesert.java @@ -0,0 +1,132 @@ +package entities; + +/** + * This is location form of Desert. + */ +public class LocationDesert implements Location { + private double foodresource; + private double waterresource; + private double weaponresource; + private double peopleresource; + private final double temperature; + private final double threat; + + public LocationDesert(int dist) { + this.foodresource = EntityConstants.STARTERRESOURCESCALAR; + this.waterresource = getsetwaterresourceavailable(dist); + this.weaponresource = EntityConstants.STARTERRESOURCESCALAR; + this.peopleresource = getsetpeopleresourceavailable(dist); + this.temperature = getsettemperature(dist); + this.threat = EntityConstants.STARTERRESOURCESCALAR; + } + + @Override + public Double getsettemperature(int dist) { + return EntityConstants.DEFAULTTEMP + (EntityConstants.MAXTEMPDIFF * (1 / (dist + 1))); + } + + @Override + public Double gettemperature() { + return this.temperature; + } + + @Override + public Double getsetpeopleresourceavailable(int dist) { + return EntityConstants.STARTERRESOURCESCALAR - (1 / (dist + 1)); + } + + @Override + public Double getpeopleresourceavailable() { + return this.peopleresource; + } + + @Override + public Double getsetfoodresourceavailable(int dist) { + return this.foodresource; + } + + @Override + public Double getfoodresourceavailable() { + return this.foodresource; + } + + @Override + public Double getsetwaterresourceavailable(int dist) { + return EntityConstants.STARTERRESOURCESCALAR - (1 / (dist + 1)); + } + + @Override + public Double getwaterresourceavailable() { + return this.waterresource; + } + + @Override + public Double getsetweaponresourceavailable(int dist) { + return this.weaponresource; + } + + @Override + public Double getweaponresourceavailable() { + return this.weaponresource; + } + + @Override + public void decreaseresourceavailable() { + this.foodresource = this.foodresource * EntityConstants.RESOUCEDECREASERATIO; + this.waterresource = this.waterresource * EntityConstants.RESOUCEDECREASERATIO; + this.weaponresource = this.weaponresource * EntityConstants.RESOUCEDECREASERATIO; + } + + @Override + public void decreaserepeopleavailable() { + this.peopleresource = this.peopleresource * EntityConstants.RESOUCEDECREASERATIO; + } + + @Override + public Double getsetthreatlevel(int dist) { + return this.threat; + } + + @Override + public Double getthreatlevel() { + return this.threat; + } + + @Override + public String toString() { + return EntityConstants.DESERT; + } + + @Override + public String getDescription() { + final String baseDescription = + "The desert stretches endlessly, its golden dunes now marred by the occasional husk of a car " + + "or the skeletal remains of travelers who did not make it. The relentless sun beats down, " + + "offering no shelter from the horrors that might still wander here."; + + // Add temperature-based phrasing + final String temperatureDescription; + if (this.temperature <= EntityConstants.DESERTHOTDEGREE) { + temperatureDescription = + "Your group finds some relief near the desert's edge. The air is warm but bearable, and " + + "a faint breeze carries a hint of moisture, suggesting you are not yet in the heart of " + + "this wasteland."; + } + else if (this.temperature >= EntityConstants.DESERTUNBAREABLEDEGREE) { + temperatureDescription = + "Your group struggles under the merciless heat, the sun blazing down like an open furnace. " + + "The ground is too hot to touch, and every step feels like it could be your last. " + + "Supplies will not last long in this heat."; + } + else { + temperatureDescription = + "The heat is punishing, but not unbearable yet. The deeper your group ventures into this " + + "wasteland, the more the sun saps your strength and the threat of " + + "dehydration looms ever larger."; + } + + // Combine base and dynamic temperature descriptions + return baseDescription + " " + temperatureDescription; + } + +} diff --git a/src/main/java/entities/LocationForest.java b/src/main/java/entities/LocationForest.java new file mode 100644 index 000000000..1b7d478c5 --- /dev/null +++ b/src/main/java/entities/LocationForest.java @@ -0,0 +1,135 @@ +package entities; + +/** + * This is woods subtype of location. + */ +public class LocationForest implements Location { + private double foodresource; + private double waterresource; + private double weaponresource; + private double peopleresource; + private double temperature; + private double threat; + + public LocationForest(int dist) { + this.foodresource = getsetfoodresourceavailable(dist); + this.waterresource = getsetwaterresourceavailable(dist); + this.weaponresource = EntityConstants.STARTERRESOURCESCALAR; + this.peopleresource = EntityConstants.STARTERRESOURCESCALAR; + this.temperature = EntityConstants.STARTERRESOURCESCALAR; + this.threat = EntityConstants.STARTERRESOURCESCALAR; + } + + @Override + public Double getsettemperature(int dist) { + return this.temperature; + } + + @Override + public Double gettemperature() { + return this.temperature; + } + + @Override + public Double getsetpeopleresourceavailable(int dist) { + return this.peopleresource; + } + + @Override + public Double getpeopleresourceavailable() { + return this.peopleresource; + } + + @Override + public Double getsetfoodresourceavailable(int dist) { + return EntityConstants.STARTERRESOURCESCALAR + (1 / (dist + 1)); + } + + @Override + public Double getfoodresourceavailable() { + return this.foodresource; + } + + @Override + public Double getsetwaterresourceavailable(int dist) { + return EntityConstants.STARTERRESOURCESCALAR + (1 / (dist + 1)); + } + + @Override + public Double getwaterresourceavailable() { + return this.waterresource; + } + + @Override + public Double getsetweaponresourceavailable(int dist) { + return this.weaponresource; + } + + @Override + public Double getweaponresourceavailable() { + return this.weaponresource; + } + + @Override + public void decreaseresourceavailable() { + this.foodresource = this.foodresource * EntityConstants.RESOUCEDECREASERATIO; + this.waterresource = this.waterresource * EntityConstants.RESOUCEDECREASERATIO; + this.weaponresource = this.weaponresource * EntityConstants.RESOUCEDECREASERATIO; + } + + @Override + public void decreaserepeopleavailable() { + this.peopleresource = this.peopleresource * EntityConstants.RESOUCEDECREASERATIO; + } + + @Override + public Double getsetthreatlevel(int dist) { + return this.threat; + } + + @Override + public Double getthreatlevel() { + return this.threat; + } + + @Override + public String toString() { + return EntityConstants.FOREST; + } + + @Override + public String getDescription() { + final String baseDescription = + "The forest feels alive yet foreboding, its towering trees " + + "stretching high above and casting long shadows. " + + "The air is rich with the scent of damp earth, and " + + "the undergrowth grows thick as your group ventures deeper."; + + // Determine resource-based phrasing + final String resourceDescription; + if (this.foodresource <= EntityConstants.FORESTRICH + && this.waterresource <= EntityConstants.FORESTEXTREMERICH) { + resourceDescription = + "At the forest's edge, food and water are scarce. The sparse undergrowth offers little sustenance, " + + "and your group must decide carefully whether to move deeper in search of resources."; + } + else if (this.foodresource >= EntityConstants.FORESTEXTREMERICH + && this.waterresource >= EntityConstants.FORESTEXTREMERICH) { + resourceDescription = + "Deep within the heart of the forest, resources are plentiful. " + + "Your group finds wild fruits, clear streams, " + + "and signs of abundant wildlife. Yet the dense trees " + + "and eerie quiet suggest danger might not be far away."; + } + else { + resourceDescription = + "The forest offers a mix of hope and caution. While food and water are becoming easier to find, " + + "the growing density of the undergrowth hints at " + + "the challenges and risks that lie ahead."; + } + + // Combine base and dynamic resource descriptions + return baseDescription + " " + resourceDescription; + } + +} diff --git a/src/main/java/entities/LocationIceland.java b/src/main/java/entities/LocationIceland.java new file mode 100644 index 000000000..b252a5efd --- /dev/null +++ b/src/main/java/entities/LocationIceland.java @@ -0,0 +1,130 @@ +package entities; + +/** + * This is location form of Iceland. + */ +public class LocationIceland implements Location { + private double foodresource; + private double waterresource; + private double weaponresource; + private double peopleresource; + private final double temperature; + private final double threat; + + public LocationIceland(int dist) { + this.foodresource = EntityConstants.STARTERRESOURCESCALAR; + this.waterresource = getsetwaterresourceavailable(dist); + this.weaponresource = EntityConstants.STARTERRESOURCESCALAR; + this.peopleresource = getsetpeopleresourceavailable(dist); + this.temperature = getsettemperature(dist); + this.threat = getsetthreatlevel(dist); + } + + @Override + public Double getsettemperature(int dist) { + return EntityConstants.DEFAULTTEMP - (EntityConstants.MAXTEMPDIFF * (1 / (dist + 1))); + } + + @Override + public Double gettemperature() { + return this.temperature; + } + + @Override + public Double getsetpeopleresourceavailable(int dist) { + return EntityConstants.STARTERRESOURCESCALAR - (1 / (dist + 1)); + } + + @Override + public Double getpeopleresourceavailable() { + return this.peopleresource; + } + + @Override + public Double getsetfoodresourceavailable(int dist) { + return this.foodresource; + } + + @Override + public Double getfoodresourceavailable() { + return this.foodresource; + } + + @Override + public Double getsetwaterresourceavailable(int dist) { + return EntityConstants.STARTERRESOURCESCALAR + (1 / (dist + 1)); + } + + @Override + public Double getwaterresourceavailable() { + return this.waterresource; + } + + @Override + public Double getsetweaponresourceavailable(int dist) { + return this.weaponresource; + } + + @Override + public Double getweaponresourceavailable() { + return this.weaponresource; + } + + @Override + public void decreaseresourceavailable() { + this.foodresource = this.foodresource * EntityConstants.RESOUCEDECREASERATIO; + this.waterresource = this.waterresource * EntityConstants.RESOUCEDECREASERATIO; + this.weaponresource = this.weaponresource * EntityConstants.RESOUCEDECREASERATIO; + } + + @Override + public void decreaserepeopleavailable() { + this.peopleresource = this.peopleresource * EntityConstants.RESOUCEDECREASERATIO; + } + + @Override + public Double getsetthreatlevel(int dist) { + return EntityConstants.STARTERRESOURCESCALAR - (EntityConstants.MAXTHREATDIFF / (dist + 1)); + } + + @Override + public Double getthreatlevel() { + return this.threat; + } + + @Override + public String toString() { + return EntityConstants.ICELAND; + } + + @Override + public String getDescription() { + final String baseDescription = + "The icy tundra stretches endlessly, a barren landscape of snow and frost. " + + "Jagged ice formations rise like silent sentinels, " + + "and the wind howls across the open plains."; + + // Add temperature-based phrasing + final String temperatureDescription; + if (this.temperature >= EntityConstants.ICELANDCOLD) { + temperatureDescription = + "The cold is biting but manageable. Your group trudges carefully, keeping an eye out for shelter " + + "as frost begins to settle on your gear."; + } + else if (this.temperature <= EntityConstants.ICELANDEXTREMECOLD) { + temperatureDescription = + "The cold is deadly, cutting through even the thickest clothing. Frostbite threatens your group, " + + "and every breath feels like shards of ice tearing through your lungs."; + } + else { + temperatureDescription = + "The freezing air saps your strength as you march onward. " + + "The snow is deep, and every step feels heavier, " + + "but the group presses on, desperate to find refuge before the cold worsens."; + } + + // Combine base and dynamic temperature descriptions + return baseDescription + " " + temperatureDescription; + } + +} diff --git a/src/main/java/entities/LocationPlain.java b/src/main/java/entities/LocationPlain.java new file mode 100644 index 000000000..4bde6dbc7 --- /dev/null +++ b/src/main/java/entities/LocationPlain.java @@ -0,0 +1,105 @@ +package entities; + +/** + * This is location form of plain, more like default, which is not any of special biome (iceland, desert etc). + */ +public class LocationPlain implements Location { + private double foodResource; + private double waterResource; + private double weaponResource; + private double peopleResource; + private final double temperature; + private final double threat; + + public LocationPlain() { + this.foodResource = EntityConstants.STARTERRESOURCESCALAR; + this.waterResource = EntityConstants.STARTERRESOURCESCALAR; + this.weaponResource = EntityConstants.STARTERRESOURCESCALAR; + this.peopleResource = EntityConstants.STARTERRESOURCESCALAR; + this.temperature = EntityConstants.DEFAULTTEMP; + this.threat = EntityConstants.DEFAULTTHREAT; + } + + @Override + public Double getsettemperature(int dist) { + return temperature; + } + + @Override + public Double gettemperature() { + return temperature; + } + + @Override + public Double getsetpeopleresourceavailable(int dist) { + return this.peopleResource; + } + + @Override + public Double getpeopleresourceavailable() { + return this.peopleResource; + } + + @Override + public Double getsetfoodresourceavailable(int dist) { + return this.foodResource; + } + + @Override + public Double getfoodresourceavailable() { + return this.foodResource; + } + + @Override + public Double getsetwaterresourceavailable(int dist) { + return this.waterResource; + } + + @Override + public Double getwaterresourceavailable() { + return this.waterResource; + } + + @Override + public Double getsetweaponresourceavailable(int dist) { + return this.weaponResource; + } + + @Override + public Double getweaponresourceavailable() { + return this.weaponResource; + } + + @Override + public void decreaseresourceavailable() { + this.foodResource = this.foodResource * EntityConstants.RESOUCEDECREASERATIO; + this.waterResource = this.waterResource * EntityConstants.RESOUCEDECREASERATIO; + this.weaponResource = this.weaponResource * EntityConstants.RESOUCEDECREASERATIO; + } + + @Override + public void decreaserepeopleavailable() { + this.peopleResource = this.peopleResource * EntityConstants.RESOUCEDECREASERATIO; + } + + @Override + public Double getsetthreatlevel(int dist) { + return this.threat; + } + + @Override + public Double getthreatlevel() { + return this.threat; + } + + @Override + public String toString() { + return EntityConstants.PLAIN; + } + + @Override + public String getDescription() { + return "The plains stretch endlessly in every direction, a sea of swaying grass under a pale, open sky. " + + "The emptiness is both calming and unsettling, offering little cover should danger arise."; + } +} diff --git a/src/main/java/entities/Main.java b/src/main/java/entities/Main.java new file mode 100644 index 000000000..b72d1da6a --- /dev/null +++ b/src/main/java/entities/Main.java @@ -0,0 +1,16 @@ +package entities; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; + +public class Main { + public static void main(String[] args) { + ArrayList environments = new ArrayList<>(Arrays.asList("Iceland", "Desert", "Forest", "City", "Plain")); + MapFactory Mapfact =new MapFactory(); + ArrayList>>> cores = + Mapfact.getCores(100, 100, environments); + ArrayList> grids = Mapfact.getGrids(100, 100, cores); + Mapfact.printGrids(grids); + } +} diff --git a/src/main/java/entities/MapFactory.java b/src/main/java/entities/MapFactory.java new file mode 100644 index 000000000..546361bdb --- /dev/null +++ b/src/main/java/entities/MapFactory.java @@ -0,0 +1,180 @@ +package entities; + +import java.util.*; + +/** + * This class is responsible for creating the map with randomization. + * Method returns location of core for resource calculation. + * Method returns the grid for map data. + */ +public class MapFactory { + + /** + * Method for generating different core for each environment in the format + * [{City: [(100, 200), (50 100)]}, {iceland: [(50, 50)]}] + * In this example, city have two core (100, 200) (50, 100), which have be used for calculating resources scalar. + * @param xWidth Map size, the width + * @param yLength Map size, the length + * @param typeOfEnvironment list of different environments, iceland woods etc. + * @return Return the description above in that format. + */ + public ArrayList>>> getCores( + final int xWidth, final int yLength, final ArrayList typeOfEnvironment) { + final ArrayList>>> environmentCores = new ArrayList<>(); + final Random random = new Random(); + for (final String environment : typeOfEnvironment) { + final ArrayList> coreCoordinates = new ArrayList<>(); + final int numberOfCores = 1 + random.nextInt(5); + for (int i = 0; i < numberOfCores; i++) { + Map.Entry newCore; + boolean validCore; + do { + final int x = random.nextInt(xWidth); + final int y = random.nextInt(yLength); + newCore = new AbstractMap.SimpleEntry<>(x, y); + validCore = true; + for (Map.Entry existingCore : coreCoordinates) { + if (calculateDistance(existingCore, newCore) < EntityConstants.CORERANGE) { + validCore = false; + break; + } + } + } while (!validCore); + coreCoordinates.add(newCore); + } + final Map>> environmentMap = new HashMap<>(); + environmentMap.put(environment, coreCoordinates); + environmentCores.add(environmentMap); + } + return environmentCores; + } + + // This is a hlper method + private double calculateDistance(Map.Entry point1, Map.Entry point2) { + final int xDiff = point1.getKey() - point2.getKey(); + final int yDiff = point1.getValue() - point2.getValue(); + return Math.sqrt(xDiff * xDiff + yDiff * yDiff); + } + + /** + * Construct the map/grid using the cores provided. + * @param xWidth Map size width. + * @param yLength Map size length. + * @param cores Different cores given. + * @return grid made of locations + */ + + public ArrayList> getGrids( + final int xWidth, final int yLength, ArrayList>>> cores + ) { + final ArrayList> grids = initializeGrid(xWidth, yLength); + for (Map>> environmentCores : cores) { + for (Map.Entry>> entry : environmentCores.entrySet()) { + updateGridWithEnvironment(grids, entry, xWidth, yLength); + } + } + return grids; + } + + // Helper method to initialize the grid with default plain as dealut. + private ArrayList> initializeGrid(final int xWidth, final int yLength) { + final ArrayList> grids = new ArrayList<>(); + for (int x = 0; x < xWidth; x++) { + final ArrayList partGrids = new ArrayList<>(); + for (int y = 0; y < yLength; y++) { + partGrids.add(new LocationPlain()); + } + grids.add(partGrids); + } + return grids; + } + + // Helper method to update the grid based on the environment and its core coordinates + private void updateGridWithEnvironment( + final ArrayList> grids, + final Map.Entry>> environmentEntry, + final int xWidth, + final int yLength + ) { + final String environmentType = environmentEntry.getKey(); + final ArrayList> coordinates = environmentEntry.getValue(); + final int radius = EntityConstants.BIOMERADIUS; + for (Map.Entry coordinate : coordinates) { + final int centerX = coordinate.getKey(); + final int centerY = coordinate.getValue(); + iterateGridWithinRadius(grids, environmentType, centerX, centerY, radius, xWidth, yLength); + } + } + + // Helper method to iterate over grid cells within a radius and modify them + private void iterateGridWithinRadius( + final ArrayList> grids, + final String environmentType, + final int centerX, + final int centerY, + final int radius, + final int xWidth, + final int yLength + ) { + for (int x = Math.max(0, centerX - radius); x < Math.min(xWidth, centerX + radius); x++) { + for (int y = Math.max(0, centerY - radius); y < Math.min(yLength, centerY + radius); y++) { + final int distance = (int) Math.sqrt(Math.pow(x - centerX, 2) + Math.pow(y - centerY, 2)); + if (distance <= radius) { + final Location newLocation = createLocationByTypeAndDistance(environmentType, distance); + grids.get(x).set(y, newLocation); + } + } + } + } + + // Helper method to create a Location + private Location createLocationByTypeAndDistance(String environmentType, int distance) { + switch (environmentType) { + case EntityConstants.CITY: + return new LocationCity(distance); + case EntityConstants.FOREST: + return new LocationForest(distance); + case EntityConstants.PLAIN: + return new LocationPlain(); + case EntityConstants.ICELAND: + return new LocationIceland(distance); + case EntityConstants.DESERT: + return new LocationDesert(distance); + default: + return new LocationPlain(); + } + } + + /** + * Prints the grid to the console, using specific characters to represent each Location type. + * P - Plain, H - Iceland, D - Desert, C - City, F - Forest + * @param grids The grid made of locations. + */ + public void printGrids(ArrayList> grids) { + for (ArrayList row : grids) { + for (Location loc : row) { + // Determine the character representation based on the Location type + if (loc instanceof LocationPlain) { + System.out.print("P "); + } + else if (loc instanceof LocationIceland) { + System.out.print("i "); + } + else if (loc instanceof LocationDesert) { + System.out.print(" "); + } + else if (loc instanceof LocationCity) { + System.out.print("W "); + } + else if (loc instanceof LocationForest) { + System.out.print("' "); + } + else { + System.out.print("? "); + } + } + System.out.println(); + } + } + +} diff --git a/src/main/java/entities/Maps.java b/src/main/java/entities/Maps.java new file mode 100644 index 000000000..000413e3f --- /dev/null +++ b/src/main/java/entities/Maps.java @@ -0,0 +1,21 @@ +package entities; + +import java.util.ArrayList; + +/** + * This class represent the map of the game. + * Notice, the map generating process (randomly) should be done by map factory class and pass the grid to here in main. + */ + +public class Maps { + private ArrayList> grid; + + public Maps(ArrayList> grid) { + this.grid = grid; + + } + + public ArrayList> getGrid() { + return grid; + } +} diff --git a/src/main/java/entities/Player.java b/src/main/java/entities/Player.java new file mode 100644 index 000000000..af9722069 --- /dev/null +++ b/src/main/java/entities/Player.java @@ -0,0 +1,67 @@ +package entities; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Represents a player in the game. + * This entity contains information about the player, such as their ID, username, and password. + * The Player class encapsulates the player's identity and authentication logic. + */ +public class Player { + // Unique identifier for the player + private final String id; + // The player's username + private final String username; + // The player's password + private final String password; + + /** + * Constructs a new Player with the specified ID, username, and password. + * + * @param id A unique identifier for the player. + * This could be a database-generated ID. + * It uniquely distinguishes this player from all others in the system. + * @param username The username chosen by the player for logging into the game. + * @param password The player's password for authentication. + */ + @JsonCreator + public Player(@JsonProperty("id") String id, + @JsonProperty("username") String username, + @JsonProperty("password") String password) { + this.id = id; + this.username = username; + this.password = password; + } + + /** + * Gets the unique identifier for the player. + * + * @return The player's unique ID. + */ + public String getId() { + return id; + } + + /** + * Gets the username of the player. + * + * @return The player's username. + */ + public String getUsername() { + return username; + } + + /** + * Validates the player's password by comparing it with the provided input. + * + * @param inputPassword The password input provided for authentication. + * @return True if the input matches the player's password, otherwise false. + */ + public boolean validatePassword(String inputPassword) { + return this.password.equals(inputPassword); + } + + public String getPassword() { + return password; } +} diff --git a/src/main/java/entities/PlayerAttributes.java b/src/main/java/entities/PlayerAttributes.java new file mode 100644 index 000000000..450832120 --- /dev/null +++ b/src/main/java/entities/PlayerAttributes.java @@ -0,0 +1,93 @@ +package entities; + +/** + * Class responsible for storing attribution information and updates. + * Note, the class shouldn't be called after player formally "started" the game as attributes are fixed. + * Points: how many points you have to allocate. If difficulty extension introduced, change the starterattributepoint. + * Charisma: Increase the chance and number of people joined after each broadcast. + * Luck: Increase probability of positive events, Decrease probability of negative events. + * Mobilization: Better mobilization ability allow group to move faster. num of action per day increase accordingly. + * Thrift: Ability of better allocating resources, decrease food/water consumption. + * Generalship: Increase firepower by changing/increase proportion of how it's calculated. + * Could be more for modification added later. + */ + +public class PlayerAttributes { + private int points; + // Control the amount of people involvement per day + private int social; + // Control the possibility of the positive effects + private int luck; + // Control the moving scale and moving times + private int mobilization; + // Control the resource consumption per individual per day + private int thrift; + // Control the level of firepower + private int generalship; + + public PlayerAttributes() { + this.points = EntityConstants.STARTERATRIBUTEPOINT; + this.social = 0; + this.luck = 0; + this.mobilization = 0; + this.thrift = 0; + this.generalship = 0; + } + + public PlayerAttributes(int points, int social, int luck, int mobilization, int thrift, int generalship) { + this.points = points; + this.social = social; + this.luck = luck; + this.mobilization = mobilization; + this.thrift = thrift; + this.generalship = generalship; + } + + public int getPoints() { + return points; + } + + public void setPoints(int points) { + this.points = points; + } + + public int getSocial() { + return social; + } + + public void setSocial(int social) { + this.social = social; + } + + public int getLuck() { + return luck; + } + + public void setLuck(int luck) { + this.luck = luck; + } + + public int getMobilization() { + return mobilization; + } + + public void setMobilization(int mobilization) { + this.mobilization = mobilization; + } + + public int getThrift() { + return thrift; + } + + public void setThrift(int thrift) { + this.thrift = thrift; + } + + public int getGeneralship() { + return generalship; + } + + public void setGeneralship(int generalship) { + this.generalship = generalship; + } +} diff --git a/src/main/java/entities/PlayerInfo.java b/src/main/java/entities/PlayerInfo.java new file mode 100644 index 000000000..5d159e743 --- /dev/null +++ b/src/main/java/entities/PlayerInfo.java @@ -0,0 +1,74 @@ +package entities; + +/** + * Playerinfo during the game. + */ +public class PlayerInfo { + // Player's username + private final String name; + // Player's score + private int score; + // Number of days the player survived + private int daysSurvived; + // Whether the player won the game + private boolean won; + private int actionPoint; + + /** + * Constructs a new RankingEntry with the specified attributes. + * + * @param name The player's username. + */ + + public PlayerInfo(String name) { + this.name = name; + this.score = 0; + this.daysSurvived = 1; + this.won = false; + this.actionPoint = EntityConstants.STARTERACTIONPOINT; + } + + public PlayerInfo(String name, int score, int daysSurvived, boolean won, int actionPoint) { + this.name = name; + this.score = score; + this.daysSurvived = daysSurvived; + this.won = won; + this.actionPoint = actionPoint; + } + + public String getName() { + return name; + } + + public int getScore() { + return score; + } + + public void setScore(int score) { + this.score = score; + } + + public int getDaysSurvived() { + return daysSurvived; + } + + public void setDaysSurvived(int daysSurvived) { + this.daysSurvived = daysSurvived; + } + + public boolean isWon() { + return won; + } + + public void setWon(boolean won) { + this.won = won; + } + + public int getActionPoint() { + return actionPoint; + } + + public void setActionPoint(int actionPoint) { + this.actionPoint = actionPoint; + } +} diff --git a/src/main/java/entities/PlayerLocation.java b/src/main/java/entities/PlayerLocation.java new file mode 100644 index 000000000..76b1cb67d --- /dev/null +++ b/src/main/java/entities/PlayerLocation.java @@ -0,0 +1,35 @@ +package entities; + +/** + * Class keep track of player location. + */ +public class PlayerLocation { + private int xcoordinate; + private int ycoordinate; + + public PlayerLocation() { + this.xcoordinate = EntityConstants.SPAWNXCOOR; + this.ycoordinate = EntityConstants.SPAWNYCOOR; + } + + public PlayerLocation(int xcoordinate, int ycoordinate) { + this.xcoordinate = xcoordinate; + this.ycoordinate = ycoordinate; + } + + public int getXcoordinate() { + return xcoordinate; + } + + public void setXcoordinate(int xcoordinate) { + this.xcoordinate = xcoordinate; + } + + public int getYcoordinate() { + return ycoordinate; + } + + public void setYcoordinate(int ycoordinate) { + this.ycoordinate = ycoordinate; + } +} diff --git a/src/main/java/entities/PlayerRankingEntry.java b/src/main/java/entities/PlayerRankingEntry.java new file mode 100644 index 000000000..f4e5806ea --- /dev/null +++ b/src/main/java/entities/PlayerRankingEntry.java @@ -0,0 +1,59 @@ +package entities; + +/** + * Represents an entry in the ranking list. + * Contains the player's name, score, days survived, and whether they won. + */ +public class PlayerRankingEntry { + // Player's username + private final String name; + // Player's score + private int score; + // Number of days the player survived + private int daysSurvived; + // Whether the player won the game + private boolean won; + + /** + * Constructs a new RankingEntry with the specified attributes. + * + * @param name The player's username. + * @param score The player's score. + * @param daysSurvived The number of days the player survived. + * @param won Whether the player won the game. + */ + public PlayerRankingEntry(String name, int score, int daysSurvived, boolean won) { + this.name = name; + this.score = score; + this.daysSurvived = daysSurvived; + this.won = won; + } + + public String getName() { + return name; + } + + public int getScore() { + return score; + } + + public int getDaysSurvived() { + return daysSurvived; + } + + public boolean isWon() { + return won; + } + + public void setScore(int score) { + this.score = score; + } + + public void setWon(boolean won) { + this.won = won; + } + + public void setDaysSurvived(int daysSurvived) { + this.daysSurvived = daysSurvived; + } +} diff --git a/src/main/java/entity/User.java b/src/main/java/entity/User.java deleted file mode 100644 index e0c57e9a6..000000000 --- a/src/main/java/entity/User.java +++ /dev/null @@ -1,24 +0,0 @@ -package entity; - -/** - * The representation of a password-protected user for our program. - */ -public class User { - - private final String name; - private final String password; - - public User(String name, String password) { - this.name = name; - this.password = password; - } - - public String getName() { - return name; - } - - public String getPassword() { - return password; - } - -} diff --git a/src/main/java/frameworks/database/FileDatabase.java b/src/main/java/frameworks/database/FileDatabase.java new file mode 100644 index 000000000..3d5876161 --- /dev/null +++ b/src/main/java/frameworks/database/FileDatabase.java @@ -0,0 +1,57 @@ +package frameworks.database; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * A utility class for managing a file-based JSON database. + * This class allows reading and writing a list of data objects to a JSON file + * specified by the user. It uses Jackson for JSON serialization and deserialization. + * + * @param The type of the data objects that will be stored in the database. + */ +public class FileDatabase { + private final ObjectMapper objectMapper = new ObjectMapper(); + private final String filePath; + private final TypeReference> typeReference; + + /** + * Constructs a new FileDatabase instance. + * + * @param filePath The path to the JSON file that will be used for storage. + * @param typeReference A TypeReference to handle generic type information for deserialization. + */ + public FileDatabase(String filePath, TypeReference> typeReference) { + this.filePath = filePath; + this.typeReference = typeReference; + } + + /** + * Loads data from the JSON file. + * + * @return A list of data objects read from the file. If the file does not exist, + * an empty list is returned. + * @throws IOException If the file cannot be read or parsed. + */ + public List load() throws IOException { + File file = new File(filePath); + if (!file.exists()) { + return List.of(); + } + return objectMapper.readValue(file, typeReference); + } + + /** + * Saves data to the JSON file. + * + * @param data The list of data objects to save to the file. + * @throws IOException If the file cannot be written. + */ + public void save(List data) throws IOException { + objectMapper.writerWithDefaultPrettyPrinter().writeValue(new File(filePath), data); + } +} diff --git a/src/main/java/frameworks/database/InMemoryUnifiedDataAccess.java b/src/main/java/frameworks/database/InMemoryUnifiedDataAccess.java new file mode 100644 index 000000000..f14bb6731 --- /dev/null +++ b/src/main/java/frameworks/database/InMemoryUnifiedDataAccess.java @@ -0,0 +1,278 @@ +package frameworks.database; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import entities.*; +import usecases.nevagateEventPage.NevagateEventDataAccessInterface; +import usecases.dailybroadcast.BroadcastDataAccessInterface; +import usecases.dailygather.GatherDataAccessInterface; +import usecases.dailymove.MoveDataAccessInterface; +import usecases.endprocesshorde.HordeDataAccessInterface; +import usecases.eventdecide.DecideEventDataAccessInterface; +import usecases.eventinitialize.EventInitializeDataAccessInterface; +import usecases.eventrespond.ambush.AmbushDataAccessInterface; +import usecases.eventrespond.blizzard.BlizzardDataAccessInterface; +import usecases.eventrespond.flood.FloodDataAccessInterface; +import usecases.eventrespond.survivor.SurvivorDataAccessInterface; +import usecases.eventrespond.trader.TraderDataAccessInterface; +import usecases.fetchcurrentevent.CurrentEventDataAccessInterface; +import usecases.fetchresource.FetchDataAccessInterface; +import usecases.gamelosedetecter.LoseDataAccessInterface; +import usecases.gameminimap.MinimapDataAccessInterface; +import usecases.gamenewday.NewdayDataAccessInterface; +import usecases.gameplacedescription.PlaceDescriptionDataAccessInterface; +import usecases.nevagateAllowcatePage.NevagateAllowcateDataAccessInterface; +import usecases.nevagateGame.NevagateGameDataAccessInterface; +import usecases.nevagateGameover.NevagateGameOverDataAccessInterface; +import usecases.navigateMain.NavigateMainDataAccessInterface; +import usecases.startallowcate.AllowcateDataAccessInterface; + +/** + * Unified In-Memory Data Access Layer for managing all game data. + */ +public class InMemoryUnifiedDataAccess implements + AllowcateDataAccessInterface, + BroadcastDataAccessInterface, + DecideEventDataAccessInterface, + EventInitializeDataAccessInterface, + FetchDataAccessInterface, + GatherDataAccessInterface, + HordeDataAccessInterface, + MinimapDataAccessInterface, + MoveDataAccessInterface, + NewdayDataAccessInterface, + PlaceDescriptionDataAccessInterface, + NevagateAllowcateDataAccessInterface, + FloodDataAccessInterface, + SurvivorDataAccessInterface, + TraderDataAccessInterface, + BlizzardDataAccessInterface, + AmbushDataAccessInterface, + NavigateMainDataAccessInterface, + NevagateEventDataAccessInterface, + CurrentEventDataAccessInterface, + NevagateGameDataAccessInterface, + LoseDataAccessInterface, + NevagateGameOverDataAccessInterface { + // Shared game data + private PlayerAttributes playerAttributes; + private Inventory inventory; + private ArrayList unprocessedevents; + private Location currentLocation; + private Horde horde; + private PlayerInfo playerInfo; + private PlayerLocation playerLocation; + private Maps gameMap; + private EventAmbush ambush; + private EventBlizzard blizzard; + private EventFlood flood; + private EventSurvivorJoins survivorJoins; + private EventTraderEncounter traderEncounter; + + // Constructor to initialize shared objects + public InMemoryUnifiedDataAccess(PlayerAttributes playerAttributes, Inventory inventory, + ArrayList events, Location currentLocation, + Horde horde, PlayerInfo playerInfo, + PlayerLocation playerLocation, Maps gameMap, EventAmbush ambush, + EventBlizzard blizzard, EventFlood flood, EventSurvivorJoins survivorJoins, + EventTraderEncounter traderEncounter) { + this.playerAttributes = playerAttributes; + this.inventory = inventory; + this.unprocessedevents = events; + this.currentLocation = currentLocation; + this.horde = horde; + this.playerInfo = playerInfo; + this.playerLocation = playerLocation; + this.gameMap = gameMap; + this.ambush = ambush; + this.blizzard = blizzard; + this.flood = flood; + this.survivorJoins = survivorJoins; + this.traderEncounter = traderEncounter; + } + + public PlayerAttributes getPlayerAttributes() { + return playerAttributes; + } + + /** + * Returns player attributes as a map. + */ + @Override + public Map getPlayerAttributesAsMap() { + final Map attributesMap = new HashMap<>(); + attributesMap.put("Social", playerAttributes.getSocial()); + attributesMap.put("Luck", playerAttributes.getLuck()); + attributesMap.put("Mobilization", playerAttributes.getMobilization()); + attributesMap.put("Thrift", playerAttributes.getThrift()); + attributesMap.put("Generalship", playerAttributes.getGeneralship()); + return attributesMap; + } + + @Override + public void setSocial(int social) { + playerAttributes.setSocial(social); + } + + @Override + public void setLuck(int luck) { + playerAttributes.setLuck(luck); + } + + @Override + public void setThrift(int thrift) { + playerAttributes.setThrift(thrift); + } + + @Override + public void setMobilization(int mobilization) { + playerAttributes.setMobilization(mobilization); + } + + @Override + public void setGeneralship(int generalship) { + playerAttributes.setGeneralship(generalship); + } + + @Override + public void setPoint(int point) { + playerAttributes.setPoints(point); + } + + // Implement of the BroadcastDataAccessInterface + @Override + public Inventory getInventory() { + return inventory; + } + + // Implement of the DecideEventDataAccessInterface + @Override + public ArrayList getALLEvents() { + // Return a copy to ensure immutability + final ArrayList allevents = new ArrayList(); + allevents.add(ambush); + allevents.add(blizzard); + allevents.add(flood); + allevents.add(survivorJoins); + allevents.add(traderEncounter); + return allevents; + } + + @Override + public void setDecidedEvents(ArrayList decidedevents) { + this.unprocessedevents = new ArrayList<>(decidedevents); + } + + @Override + public ArrayList getUnprocessedEvents() { + return unprocessedevents; + } + + @Override + public Location getLocation() { + return currentLocation; + } + + @Override + public int getActionPoint() { + return playerInfo.getActionPoint(); + } + + @Override + public void setActionPoint(int actionPoint) { + playerInfo.setActionPoint(actionPoint); + } + + // Implement of the EventInitiallizeInterface + @Override + public Event getEvent() { + return unprocessedevents.get(0); + } + + @Override + public void removeEvent() { + this.unprocessedevents.remove(0); + } + + // Implement of the FetchDataAccessInterface + + // Implement of the GatherInterface + @Override + public void decreaseResourceavailable() { + currentLocation.decreaseresourceavailable(); + } + + @Override + public void changeFood(int foodgathered) { + inventory.changeFood(foodgathered); + } + + @Override + public void changeWater(int watergathered) { + inventory.changeWater(watergathered); + } + + @Override + public void changeWeapon(int weapongathered) { + inventory.changeweapon(weapongathered); + } + + // Implement of the HordeInterface + @Override + public Horde getHorde() { + return horde; + } + + @Override + public void setWon(boolean won) { + this.playerInfo.setWon(won); + } + + @Override + public PlayerInfo getPlayerInfo() { + return playerInfo; + } + + // Implement of the MinimapInterface + + @Override + public PlayerLocation getPlayerLocation() { + return playerLocation; + } + + @Override + public Maps getMaps() { + return gameMap; + } + + // Implement of the MoveInterface + @Override + public void updatePlayerLocation(int newx, int newy) { + playerLocation.setXcoordinate(newx); + playerLocation.setYcoordinate(newy); + currentLocation = gameMap.getGrid().get(newy).get(newx); + } + + // Implement of the NewdayInterface + @Override + public void setDaysSurvived(int days) { + playerInfo.setDaysSurvived(days); + } + + @Override + public void setScore(int score) { + playerInfo.setScore(score); + } + + @Override + public void changePeople(int people) { + inventory.changePeople(people); + } + + @Override + public ArrayList getDecidedEvents() { + return this.unprocessedevents; + } +} diff --git a/src/main/java/frameworks/database/JsonLoginDataAccess.java b/src/main/java/frameworks/database/JsonLoginDataAccess.java new file mode 100644 index 000000000..6053de398 --- /dev/null +++ b/src/main/java/frameworks/database/JsonLoginDataAccess.java @@ -0,0 +1,71 @@ +package frameworks.database; + +import java.io.IOException; +import java.util.List; + +import com.fasterxml.jackson.core.type.TypeReference; +import entities.Player; +import usecases.accountlogin.LoginDataAccessInterface; + +/** + * A JSON-based implementation of the LoginDataAccessInterface. + * This class provides methods to validate user credentials and check user existence. + */ +public class JsonLoginDataAccess implements LoginDataAccessInterface { + private final FileDatabase database; + private List players; + + /** + * Constructs a new JsonLoginDataAccess object with the specified file path. + * + * @param filePath The path to the JSON file containing player data. + * @throws IOException If there is an issue reading the JSON file. + */ + public JsonLoginDataAccess(String filePath) throws IOException { + this.database = new FileDatabase<>(filePath, new TypeReference>() {}); + this.players = database.load(); + } + + /** + * Validates the credentials of a user. + * + * @param username The username provided by the user. + * @param password The password provided by the user. + * @return True if the credentials are valid, otherwise false. + */ + @Override + public boolean validateCredentials(String username, String password) { + return players.stream() + .anyMatch(player -> player.getUsername().equals(username) + && player.validatePassword(password)); + } + + /** + * Checks if a user with the specified username exists. + * + * @param username The username to check. + * @return True if the user exists, otherwise false. + */ + @Override + public boolean doesUserExist(String username) { + return players.stream() + .anyMatch(player -> player.getUsername().equals(username)); + } + + /** + * Reloads the player data from the JSON file. + * This ensures that any updates to the file are reflected in the players list. + */ + @Override + public void reloadData() { + try { + this.players = database.load(); + System.out.println("Data successfully reloaded. Current players: " + players); + } + catch (IOException e) { + System.err.println("Error reloading data: " + e.getMessage()); + throw new RuntimeException("Unable to reload player data.", e); + } + } + +} diff --git a/src/main/java/frameworks/database/JsonRankingDataAccess.java b/src/main/java/frameworks/database/JsonRankingDataAccess.java new file mode 100644 index 000000000..dcc1ec459 --- /dev/null +++ b/src/main/java/frameworks/database/JsonRankingDataAccess.java @@ -0,0 +1,83 @@ +package frameworks.database; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.core.type.TypeReference; +import entities.PlayerRankingEntry; +import usecases.accountranking.RankingDataAccessInterface; + +/** + * A JSON-based implementation of the RankingDataAccessInterface. + * This class is responsible for retrieving and updating ranking data stored in a JSON file. + */ +public class JsonRankingDataAccess implements RankingDataAccessInterface { + private final FileDatabase database; + private List rankings; + + public JsonRankingDataAccess(String filePath) throws IOException { + this.database = new FileDatabase<>(filePath, new TypeReference>() {}); + this.rankings = new ArrayList<>(database.load()); + } + + @Override + public List getLeaderboard() { + return new ArrayList<>(rankings); + } + + @Override + public void updateScore(String username, int score) { + boolean playerFound = false; + + for (PlayerRankingEntry entry : rankings) { + if (entry.getName().equals(username)) { + entry.setScore(score); + playerFound = true; + break; + } + } + + if (!playerFound) { + rankings.add(new PlayerRankingEntry(username, score, 0, false)); + } + + saveRankings(); + } + + @Override + public void updateRankingData(String username, int score, int daysSurvived, boolean won) { + boolean playerFound = false; + + for (PlayerRankingEntry entry : rankings) { + if (entry.getName().equals(username)) { + entry.setScore(score); + entry.setDaysSurvived(daysSurvived); + entry.setWon(won); + playerFound = true; + break; + } + } + + if (!playerFound) { + rankings.add(new PlayerRankingEntry(username, score, daysSurvived, won)); + } + + saveRankings(); + } + + private void saveRankings() { + try { + database.save(rankings); + reloadData(); + } + catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public void reloadData() throws IOException { + this.rankings = new ArrayList<>(database.load()); + } +} diff --git a/src/main/java/frameworks/database/JsonRankingRepository.java b/src/main/java/frameworks/database/JsonRankingRepository.java new file mode 100644 index 000000000..0ec5113da --- /dev/null +++ b/src/main/java/frameworks/database/JsonRankingRepository.java @@ -0,0 +1,43 @@ +package frameworks.database; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.core.type.TypeReference; +import entities.PlayerRankingEntry; +import interface_adapters.gateways.RankingRepository; + +/** + * A JSON-based implementation of the RankingRepository interface. + */ + +public class JsonRankingRepository implements RankingRepository { + private final FileDatabase database; + private List rankings; + + public JsonRankingRepository(String filePath) throws IOException { + this.database = new FileDatabase<>(filePath, new TypeReference>() { }); + this.rankings = database.load(); + } + + @Override + public List getAllRankings() { + return new ArrayList<>(rankings); + } + /** + * Adds a new ranking entry to the repository and persists it to the database. + * + * @param rankingEntry The {@link PlayerRankingEntry} object to be added to the rankings list. + */ + + public void addRanking(PlayerRankingEntry rankingEntry) { + rankings.add(rankingEntry); + try { + database.save(rankings); + } + catch (IOException ioException) { + ioException.printStackTrace(); + } + } +} diff --git a/src/main/java/frameworks/database/JsonSignupDataAccess.java b/src/main/java/frameworks/database/JsonSignupDataAccess.java new file mode 100644 index 000000000..e8adaf644 --- /dev/null +++ b/src/main/java/frameworks/database/JsonSignupDataAccess.java @@ -0,0 +1,105 @@ +package frameworks.database; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.core.type.TypeReference; +import entities.Player; +import usecases.accountsignup.SignupDataAccessInterface; + +/** + * A JSON-based implementation of the PlayerRepository interface. + */ +public class JsonSignupDataAccess implements SignupDataAccessInterface { + private final FileDatabase database; + private List players; + + /** + * Constructs a JsonSignupDataAccess instance and loads the players from the specified file. + * + * @param filePath The file path for the player database. + * @throws IOException If an I/O error occurs while loading the file. + */ + public JsonSignupDataAccess(String filePath) throws IOException { + this.database = new FileDatabase<>(filePath, new TypeReference>() {}); + // Ensure players is mutable + this.players = new ArrayList<>(database.load()); + System.out.println("Loaded players: " + players); + } + + /** + * Finds a player by their username. + * + * @param username The username to search for. + * @return The Player object if found, or null if no player with the given username exists. + */ + public Player findByUsername(String username) { + return players.stream() + .filter(player -> player.getUsername().equals(username)) + .findFirst() + .orElse(null); + } + + @Override + public boolean isUsernameTaken(String username) { + final Player found = findByUsername(username); + return found != null; + } + + /** + * Generates a unique player ID based on the provided username and password. + * + * This method combines the username and password into a single string and applies + * the SHA-256 hashing algorithm to generate a unique, fixed-length player ID. + * + * @param username The player's username. + * @param password The player's password. + * @return A unique player ID as a hexadecimal string. + * @throws RuntimeException If the SHA-256 hashing algorithm is not available. + */ + public static String generatePlayerID(String username, String password) { + try { + // Combine username and password + final String input = username + ":" + password; + + // Create SHA-256 hash + final MessageDigest digest = MessageDigest.getInstance("SHA-256"); + final byte[] hashBytes = digest.digest(input.getBytes(StandardCharsets.UTF_8)); + + // Convert byte array to hexadecimal string + final StringBuilder hexString = new StringBuilder(); + for (byte b : hashBytes) { + final String hex = Integer.toHexString(255 & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + // Return hashed ID + return hexString.toString(); + } + catch (NoSuchAlgorithmException e) { + throw new RuntimeException("Error generating player ID: " + e.getMessage(), e); + } + } + + @Override + public void addUser(String username, String password) { + if (isUsernameTaken(username)) { + throw new IllegalArgumentException("The username is already taken."); + } + + players.add(new Player(generatePlayerID(username, password), username, password)); + + try { + database.save(players); + } catch (IOException ioException) { + ioException.printStackTrace(); + } + } + +} diff --git a/src/main/java/interface_adapter/ViewModel.java b/src/main/java/interface_adapter/ViewModel.java deleted file mode 100644 index 130d797a1..000000000 --- a/src/main/java/interface_adapter/ViewModel.java +++ /dev/null @@ -1,63 +0,0 @@ -package interface_adapter; - -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; - -/** - * The ViewModel for our CA implementation. - * This class delegates work to a PropertyChangeSupport object for - * managing the property change events. - * - * @param The type of state object contained in the model. - */ -public class ViewModel { - - private final String viewName; - - private final PropertyChangeSupport support = new PropertyChangeSupport(this); - - private T state; - - public ViewModel(String viewName) { - this.viewName = viewName; - } - - public String getViewName() { - return this.viewName; - } - - public T getState() { - return this.state; - } - - public void setState(T state) { - this.state = state; - } - - /** - * Fires a property changed event for the state of this ViewModel. - */ - public void firePropertyChanged() { - this.support.firePropertyChange("state", null, this.state); - } - - /** - * Fires a property changed event for the state of this ViewModel, which - * allows the user to specify a different propertyName. This can be useful - * when a class is listening for multiple kinds of property changes. - *

For example, the LoggedInView listens for two kinds of property changes; - * it can use the property name to distinguish which property has changed.

- * @param propertyName the label for the property that was changed - */ - public void firePropertyChanged(String propertyName) { - this.support.firePropertyChange(propertyName, null, this.state); - } - - /** - * Adds a PropertyChangeListener to this ViewModel. - * @param listener The PropertyChangeListener to be added - */ - public void addPropertyChangeListener(PropertyChangeListener listener) { - this.support.addPropertyChangeListener(listener); - } -} diff --git a/src/main/java/interface_adapter/note/NoteController.java b/src/main/java/interface_adapter/note/NoteController.java deleted file mode 100644 index e3e5dfb32..000000000 --- a/src/main/java/interface_adapter/note/NoteController.java +++ /dev/null @@ -1,28 +0,0 @@ -package interface_adapter.note; - -import use_case.note.NoteInputBoundary; - -/** - * Controller for our Note related Use Cases. - */ -public class NoteController { - - private final NoteInputBoundary noteInteractor; - - public NoteController(NoteInputBoundary noteInteractor) { - this.noteInteractor = noteInteractor; - } - - /** - * Executes the Note related Use Cases. - * @param note the note to be recorded - */ - public void execute(String note) { - if (note != null) { - noteInteractor.executeSave(note); - } - else { - noteInteractor.executeRefresh(); - } - } -} diff --git a/src/main/java/interface_adapter/note/NotePresenter.java b/src/main/java/interface_adapter/note/NotePresenter.java deleted file mode 100644 index d4e416165..000000000 --- a/src/main/java/interface_adapter/note/NotePresenter.java +++ /dev/null @@ -1,38 +0,0 @@ -package interface_adapter.note; - -import use_case.note.NoteOutputBoundary; - -/** - * The presenter for our Note viewing and editing program. - */ -public class NotePresenter implements NoteOutputBoundary { - - private final NoteViewModel noteViewModel; - - public NotePresenter(NoteViewModel noteViewModel) { - this.noteViewModel = noteViewModel; - } - - /** - * Prepares the success view for the Note related Use Cases. - * - * @param note the output data - */ - @Override - public void prepareSuccessView(String note) { - noteViewModel.getState().setNote(note); - noteViewModel.getState().setError(null); - noteViewModel.firePropertyChanged(); - } - - /** - * Prepares the failure view for the Note related Use Cases. - * - * @param errorMessage the explanation of the failure - */ - @Override - public void prepareFailView(String errorMessage) { - noteViewModel.getState().setError(errorMessage); - noteViewModel.firePropertyChanged(); - } -} diff --git a/src/main/java/interface_adapter/note/NoteState.java b/src/main/java/interface_adapter/note/NoteState.java deleted file mode 100644 index c5b2234d6..000000000 --- a/src/main/java/interface_adapter/note/NoteState.java +++ /dev/null @@ -1,26 +0,0 @@ -package interface_adapter.note; - -/** - * The State for a note. - *

For this example, a note is simplay a string.

- */ -public class NoteState { - private String note = ""; - private String error; - - public String getNote() { - return note; - } - - public void setNote(String note) { - this.note = note; - } - - public void setError(String errorMessage) { - this.error = errorMessage; - } - - public String getError() { - return error; - } -} diff --git a/src/main/java/interface_adapter/note/NoteViewModel.java b/src/main/java/interface_adapter/note/NoteViewModel.java deleted file mode 100644 index 6e185d0fa..000000000 --- a/src/main/java/interface_adapter/note/NoteViewModel.java +++ /dev/null @@ -1,13 +0,0 @@ -package interface_adapter.note; - -import interface_adapter.ViewModel; - -/** - * The ViewModel for the NoteView. - */ -public class NoteViewModel extends ViewModel { - public NoteViewModel() { - super("note"); - setState(new NoteState()); - } -} diff --git a/src/main/java/interface_adapters/EventManager.java b/src/main/java/interface_adapters/EventManager.java new file mode 100644 index 000000000..7f82489e4 --- /dev/null +++ b/src/main/java/interface_adapters/EventManager.java @@ -0,0 +1,58 @@ +package interface_adapters; + +import interface_adapters.eventrespond.ambush.AmbushResponseController; +import interface_adapters.eventrespond.blizzard.BlizzardResponseController; +import interface_adapters.eventrespond.flood.FloodResponseController; +import interface_adapters.eventrespond.survivor.SurvivorResponseController; +import interface_adapters.eventrespond.trader.TraderResponseController; + +public class EventManager { + private String ActiveEvent; + private final AmbushResponseController ambushResponseController; + private final BlizzardResponseController blizzardResponseController; + private final FloodResponseController floodResponseController; + private final SurvivorResponseController survivorResponseController; + private final TraderResponseController traderResponseController; + + public EventManager(AmbushResponseController ambushResponseController, + BlizzardResponseController blizzardResponseController, + FloodResponseController floodResponseController, + SurvivorResponseController survivorResponseController, + TraderResponseController traderResponseController) { + this.ActiveEvent = ""; + this.ambushResponseController = ambushResponseController; + this.blizzardResponseController = blizzardResponseController; + this.floodResponseController = floodResponseController; + this.survivorResponseController = survivorResponseController; + this.traderResponseController = traderResponseController; + } + public void setActiveEvent(String activeEvent) { + this.ActiveEvent = activeEvent; + } + + public void execute(int choice) { + if (ActiveEvent.equals("Ambush")) { + System.out.println("processing ambush"); + ambushResponseController.execute(choice); + } + else if (ActiveEvent.equals("Blizzard")) { + System.out.println("processing blizzard"); + blizzardResponseController.execute(choice); + } + else if (ActiveEvent.equals("Flood")) { + System.out.println("Processing flood"); + floodResponseController.execute(choice); + } + else if (ActiveEvent.equals("SurvivorsJoins")) { + System.out.println("processing survivor"); + survivorResponseController.execute(choice); + } + else if (ActiveEvent.equals("TradeEncounter")) { + System.out.println("processing trader"); + traderResponseController.execute(choice); + } + else { + System.out.println("Unknown event: " + ActiveEvent); + } + } +} diff --git a/src/main/java/interface_adapters/NavigationManager.java b/src/main/java/interface_adapters/NavigationManager.java new file mode 100644 index 000000000..202755d9e --- /dev/null +++ b/src/main/java/interface_adapters/NavigationManager.java @@ -0,0 +1,79 @@ +package interface_adapters; + +import view.*; + +public class NavigationManager { + private final MainView mainView; + private final CharacterCreationView characterCreationView; + private final GameView gameView; + private final EventView eventView; + private final InformationView informationView; + private final GameOverView gameOverView; + + public NavigationManager(MainView mainView, + CharacterCreationView characterCreationView, GameView gameView, EventView eventView, + InformationView informationView, GameOverView gameOverView) { + this.mainView = mainView; + this.characterCreationView = characterCreationView; + this.gameView = gameView; + this.eventView = eventView; + this.informationView = informationView; + this.gameOverView = gameOverView; + } + + public void showMainView() { + mainView.render(); + characterCreationView.disrender(); + gameView.disrender(); + eventView.disrender(); + informationView.disrender(); + gameOverView.disrender(); + } + + public void showCharacterCreationView() { + mainView.disrender(); + characterCreationView.render(); + gameView.disrender(); + eventView.disrender(); + informationView.disrender(); + gameOverView.disrender(); + System.out.println("Attribute view created"); + } + + public void showEventView() { + mainView.disrender(); + characterCreationView.disrender(); + gameView.disrender(); + eventView.render(); + informationView.disrender(); + gameOverView.disrender(); + } + + public void showGameView() { + mainView.disrender(); + characterCreationView.disrender(); + gameView.render(); + eventView.disrender(); + informationView.disrender(); + gameOverView.disrender(); + } + + public void showInformationView() { + mainView.disrender(); + characterCreationView.disrender(); + gameView.disrender(); + eventView.disrender(); + informationView.render(); + gameOverView.disrender(); + } + + public void showGameOverView() { + mainView.disrender(); + characterCreationView.disrender(); + gameView.disrender(); + eventView.disrender(); + informationView.disrender(); + gameOverView.render(); + } + +} diff --git a/src/main/java/interface_adapters/NavigationManagerJson.java b/src/main/java/interface_adapters/NavigationManagerJson.java new file mode 100644 index 000000000..eaab3fa27 --- /dev/null +++ b/src/main/java/interface_adapters/NavigationManagerJson.java @@ -0,0 +1,45 @@ +package interface_adapters; + +import view.*; + +public class NavigationManagerJson { + private final LoginView loginView; + private final SignUpView signUpView; + private final RankingView rankingView; + private final MainView mainView; + + public NavigationManagerJson(LoginView loginView, SignUpView signUpView, MainView mainView, RankingView rankingView) { + this.loginView = loginView; + this.signUpView = signUpView; + this.mainView = mainView; + this.rankingView = rankingView; + } + + public void showLoginView() { + loginView.render(); + signUpView.disrender(); + mainView.disrender(); + rankingView.disrender(); + } + + public void showSignUpView() { + loginView.disrender(); + signUpView.render(); + mainView.disrender(); + rankingView.disrender(); + } + + public void showMainView() { + loginView.disrender(); + signUpView.disrender(); + mainView.render(); + rankingView.disrender(); + } + + public void showRankingView() { + loginView.disrender(); + signUpView.disrender(); + mainView.disrender(); + rankingView.render(); + } +} diff --git a/src/main/java/interface_adapters/broadcast/BroadcastController.java b/src/main/java/interface_adapters/broadcast/BroadcastController.java new file mode 100644 index 000000000..de2de6d0a --- /dev/null +++ b/src/main/java/interface_adapters/broadcast/BroadcastController.java @@ -0,0 +1,29 @@ +package interface_adapters.broadcast; + +import usecases.dailybroadcast.BroadcastInputBoundary; +import usecases.dailybroadcast.BroadcastInputData; + +/** + * The BroadcastController class is responsible for handling user input for broadcasts. + * It acts as a bridge between the UI and the broadcast use case. + */ +public class BroadcastController { + private final BroadcastInputBoundary inputBoundary; + + /** + * Constructs a BroadcastController with the given input boundary. + * + * @param inputBoundary The use case input boundary for broadcasts. + */ + public BroadcastController(BroadcastInputBoundary inputBoundary) { + this.inputBoundary = inputBoundary; + } + + /** + * Handles the broadcast action by invoking the use case with the provided type. + */ + public void execute() { + final BroadcastInputData inputData = new BroadcastInputData(); + inputBoundary.execute(inputData); + } +} diff --git a/src/main/java/interface_adapters/broadcast/BroadcastInterface.java b/src/main/java/interface_adapters/broadcast/BroadcastInterface.java new file mode 100644 index 000000000..101da970a --- /dev/null +++ b/src/main/java/interface_adapters/broadcast/BroadcastInterface.java @@ -0,0 +1,20 @@ +package interface_adapters.broadcast; + +/** + * Interface for broadcast view, ensures the UI adheres to this contract. + */ +public interface BroadcastInterface { + /** + * Updates the UI with the successful broadcast result. + * + * @param message The result message of the broadcast. + */ + void updateUiBroadcast(String message); + + /** + * Updates the UI with the error message in case of failure. + * + * @param errorMessage The error message indicating the failure reason. + */ + void failureBroadcast(String errorMessage); +} diff --git a/src/main/java/interface_adapters/broadcast/BroadcastPresenter.java b/src/main/java/interface_adapters/broadcast/BroadcastPresenter.java new file mode 100644 index 000000000..374738e76 --- /dev/null +++ b/src/main/java/interface_adapters/broadcast/BroadcastPresenter.java @@ -0,0 +1,38 @@ +package interface_adapters.broadcast; + +import usecases.dailybroadcast.BroadcastOutputBoundary; +import usecases.dailybroadcast.BroadcastOutputData; + +/** + * The BroadcastPresenter class processes use case output for the broadcast + * and converts it into a format suitable for the UI. + */ +public class BroadcastPresenter implements BroadcastOutputBoundary { + private final BroadcastInterface view; + + public BroadcastPresenter(BroadcastInterface view) { + this.view = view; + } + + /** + * Prepares the success view for the broadcast. + * + * @param outputData The output data from the broadcast use case. + */ + @Override + public void prepareSuccessView(BroadcastOutputData outputData) { + view.updateUiBroadcast( + outputData.getResultMessage() + ); + } + + /** + * Prepares the failure view for the broadcast. + * + * @param errorMessage The error message indicating why the broadcast failed. + */ + @Override + public void prepareFailureView(String errorMessage) { + view.failureBroadcast(errorMessage); + } +} diff --git a/src/main/java/interface_adapters/dailygather/DailyGatherController.java b/src/main/java/interface_adapters/dailygather/DailyGatherController.java new file mode 100644 index 000000000..2ee19e071 --- /dev/null +++ b/src/main/java/interface_adapters/dailygather/DailyGatherController.java @@ -0,0 +1,23 @@ +package interface_adapters.dailygather; + +import usecases.dailygather.GatherInputBoundary; +import usecases.dailygather.GatherInputData; + +/** + * Controller of gather usecase. + */ +public class DailyGatherController { + private GatherInputBoundary gatherUsecaseInteractor; + + public DailyGatherController(GatherInputBoundary gatherUsecaseInteractor) { + this.gatherUsecaseInteractor = gatherUsecaseInteractor; + } + + /** + * Execute and call the interactor in gather. + */ + public void execute() { + final GatherInputData inputdata = new GatherInputData(); + gatherUsecaseInteractor.execute(inputdata); + } +} diff --git a/src/main/java/interface_adapters/dailygather/DailyGatherInterface.java b/src/main/java/interface_adapters/dailygather/DailyGatherInterface.java new file mode 100644 index 000000000..a90416611 --- /dev/null +++ b/src/main/java/interface_adapters/dailygather/DailyGatherInterface.java @@ -0,0 +1,19 @@ +package interface_adapters.dailygather; + +/** + * Interface of daily gather, suppose to be implement by the view. + */ +public interface DailyGatherInterface { + + /** + * All the stuff we have to display and update at this point. Ne wmessage, and updated resource. + * @param message message for the gather. + */ + void updateUiGather(String message); + + /** + * No need to update resource, or anything except the error message telling play why this is invaild move. + * @param message errormessage. + */ + void failureGather(String message); +} diff --git a/src/main/java/interface_adapters/dailygather/DailyGatherPresenter.java b/src/main/java/interface_adapters/dailygather/DailyGatherPresenter.java new file mode 100644 index 000000000..116903371 --- /dev/null +++ b/src/main/java/interface_adapters/dailygather/DailyGatherPresenter.java @@ -0,0 +1,25 @@ +package interface_adapters.dailygather; + +import usecases.dailygather.GatherOutputBoundary; +import usecases.dailygather.GatherOutputData; + +/** + * Daily gather usecase presentor. + */ +public class DailyGatherPresenter implements GatherOutputBoundary { + private DailyGatherInterface view; + + public DailyGatherPresenter(DailyGatherInterface view) { + this.view = view; + } + + @Override + public void prepareSuccessView(GatherOutputData outputdata) { + view.updateUiGather(outputdata.getSuccessmessage()); + } + + @Override + public void prepareFailureView(String errorMessage) { + view.failureGather(errorMessage); + } +} diff --git a/src/main/java/interface_adapters/dailymove/DailyMoveController.java b/src/main/java/interface_adapters/dailymove/DailyMoveController.java new file mode 100644 index 000000000..74b4ae46c --- /dev/null +++ b/src/main/java/interface_adapters/dailymove/DailyMoveController.java @@ -0,0 +1,24 @@ +package interface_adapters.dailymove; + +import usecases.dailymove.MoveInputBoundary; +import usecases.dailymove.MoveInputData; + +/** + * Move controller, used to make player input into inputdata type for move usecase. + */ +public class DailyMoveController { + private MoveInputBoundary moveInteractor; + + public DailyMoveController(MoveInputBoundary moveInteractor) { + this.moveInteractor = moveInteractor; + } + + /** + * Serve as execute the interactor by converting player input raw data to inputdata type. + * @param direction direction player inputed. + */ + public void execute(String direction) { + final MoveInputData inputdata = new MoveInputData(direction); + moveInteractor.execute(inputdata); + } +} diff --git a/src/main/java/interface_adapters/dailymove/DailyMoveInterface.java b/src/main/java/interface_adapters/dailymove/DailyMoveInterface.java new file mode 100644 index 000000000..1b4e44162 --- /dev/null +++ b/src/main/java/interface_adapters/dailymove/DailyMoveInterface.java @@ -0,0 +1,21 @@ +package interface_adapters.dailymove; + +import java.util.ArrayList; + +/** + * Move interface usecase for communicate with view in not direct or hard dependent way. + */ +public interface DailyMoveInterface { + + /** + * Update the minimap after move use case with the nested arraylist of single letter string. + * @param message description telling you moved. + */ + void updateUiMove(String message); + + /** + * Don;t update or change anything if usecase failed, display the error message to player only. + * @param errormessage Error message. + */ + void failureMove(String errormessage); +} diff --git a/src/main/java/interface_adapters/dailymove/DailyMovePresenter.java b/src/main/java/interface_adapters/dailymove/DailyMovePresenter.java new file mode 100644 index 000000000..09f6d0cca --- /dev/null +++ b/src/main/java/interface_adapters/dailymove/DailyMovePresenter.java @@ -0,0 +1,25 @@ +package interface_adapters.dailymove; + +import usecases.dailymove.MoveOutputBoundary; +import usecases.dailymove.MoveOutputData; + +/** + * Presentor of move. + */ +public class DailyMovePresenter implements MoveOutputBoundary { + private DailyMoveInterface view; + + public DailyMovePresenter(DailyMoveInterface view) { + this.view = view; + } + + @Override + public void prepareSuccessView(MoveOutputData outputData) { + view.updateUiMove(outputData.getmessage()); + } + + @Override + public void prepareFailureView(String errorMessage) { + view.failureMove(errorMessage); + } +} diff --git a/src/main/java/interface_adapters/endprocesshorde/HordeController.java b/src/main/java/interface_adapters/endprocesshorde/HordeController.java new file mode 100644 index 000000000..743ead908 --- /dev/null +++ b/src/main/java/interface_adapters/endprocesshorde/HordeController.java @@ -0,0 +1,23 @@ +package interface_adapters.endprocesshorde; + +import usecases.endprocesshorde.HordeInputBoundary; +import usecases.endprocesshorde.HordeInputData; + +/** + * Horde controller, for horde process use case. + */ +public class HordeController { + private final HordeInputBoundary interactor; + + public HordeController(HordeInputBoundary interactor) { + this.interactor = interactor; + } + + /** + * Execute this horde usecase. + */ + public void execute() { + final HordeInputData inputData = new HordeInputData(); + interactor.execute(inputData); + } +} diff --git a/src/main/java/interface_adapters/endprocesshorde/HordeInterface.java b/src/main/java/interface_adapters/endprocesshorde/HordeInterface.java new file mode 100644 index 000000000..1a4f34016 --- /dev/null +++ b/src/main/java/interface_adapters/endprocesshorde/HordeInterface.java @@ -0,0 +1,20 @@ +package interface_adapters.endprocesshorde; + +/** + * Interface for horde process which is on the game over page. + */ +public interface HordeInterface { + + /** + * Update the ui with the info provided on the game over game as summary. + * @param message message of description to what happened. + * @param score score of player get at the end. + */ + void updateUiHorde(String message, int score); + + /** + * If the usecase was failed, explain why is it failed. + * @param failmessage fail message. + */ + void failureHorde(String failmessage); +} diff --git a/src/main/java/interface_adapters/endprocesshorde/HordeInterfaceNavigate.java b/src/main/java/interface_adapters/endprocesshorde/HordeInterfaceNavigate.java new file mode 100644 index 000000000..63f1bed32 --- /dev/null +++ b/src/main/java/interface_adapters/endprocesshorde/HordeInterfaceNavigate.java @@ -0,0 +1,7 @@ +package interface_adapters.endprocesshorde; + +import interface_adapters.NavigationManager; + +public interface HordeInterfaceNavigate { + void NavigateHordeGameOver(NavigationManager manager); +} diff --git a/src/main/java/interface_adapters/endprocesshorde/HordePresenter.java b/src/main/java/interface_adapters/endprocesshorde/HordePresenter.java new file mode 100644 index 000000000..f0f684425 --- /dev/null +++ b/src/main/java/interface_adapters/endprocesshorde/HordePresenter.java @@ -0,0 +1,31 @@ +package interface_adapters.endprocesshorde; + +import interface_adapters.NavigationManager; +import usecases.endprocesshorde.HordeOutputBoundary; +import usecases.endprocesshorde.HordeOutputData; + +/** + * Horde presenter. + */ +public class HordePresenter implements HordeOutputBoundary { + private final HordeInterface newview; + private final NavigationManager navigationManager; + private final HordeInterfaceNavigate view; + + public HordePresenter(HordeInterface newview, NavigationManager navigationManager, HordeInterfaceNavigate view) { + this.newview = newview; + this.navigationManager = navigationManager; + this.view = view; + } + + @Override + public void prepareSuccessView(HordeOutputData outputData) { + view.NavigateHordeGameOver(navigationManager); + newview.updateUiHorde(outputData.getIntroduction(), outputData.getPoints()); + } + + @Override + public void prepareFailureView(String errorMessage) { + newview.failureHorde(errorMessage); + } +} diff --git a/src/main/java/interface_adapters/eventdecide/EventDecideController.java b/src/main/java/interface_adapters/eventdecide/EventDecideController.java new file mode 100644 index 000000000..45e1c826a --- /dev/null +++ b/src/main/java/interface_adapters/eventdecide/EventDecideController.java @@ -0,0 +1,23 @@ +package interface_adapters.eventdecide; + +import usecases.eventdecide.DecideEventInputBoundary; +import usecases.eventdecide.DecideEventInputData; + +/** + * Event deside controller + */ +public class EventDecideController { + private DecideEventInputBoundary interactor; + + public EventDecideController(DecideEventInputBoundary interactor) { + this.interactor = interactor; + } + + /** + * Execute. + */ + public void execute() { + final DecideEventInputData inputData = new DecideEventInputData(); + interactor.execute(inputData); + } +} diff --git a/src/main/java/interface_adapters/eventdecide/EventDecideInterface.java b/src/main/java/interface_adapters/eventdecide/EventDecideInterface.java new file mode 100644 index 000000000..6cb6b6e2c --- /dev/null +++ b/src/main/java/interface_adapters/eventdecide/EventDecideInterface.java @@ -0,0 +1,21 @@ +package interface_adapters.eventdecide; + +import java.util.ArrayList; + +/** + * Interface of event decide. + */ +public interface EventDecideInterface { + + /** + * Update the UI event decide "Event happened today:", or not event at all. + * @param eventNames name of the events chose. + */ + void updateUiEventDecide(ArrayList eventNames); + + /** + * In case something went wrong. + * @param errorMessage error description. + */ + void failureEventDecide(String errorMessage); +} diff --git a/src/main/java/interface_adapters/eventdecide/EventDecidePresenter.java b/src/main/java/interface_adapters/eventdecide/EventDecidePresenter.java new file mode 100644 index 000000000..eac334167 --- /dev/null +++ b/src/main/java/interface_adapters/eventdecide/EventDecidePresenter.java @@ -0,0 +1,28 @@ +package interface_adapters.eventdecide; + +import java.util.ArrayList; + +import usecases.eventdecide.DecideEventOutputBoundary; +import usecases.eventdecide.DecideEventOutputData; + +/** + * Event decider presenter. + */ +public class EventDecidePresenter implements DecideEventOutputBoundary { + private final EventDecideInterface view; + + public EventDecidePresenter(EventDecideInterface view) { + this.view = view; + } + + @Override + public void prepareSuccessView(DecideEventOutputData outputData) { + final ArrayList events = outputData.getEvents(); + view.updateUiEventDecide(events); + } + + @Override + public void prepareFailureView(String errorMessage) { + view.failureEventDecide(errorMessage); + } +} diff --git a/src/main/java/interface_adapters/eventinitializer/EventInitializerController.java b/src/main/java/interface_adapters/eventinitializer/EventInitializerController.java new file mode 100644 index 000000000..8c88b3512 --- /dev/null +++ b/src/main/java/interface_adapters/eventinitializer/EventInitializerController.java @@ -0,0 +1,23 @@ +package interface_adapters.eventinitializer; + +import usecases.eventinitialize.EventInitializeInputBoundary; +import usecases.eventinitialize.EventInitializeInputData; + +/** + * Event initializer controller. + */ +public class EventInitializerController { + private EventInitializeInputBoundary interactor; + + public EventInitializerController(EventInitializeInputBoundary interactor) { + this.interactor = interactor; + } + + /** + * Execute with input data provided, not needed. + */ + public void execute() { + final EventInitializeInputData inputData = new EventInitializeInputData(); + interactor.execute(inputData); + } +} diff --git a/src/main/java/interface_adapters/eventinitializer/EventInitializerInterface.java b/src/main/java/interface_adapters/eventinitializer/EventInitializerInterface.java new file mode 100644 index 000000000..8b642e269 --- /dev/null +++ b/src/main/java/interface_adapters/eventinitializer/EventInitializerInterface.java @@ -0,0 +1,22 @@ +package interface_adapters.eventinitializer; + +/** + * Interface for presenter talking to view. + */ +public interface EventInitializerInterface { + + /** + * Update the event page by update the description, and options for the buttons. + * @param eventdescription Description of the event. + * @param option1 option 1 + * @param option2 option 2 + * @param option3 option 3 + */ + void updateUiEventInitializer(String eventdescription, String option1, String option2, String option3); + + /** + * Update the event page by saying no event at that day or something else is going on. + * @param failmessage fail message. + */ + void failureEventInitializer(String failmessage); +} diff --git a/src/main/java/interface_adapters/eventinitializer/EventInitializerPresenter.java b/src/main/java/interface_adapters/eventinitializer/EventInitializerPresenter.java new file mode 100644 index 000000000..12bc0a9f7 --- /dev/null +++ b/src/main/java/interface_adapters/eventinitializer/EventInitializerPresenter.java @@ -0,0 +1,29 @@ +package interface_adapters.eventinitializer; + +import usecases.eventinitialize.EventInitializeOutputBoundary; +import usecases.eventinitialize.EventInitializeOutputData; + +/** + * Event Initialize presenter. + */ +public class EventInitializerPresenter implements EventInitializeOutputBoundary { + private EventInitializerInterface view; + + public EventInitializerPresenter(EventInitializerInterface view) { + this.view = view; + } + + @Override + public void prepareSuccessView(EventInitializeOutputData outputData) { + final String description = outputData.getDescription(); + final String choice1 = outputData.getChoice(1); + final String choice2 = outputData.getChoice(2); + final String choice3 = outputData.getChoice(3); + view.updateUiEventInitializer(description, choice1, choice2, choice3); + } + + @Override + public void prepareFailureView(String errorMessage) { + view.failureEventInitializer(errorMessage); + } +} diff --git a/src/main/java/interface_adapters/eventrespond/ambush/AmbushResponseController.java b/src/main/java/interface_adapters/eventrespond/ambush/AmbushResponseController.java new file mode 100644 index 000000000..35cc4532f --- /dev/null +++ b/src/main/java/interface_adapters/eventrespond/ambush/AmbushResponseController.java @@ -0,0 +1,24 @@ +package interface_adapters.eventrespond.ambush; + +import usecases.eventrespond.ambush.AmbushEventInteractor; +import usecases.eventrespond.ambush.AmbushInputData; + +/** + * Controller for handling responses to an Ambush event. + */ +public class AmbushResponseController { + private final AmbushEventInteractor interactor; + + public AmbushResponseController(AmbushEventInteractor interactor) { + this.interactor = interactor; + } + + /** + * Execute the interactor by converting the player’s input into input data. + * @param choice The player's choice for the event. + */ + public void execute(int choice) { + AmbushInputData inputData = new AmbushInputData(choice); // Using AmbushInputData now + interactor.execute(inputData); + } +} diff --git a/src/main/java/interface_adapters/eventrespond/ambush/AmbushResponseInterface.java b/src/main/java/interface_adapters/eventrespond/ambush/AmbushResponseInterface.java new file mode 100644 index 000000000..90abfb937 --- /dev/null +++ b/src/main/java/interface_adapters/eventrespond/ambush/AmbushResponseInterface.java @@ -0,0 +1,10 @@ +package interface_adapters.eventrespond.ambush; + +/** + * Interface for updating the UI for an Ambush event. + */ +public interface AmbushResponseInterface { + void updateUiResponse(String message); + + void failureResponse(String errorMessage); +} diff --git a/src/main/java/interface_adapters/eventrespond/ambush/AmbushResponsePresenter.java b/src/main/java/interface_adapters/eventrespond/ambush/AmbushResponsePresenter.java new file mode 100644 index 000000000..c9efde63b --- /dev/null +++ b/src/main/java/interface_adapters/eventrespond/ambush/AmbushResponsePresenter.java @@ -0,0 +1,26 @@ +package interface_adapters.eventrespond.ambush; + +import usecases.eventrespond.ambush.AmbushOutputBoundary; +import usecases.eventrespond.ambush.AmbushOutputData; + +/** + * Presenter for handling the response output of an Ambush event. + */ +public class AmbushResponsePresenter implements AmbushOutputBoundary { + private final AmbushResponseInterface view; + + public AmbushResponsePresenter(AmbushResponseInterface view) { + this.view = view; + } + + @Override + public void prepareSuccessView(AmbushOutputData outputData) { + // Pass the message and relevant details to the view + view.updateUiResponse(outputData.getMessage()); // Updated method based on new event-specific data + } + + @Override + public void prepareFailureView(String errorMessage) { + view.failureResponse(errorMessage); // Handle failure case + } +} diff --git a/src/main/java/interface_adapters/eventrespond/blizzard/BlizzardResponseController.java b/src/main/java/interface_adapters/eventrespond/blizzard/BlizzardResponseController.java new file mode 100644 index 000000000..90a3f448b --- /dev/null +++ b/src/main/java/interface_adapters/eventrespond/blizzard/BlizzardResponseController.java @@ -0,0 +1,24 @@ +package interface_adapters.eventrespond.blizzard; + +import usecases.eventrespond.blizzard.BlizzardEventInteractor; +import usecases.eventrespond.blizzard.BlizzardInputData; + +/** + * Controller for handling responses to a Blizzard event. + */ +public class BlizzardResponseController { + private final BlizzardEventInteractor interactor; + + public BlizzardResponseController(BlizzardEventInteractor interactor) { + this.interactor = interactor; + } + + /** + * Execute the interactor by converting the player’s input into input data. + * @param choice The player's choice for the event. + */ + public void execute(int choice) { + BlizzardInputData inputData = new BlizzardInputData(choice); // Using BlizzardInputData now + interactor.execute(inputData); + } +} diff --git a/src/main/java/interface_adapters/eventrespond/blizzard/BlizzardResponseInterface.java b/src/main/java/interface_adapters/eventrespond/blizzard/BlizzardResponseInterface.java new file mode 100644 index 000000000..c100ab32f --- /dev/null +++ b/src/main/java/interface_adapters/eventrespond/blizzard/BlizzardResponseInterface.java @@ -0,0 +1,10 @@ +package interface_adapters.eventrespond.blizzard; + +/** + * Interface for updating the UI for a Blizzard event. + */ +public interface BlizzardResponseInterface { + void updateUiResponse(String message); // Message to update UI with + + void failureResponse(String errorMessage); // Handle failure cases +} diff --git a/src/main/java/interface_adapters/eventrespond/blizzard/BlizzardResponsePresenter.java b/src/main/java/interface_adapters/eventrespond/blizzard/BlizzardResponsePresenter.java new file mode 100644 index 000000000..0e5032816 --- /dev/null +++ b/src/main/java/interface_adapters/eventrespond/blizzard/BlizzardResponsePresenter.java @@ -0,0 +1,26 @@ +package interface_adapters.eventrespond.blizzard; + +import usecases.eventrespond.blizzard.BlizzardOutputBoundary; +import usecases.eventrespond.blizzard.BlizzardOutputData; + +/** + * Presenter for handling the response output of a Blizzard event. + */ +public class BlizzardResponsePresenter implements BlizzardOutputBoundary { + private final BlizzardResponseInterface view; + + public BlizzardResponsePresenter(BlizzardResponseInterface view) { + this.view = view; + } + + @Override + public void prepareSuccessView(BlizzardOutputData outputData) { + // Pass the message and relevant details to the view + view.updateUiResponse(outputData.getMessage()); // Updated method based on new event-specific data + } + + @Override + public void prepareFailureView(String errorMessage) { + view.failureResponse(errorMessage); // Handle failure case + } +} diff --git a/src/main/java/interface_adapters/eventrespond/flood/FloodResponseController.java b/src/main/java/interface_adapters/eventrespond/flood/FloodResponseController.java new file mode 100644 index 000000000..98a7e35f4 --- /dev/null +++ b/src/main/java/interface_adapters/eventrespond/flood/FloodResponseController.java @@ -0,0 +1,24 @@ +package interface_adapters.eventrespond.flood; + +import usecases.eventrespond.flood.FloodEventInteractor; +import usecases.eventrespond.flood.FloodInputData; + +/** + * Controller for handling responses to a Flood event. + */ +public class FloodResponseController { + private final FloodEventInteractor interactor; + + public FloodResponseController(FloodEventInteractor interactor) { + this.interactor = interactor; + } + + /** + * Execute the interactor by converting the player’s input into input data. + * @param choice The player's choice for the event. + */ + public void execute(int choice) { + FloodInputData inputData = new FloodInputData(choice); // Using FloodInputData now + interactor.execute(inputData); + } +} diff --git a/src/main/java/interface_adapters/eventrespond/flood/FloodResponseInterface.java b/src/main/java/interface_adapters/eventrespond/flood/FloodResponseInterface.java new file mode 100644 index 000000000..db99b6dcb --- /dev/null +++ b/src/main/java/interface_adapters/eventrespond/flood/FloodResponseInterface.java @@ -0,0 +1,10 @@ +package interface_adapters.eventrespond.flood; + +/** + * Interface for updating the UI for a Flood event. + */ +public interface FloodResponseInterface { + void updateUiResponse(String message); // Update the UI with the event's message + + void failureResponse(String errorMessage); // Handle failure response +} diff --git a/src/main/java/interface_adapters/eventrespond/flood/FloodResponsePresenter.java b/src/main/java/interface_adapters/eventrespond/flood/FloodResponsePresenter.java new file mode 100644 index 000000000..2bb02ea8d --- /dev/null +++ b/src/main/java/interface_adapters/eventrespond/flood/FloodResponsePresenter.java @@ -0,0 +1,26 @@ +package interface_adapters.eventrespond.flood; + +import usecases.eventrespond.flood.FloodOutputBoundary; +import usecases.eventrespond.flood.FloodOutputData; + +/** + * Presenter for handling the response output of a Flood event. + */ +public class FloodResponsePresenter implements FloodOutputBoundary { + private final FloodResponseInterface view; + + public FloodResponsePresenter(FloodResponseInterface view) { + this.view = view; + } + + @Override + public void prepareSuccessView(FloodOutputData outputData) { + // Update the UI with the message from FloodOutputData + view.updateUiResponse(outputData.getMessage()); // Updated to FloodOutputData's message + } + + @Override + public void prepareFailureView(String errorMessage) { + view.failureResponse(errorMessage); // Handle failure case + } +} diff --git a/src/main/java/interface_adapters/eventrespond/survivor/SurvivorResponseController.java b/src/main/java/interface_adapters/eventrespond/survivor/SurvivorResponseController.java new file mode 100644 index 000000000..718bb5719 --- /dev/null +++ b/src/main/java/interface_adapters/eventrespond/survivor/SurvivorResponseController.java @@ -0,0 +1,24 @@ +package interface_adapters.eventrespond.survivor; + +import usecases.eventrespond.survivor.SurvivorEventInteractor; +import usecases.eventrespond.survivor.SurvivorInputData; + +/** + * Controller for handling responses to a Survivor event. + */ +public class SurvivorResponseController { + private final SurvivorEventInteractor interactor; + + public SurvivorResponseController(SurvivorEventInteractor interactor) { + this.interactor = interactor; + } + + /** + * Execute the interactor by converting the player’s input into input data. + * @param choice The player's choice for the event. + */ + public void execute(int choice) { + SurvivorInputData inputData = new SurvivorInputData(choice); // Use SurvivorInputData + interactor.execute(inputData); + } +} diff --git a/src/main/java/interface_adapters/eventrespond/survivor/SurvivorResponseInterface.java b/src/main/java/interface_adapters/eventrespond/survivor/SurvivorResponseInterface.java new file mode 100644 index 000000000..8dc949027 --- /dev/null +++ b/src/main/java/interface_adapters/eventrespond/survivor/SurvivorResponseInterface.java @@ -0,0 +1,10 @@ +package interface_adapters.eventrespond.survivor; + +/** + * Interface for updating the UI for a Survivor event. + */ +public interface SurvivorResponseInterface { + void updateUiResponse(String message); // Update the UI with the event's message + + void failureResponse(String errorMessage); // Handle failure response +} diff --git a/src/main/java/interface_adapters/eventrespond/survivor/SurvivorResponsePresenter.java b/src/main/java/interface_adapters/eventrespond/survivor/SurvivorResponsePresenter.java new file mode 100644 index 000000000..deb326548 --- /dev/null +++ b/src/main/java/interface_adapters/eventrespond/survivor/SurvivorResponsePresenter.java @@ -0,0 +1,26 @@ +package interface_adapters.eventrespond.survivor; + +import usecases.eventrespond.survivor.SurvivorOutputBoundary; +import usecases.eventrespond.survivor.SurvivorOutputData; + +/** + * Presenter for handling the response output of a Survivor event. + */ +public class SurvivorResponsePresenter implements SurvivorOutputBoundary { + private final SurvivorResponseInterface view; + + public SurvivorResponsePresenter(SurvivorResponseInterface view) { + this.view = view; + } + + @Override + public void prepareSuccessView(SurvivorOutputData outputData) { + // Update the UI with the message from SurvivorOutputData + view.updateUiResponse(outputData.getMessage()); + } + + @Override + public void prepareFailureView(String errorMessage) { + view.failureResponse(errorMessage); // Handle failure case + } +} diff --git a/src/main/java/interface_adapters/eventrespond/trader/TraderResponseController.java b/src/main/java/interface_adapters/eventrespond/trader/TraderResponseController.java new file mode 100644 index 000000000..2e9aabe24 --- /dev/null +++ b/src/main/java/interface_adapters/eventrespond/trader/TraderResponseController.java @@ -0,0 +1,24 @@ +package interface_adapters.eventrespond.trader; + +import usecases.eventrespond.trader.TraderEventInteractor; +import usecases.eventrespond.trader.TraderInputData; + +/** + * Controller for handling responses to a Trader event. + */ +public class TraderResponseController { + private final TraderEventInteractor interactor; + + public TraderResponseController(TraderEventInteractor interactor) { + this.interactor = interactor; + } + + /** + * Execute the interactor by converting the player’s input into input data. + * @param choice The player's choice for the event. + */ + public void execute(int choice) { + TraderInputData inputData = new TraderInputData(choice); // Use TraderInputData + interactor.execute(inputData); + } +} diff --git a/src/main/java/interface_adapters/eventrespond/trader/TraderResponseInterface.java b/src/main/java/interface_adapters/eventrespond/trader/TraderResponseInterface.java new file mode 100644 index 000000000..ace9f58e9 --- /dev/null +++ b/src/main/java/interface_adapters/eventrespond/trader/TraderResponseInterface.java @@ -0,0 +1,10 @@ +package interface_adapters.eventrespond.trader; + +/** + * Interface for updating the UI for a Trader event. + */ +public interface TraderResponseInterface { + void updateUiResponse(String message); // Update the UI with the event's message + + void failureResponse(String errorMessage); // Handle failure response +} diff --git a/src/main/java/interface_adapters/eventrespond/trader/TraderResponsePresenter.java b/src/main/java/interface_adapters/eventrespond/trader/TraderResponsePresenter.java new file mode 100644 index 000000000..d4eb34051 --- /dev/null +++ b/src/main/java/interface_adapters/eventrespond/trader/TraderResponsePresenter.java @@ -0,0 +1,26 @@ +package interface_adapters.eventrespond.trader; + +import usecases.eventrespond.trader.TraderOutputBoundary; +import usecases.eventrespond.trader.TraderOutputData; + +/** + * Presenter for handling the response output of a Trader event. + */ +public class TraderResponsePresenter implements TraderOutputBoundary { + private final TraderResponseInterface view; + + public TraderResponsePresenter(TraderResponseInterface view) { + this.view = view; + } + + @Override + public void prepareSuccessView(TraderOutputData outputData) { + // Update the UI with the message from TraderOutputData + view.updateUiResponse(outputData.getMessage()); + } + + @Override + public void prepareFailureView(String errorMessage) { + view.failureResponse(errorMessage); // Handle failure case + } +} diff --git a/src/main/java/interface_adapters/fetchcurrentevent/FetchEventController.java b/src/main/java/interface_adapters/fetchcurrentevent/FetchEventController.java new file mode 100644 index 000000000..d51904dab --- /dev/null +++ b/src/main/java/interface_adapters/fetchcurrentevent/FetchEventController.java @@ -0,0 +1,16 @@ +package interface_adapters.fetchcurrentevent; + +import usecases.fetchcurrentevent.CurrentEventInputBoundary; +import usecases.fetchcurrentevent.CurrentEventInputData; + +public class FetchEventController { + private CurrentEventInputBoundary interactor; + + public FetchEventController(CurrentEventInputBoundary interactor) { + this.interactor = interactor; + } + + public void execute() { + interactor.execute(new CurrentEventInputData()); + } +} diff --git a/src/main/java/interface_adapters/fetchcurrentevent/FetchEventInterface.java b/src/main/java/interface_adapters/fetchcurrentevent/FetchEventInterface.java new file mode 100644 index 000000000..91c11fd87 --- /dev/null +++ b/src/main/java/interface_adapters/fetchcurrentevent/FetchEventInterface.java @@ -0,0 +1,8 @@ +package interface_adapters.fetchcurrentevent; + +/** + * No need to update, just fetch the event. + */ +public interface FetchEventInterface { + void setEventName(String event); +} diff --git a/src/main/java/interface_adapters/fetchcurrentevent/FetchEventPresenter.java b/src/main/java/interface_adapters/fetchcurrentevent/FetchEventPresenter.java new file mode 100644 index 000000000..58b25bb3b --- /dev/null +++ b/src/main/java/interface_adapters/fetchcurrentevent/FetchEventPresenter.java @@ -0,0 +1,17 @@ +package interface_adapters.fetchcurrentevent; + +import usecases.fetchcurrentevent.CurrentEventOutputBoundary; +import usecases.fetchcurrentevent.CurrentEventOutputData; + +public class FetchEventPresenter implements CurrentEventOutputBoundary { + private FetchEventInterface view; + + public FetchEventPresenter(FetchEventInterface view) { + this.view = view; + } + + @Override + public void presentcurrentEvent(CurrentEventOutputData currentEventOutputData) { + view.setEventName(currentEventOutputData.getCurrentEvent().toString()); + } +} diff --git a/src/main/java/interface_adapters/fetchresource/FetchController.java b/src/main/java/interface_adapters/fetchresource/FetchController.java new file mode 100644 index 000000000..6a8212ea0 --- /dev/null +++ b/src/main/java/interface_adapters/fetchresource/FetchController.java @@ -0,0 +1,23 @@ +package interface_adapters.fetchresource; + +import usecases.fetchresource.FetchInputBoundary; +import usecases.fetchresource.FetchInputData; + +/** + * Fetch controller. + */ +public class FetchController { + private FetchInputBoundary fetchInteractor; + + public FetchController(FetchInputBoundary fetchInteractor) { + this.fetchInteractor = fetchInteractor; + } + + /** + * Execute interactor. + */ + public void execute() { + final FetchInputData fetchInputData = new FetchInputData(); + fetchInteractor.execute(fetchInputData); + } +} diff --git a/src/main/java/interface_adapters/fetchresource/FetchInterface.java b/src/main/java/interface_adapters/fetchresource/FetchInterface.java new file mode 100644 index 000000000..a200b7932 --- /dev/null +++ b/src/main/java/interface_adapters/fetchresource/FetchInterface.java @@ -0,0 +1,18 @@ +package interface_adapters.fetchresource; + +/** + * Fetch interface. + */ +public interface FetchInterface { + + /** + * Update the resouce appearing on the UI. + * @param food food + * @param water water + * @param people people + * @param weapon weapon + * @param actionpoint actionpoint left. + * @param day day. + */ + void updateUiResource(int food, int water, int people, int weapon, int day, int actionpoint); +} diff --git a/src/main/java/interface_adapters/fetchresource/FetchPresenter.java b/src/main/java/interface_adapters/fetchresource/FetchPresenter.java new file mode 100644 index 000000000..bd7bb7c6a --- /dev/null +++ b/src/main/java/interface_adapters/fetchresource/FetchPresenter.java @@ -0,0 +1,21 @@ +package interface_adapters.fetchresource; + +import usecases.fetchresource.FetchOutputBoundary; +import usecases.fetchresource.FetchOutputData; + +/** + * Fetch presenter. + */ +public class FetchPresenter implements FetchOutputBoundary { + private FetchInterface view; + + public FetchPresenter(FetchInterface view) { + this.view = view; + } + + @Override + public void prepareSuccessview(FetchOutputData outputdata) { + view.updateUiResource(outputdata.getFood(), outputdata.getWater(), + outputdata.getPeople(), outputdata.getWeapon(), outputdata.getDay(), outputdata.getActionpoint()); + } +} diff --git a/src/main/java/interface_adapters/gamelosedetecter/LoseController.java b/src/main/java/interface_adapters/gamelosedetecter/LoseController.java new file mode 100644 index 000000000..5d7d60843 --- /dev/null +++ b/src/main/java/interface_adapters/gamelosedetecter/LoseController.java @@ -0,0 +1,17 @@ +package interface_adapters.gamelosedetecter; + +import usecases.gamelosedetecter.LoseInputBoundary; +import usecases.gamelosedetecter.LoseInputData; + +public class LoseController { + private LoseInputBoundary interactor; + + public LoseController(LoseInputBoundary interactor) { + this.interactor = interactor; + } + + public void execute() { + final LoseInputData inputData = new LoseInputData(); + interactor.execute(inputData); + } +} diff --git a/src/main/java/interface_adapters/gamelosedetecter/LoseInterface.java b/src/main/java/interface_adapters/gamelosedetecter/LoseInterface.java new file mode 100644 index 000000000..6995b3762 --- /dev/null +++ b/src/main/java/interface_adapters/gamelosedetecter/LoseInterface.java @@ -0,0 +1,6 @@ +package interface_adapters.gamelosedetecter; + +public interface LoseInterface { + + void prepareGameOverEarly(String message, int score); +} diff --git a/src/main/java/interface_adapters/gamelosedetecter/LoseInterfaceNavigate.java b/src/main/java/interface_adapters/gamelosedetecter/LoseInterfaceNavigate.java new file mode 100644 index 000000000..32b4f7c54 --- /dev/null +++ b/src/main/java/interface_adapters/gamelosedetecter/LoseInterfaceNavigate.java @@ -0,0 +1,7 @@ +package interface_adapters.gamelosedetecter; + +import interface_adapters.NavigationManager; + +public interface LoseInterfaceNavigate { + void navigateGameOver(NavigationManager navigationManager); +} diff --git a/src/main/java/interface_adapters/gamelosedetecter/LosePresenter.java b/src/main/java/interface_adapters/gamelosedetecter/LosePresenter.java new file mode 100644 index 000000000..2a9a31b79 --- /dev/null +++ b/src/main/java/interface_adapters/gamelosedetecter/LosePresenter.java @@ -0,0 +1,23 @@ +package interface_adapters.gamelosedetecter; + +import interface_adapters.NavigationManager; +import usecases.gamelosedetecter.LoseOutputBoundary; +import usecases.gamelosedetecter.LoseOutputData; + +public class LosePresenter implements LoseOutputBoundary { + private NavigationManager navigationManager; + private LoseInterface newview; + private LoseInterfaceNavigate view; + + public LosePresenter(LoseInterface newview, NavigationManager navigationManager, LoseInterfaceNavigate view) { + this.newview = newview; + this.navigationManager = navigationManager; + this.view = view; + } + + @Override + public void preapareGameoverEarly(LoseOutputData loseOutputData) { + view.navigateGameOver(navigationManager); + newview.prepareGameOverEarly(loseOutputData.getLosedescription(), loseOutputData.getScore()); + } +} diff --git a/src/main/java/interface_adapters/gameminimap/MinimapController.java b/src/main/java/interface_adapters/gameminimap/MinimapController.java new file mode 100644 index 000000000..7685b04a8 --- /dev/null +++ b/src/main/java/interface_adapters/gameminimap/MinimapController.java @@ -0,0 +1,24 @@ +package interface_adapters.gameminimap; + +import usecases.gameminimap.MinimapInputBoundary; +import usecases.gameminimap.MinimapInputData; + +/** + * Controller for minimap update ui usecase. + */ +public class MinimapController { + private MinimapInputBoundary minimapInteractor; + + public MinimapController(MinimapInputBoundary minimapInteractor) { + this.minimapInteractor = minimapInteractor; + } + + /** + * Execute by taking info from player side, turn to inputdata type, and sent to execute. + */ + public void execute() { + final MinimapInputData inputdata = new MinimapInputData(); + minimapInteractor.execute(inputdata); + } + +} diff --git a/src/main/java/interface_adapters/gameminimap/MinimapInterface.java b/src/main/java/interface_adapters/gameminimap/MinimapInterface.java new file mode 100644 index 000000000..c2a1a0888 --- /dev/null +++ b/src/main/java/interface_adapters/gameminimap/MinimapInterface.java @@ -0,0 +1,15 @@ +package interface_adapters.gameminimap; + +import java.util.ArrayList; + +/** + * Interface for minimap, updateminimap ui. + */ +public interface MinimapInterface { + + /** + * Updata Minimap with nested list of single letter. + * @param grid representation of each loc form together to be minimap. + */ + void updateUiMinimap(ArrayList> grid); +} diff --git a/src/main/java/interface_adapters/gameminimap/MinimapPresenter.java b/src/main/java/interface_adapters/gameminimap/MinimapPresenter.java new file mode 100644 index 000000000..d7ac817c3 --- /dev/null +++ b/src/main/java/interface_adapters/gameminimap/MinimapPresenter.java @@ -0,0 +1,23 @@ +package interface_adapters.gameminimap; + +import java.util.ArrayList; + +import usecases.gameminimap.MinimapOutputBoundary; +import usecases.gameminimap.MinimapOutputData; + +/** + * Minimap presentor. + */ +public class MinimapPresenter implements MinimapOutputBoundary { + private MinimapInterface view; + + public MinimapPresenter(MinimapInterface view) { + this.view = view; + } + + @Override + public void preparesuccessview(MinimapOutputData outputdata) { + final ArrayList> grid = outputdata.getMinimap(); + view.updateUiMinimap(grid); + } +} diff --git a/src/main/java/interface_adapters/gamenewday/NewdayController.java b/src/main/java/interface_adapters/gamenewday/NewdayController.java new file mode 100644 index 000000000..ba0e27544 --- /dev/null +++ b/src/main/java/interface_adapters/gamenewday/NewdayController.java @@ -0,0 +1,23 @@ +package interface_adapters.gamenewday; + +import usecases.gamenewday.NewdayInputBoundary; +import usecases.gamenewday.NewdayInputData; + +/** + * New day usecase controller. + */ +public class NewdayController { + private NewdayInputBoundary newdayInteractor; + + public NewdayController(NewdayInputBoundary newdayInteractor) { + this.newdayInteractor = newdayInteractor; + } + + /** + * Execute the newday usecase. after player successfully pressed the button. + */ + public void execute() { + final NewdayInputData inputData = new NewdayInputData(); + newdayInteractor.execute(inputData); + } +} diff --git a/src/main/java/interface_adapters/gamenewday/NewdayInterface.java b/src/main/java/interface_adapters/gamenewday/NewdayInterface.java new file mode 100644 index 000000000..79a87fb08 --- /dev/null +++ b/src/main/java/interface_adapters/gamenewday/NewdayInterface.java @@ -0,0 +1,21 @@ +package interface_adapters.gamenewday; + +/** + * Interface, act as communication between new day adaptior and view. + */ +public interface NewdayInterface { + + /** + * Update the view by providing message to the textbox, update the 4 resource representation. + * @param message message for what happened in a new day. + + */ + void updateUiNewday(String message); + + /** + * If usecase failed, for example is already day 60 and this button was click, show reason why, don't change + * anything else. + * @param message error message. + */ + void failureNewday(String message); +} diff --git a/src/main/java/interface_adapters/gamenewday/NewdayPresenter.java b/src/main/java/interface_adapters/gamenewday/NewdayPresenter.java new file mode 100644 index 000000000..9b196afe4 --- /dev/null +++ b/src/main/java/interface_adapters/gamenewday/NewdayPresenter.java @@ -0,0 +1,25 @@ +package interface_adapters.gamenewday; + +import usecases.gamenewday.NewdayOutputBoundary; +import usecases.gamenewday.NewdayOutputData; + +/** + * Newday presentor, + */ +public class NewdayPresenter implements NewdayOutputBoundary { + private NewdayInterface view; + + public NewdayPresenter(NewdayInterface view) { + this.view = view; + } + + @Override + public void prepareSuccessView(NewdayOutputData outputData) { + view.updateUiNewday(outputData.getMessage()); + } + + @Override + public void prepareFailureView(String errorMessage) { + view.failureNewday(errorMessage); + } +} diff --git a/src/main/java/interface_adapters/gameplacedescription/PlaceDescriptionController.java b/src/main/java/interface_adapters/gameplacedescription/PlaceDescriptionController.java new file mode 100644 index 000000000..c504b8be1 --- /dev/null +++ b/src/main/java/interface_adapters/gameplacedescription/PlaceDescriptionController.java @@ -0,0 +1,23 @@ +package interface_adapters.gameplacedescription; + +import usecases.gameplacedescription.PlaceDescriptionInputBoundary; +import usecases.gameplacedescription.PlaceDescriptionInputData; + +/** + * Place description usecase controller. + */ +public class PlaceDescriptionController { + private PlaceDescriptionInputBoundary interactor; + + public PlaceDescriptionController(PlaceDescriptionInputBoundary interactor) { + this.interactor = interactor; + } + + /** + * Automatic move, no player input needed. + */ + public void execute() { + final PlaceDescriptionInputData inputdata = new PlaceDescriptionInputData(); + interactor.execute(inputdata); + } +} diff --git a/src/main/java/interface_adapters/gameplacedescription/PlaceDescriptionInterface.java b/src/main/java/interface_adapters/gameplacedescription/PlaceDescriptionInterface.java new file mode 100644 index 000000000..e944bb715 --- /dev/null +++ b/src/main/java/interface_adapters/gameplacedescription/PlaceDescriptionInterface.java @@ -0,0 +1,19 @@ +package interface_adapters.gameplacedescription; + +/** + * Place description interface. + */ +public interface PlaceDescriptionInterface { + + /** + * If successful usecase, display the place description. + * @param placeDescription place description. + */ + void updateUiPlaceDescription(String placeDescription); + + /** + * If not successful, explain why location description generate was failed. + * @param failmessage fail reasoning. + */ + void failurePlaceDescription(String failmessage); +} diff --git a/src/main/java/interface_adapters/gameplacedescription/PlaceDescriptionPresenter.java b/src/main/java/interface_adapters/gameplacedescription/PlaceDescriptionPresenter.java new file mode 100644 index 000000000..55d3eef23 --- /dev/null +++ b/src/main/java/interface_adapters/gameplacedescription/PlaceDescriptionPresenter.java @@ -0,0 +1,26 @@ +package interface_adapters.gameplacedescription; + +import usecases.gameplacedescription.PlaceDescriptionOutputBoundary; +import usecases.gameplacedescription.PlaceDescriptionOutputData; + +/** + * Presenter of place description. + */ +public class PlaceDescriptionPresenter implements PlaceDescriptionOutputBoundary { + private PlaceDescriptionInterface view; + + public PlaceDescriptionPresenter(PlaceDescriptionInterface view) { + this.view = view; + } + + @Override + public void preparesuccessview(PlaceDescriptionOutputData data) { + final String description = data.getDescription(); + view.updateUiPlaceDescription(description); + } + + @Override + public void preparefailureview(String failmessage) { + view.failurePlaceDescription(failmessage); + } +} diff --git a/src/main/java/interface_adapters/gateways/PlayerRepository.java b/src/main/java/interface_adapters/gateways/PlayerRepository.java new file mode 100644 index 000000000..b4bbb0df4 --- /dev/null +++ b/src/main/java/interface_adapters/gateways/PlayerRepository.java @@ -0,0 +1,42 @@ +package interface_adapters.gateways; + +import entities.Player; + +/** + * Represents the interface for accessing and managing player data. + */ +public interface PlayerRepository { + + /** + * Finds and retrieves a player by their username. + * + * This method searches the data source for a player with the specified username. + * If a matching player is found, it returns the corresponding Player object. + * Otherwise, it returns null. + * + * @param username The username of the player to find. + * @return The Player object if the username exists in the data source, otherwise null. + */ + Player findByUsername(String username); + + /** + * Checks if the given username already exists in the data source. + * + * This method determines whether a player with the specified username is already + * stored in the data source. It helps ensure username uniqueness during signup. + * + * @param username The username to check. + * @return True if the username exists in the data source, otherwise false. + */ + boolean isUsernameDuplicate(String username); + + /** + * Adds a new player to the data source. + * + * This method saves the given Player object into the data source. It assumes + * that the username is unique and does not perform additional duplicate checks. + * + * @param player The Player object to add to the data source. + */ + void addPlayer(Player player); +} diff --git a/src/main/java/interface_adapters/gateways/RankingRepository.java b/src/main/java/interface_adapters/gateways/RankingRepository.java new file mode 100644 index 000000000..d5c4738ad --- /dev/null +++ b/src/main/java/interface_adapters/gateways/RankingRepository.java @@ -0,0 +1,18 @@ +package interface_adapters.gateways; + +import java.util.List; + +import entities.PlayerRankingEntry; + +/** + * Represents the interface for accessing ranking data. + * This interface defines the contract for retrieving the ranking list. + */ +public interface RankingRepository { + /** + * Retrieves all ranking entries from the data source. + * + * @return A list of all ranking entries. + */ + List getAllRankings(); +} diff --git a/src/main/java/interface_adapters/login/LoginController.java b/src/main/java/interface_adapters/login/LoginController.java new file mode 100644 index 000000000..e10b1d2a5 --- /dev/null +++ b/src/main/java/interface_adapters/login/LoginController.java @@ -0,0 +1,38 @@ +package interface_adapters.login; + +import usecases.accountlogin.LoginInputBoundary; +import usecases.accountlogin.LoginInputData; + +/** + * The LoginController class is responsible for handling user input from the UI + * and invoking the Login use case to process the login logic. + * It acts as the bridge between the user interface and the application's business logic. + */ +public class LoginController { + private final LoginInputBoundary loginUseCase; + + /** + * Constructs a new LoginController with the specified LoginInputBoundary. + * + * @param loginUseCase The input boundary instance responsible for processing login requests. + */ + public LoginController(LoginInputBoundary loginUseCase) { + this.loginUseCase = loginUseCase; + } + + /** + * Handles the login process by creating a LoginInputData object with the provided + * username and password, passing it to the Login use case, and returning the result. + * + * @param username The username provided by the user. + * @param password The password provided by the user. + */ + public void handleLogin(String username, String password) { + // Create input data object for the use case + final LoginInputData inputData = new LoginInputData(username, password); + + // Invoke the use case with the input data + loginUseCase.execute(inputData); + } +} + diff --git a/src/main/java/interface_adapters/login/LoginInterface.java b/src/main/java/interface_adapters/login/LoginInterface.java new file mode 100644 index 000000000..332196d3d --- /dev/null +++ b/src/main/java/interface_adapters/login/LoginInterface.java @@ -0,0 +1,15 @@ +package interface_adapters.login; + +/** + * The LoginInterface defines the methods required for presenting the result of a login attempt. + */ +public interface LoginInterface { + + /** + * Displays the result of the login attempt. + * + * @param message A string containing the result message of the login attempt. + * This could indicate a successful login or describe the reason for a login failure. + */ + void displayLoginResult(String message); +} diff --git a/src/main/java/interface_adapters/login/LoginPresenter.java b/src/main/java/interface_adapters/login/LoginPresenter.java new file mode 100644 index 000000000..b14ac105e --- /dev/null +++ b/src/main/java/interface_adapters/login/LoginPresenter.java @@ -0,0 +1,44 @@ +package interface_adapters.login; + +import interface_adapters.NavigationManagerJson; +import usecases.accountlogin.LoginOutputBoundary; +import usecases.accountlogin.LoginOutputData; + +/** + * The LoginPresenter class is responsible for formatting the output data + * from the Login use case into a format suitable for the user interface. + */ +public class LoginPresenter implements LoginOutputBoundary { + private final LoginInterface view; + private final NavigationManagerJson navigationManager; + + /** + * Constructs a LoginPresenter with the specified view and navigation manager. + * + * @param view The view interface for displaying login results. + * @param navigationManager The navigation manager for handling navigation logic. + */ + public LoginPresenter(LoginInterface view, NavigationManagerJson navigationManager) { + this.view = view; + this.navigationManager = navigationManager; + } + + /** + * Prepares the view for a successful login attempt. + */ + @Override + public void prepareSuccessView(LoginOutputData outputData) { + view.displayLoginResult(outputData.getMessage()); + if (outputData.isLoginSuccess()) { + navigationManager.showMainView(); + } + } + + /** + * Prepares the view for a failed login attempt. + */ + @Override + public void prepareFailureView(LoginOutputData outputData) { + view.displayLoginResult(outputData.getMessage()); + } +} diff --git a/src/main/java/interface_adapters/nevagateRanking/NevagateRankingController.java b/src/main/java/interface_adapters/nevagateRanking/NevagateRankingController.java new file mode 100644 index 000000000..5f57f4ed9 --- /dev/null +++ b/src/main/java/interface_adapters/nevagateRanking/NevagateRankingController.java @@ -0,0 +1,31 @@ +package interface_adapters.nevagateRanking; + +import usecases.nevagateRanking.NevagateRankingInputBoundary; +import usecases.nevagateRanking.NevagateRankingInputData; + +/** + * Controller for the NavigateRanking use case. + * Acts as a bridge between the user interface and the interactor. + */ +public class NevagateRankingController { + private final NevagateRankingInputBoundary interactor; + + /** + * Constructs a NevagateRankingController instance. + * + * @param interactor The interactor responsible for processing the navigation logic. + */ + public NevagateRankingController(NevagateRankingInputBoundary interactor) { + this.interactor = interactor; + } + + /** + * Triggers the navigation to the ranking page by passing input data to the interactor. + * + * @param context A string representing the navigation context (e.g., "Navigate to Ranking"). + */ + public void navigateToRanking(String context) { + final NevagateRankingInputData inputData = new NevagateRankingInputData(context); + interactor.execute(inputData); + } +} diff --git a/src/main/java/interface_adapters/nevagateRanking/NevagateRankingPresenter.java b/src/main/java/interface_adapters/nevagateRanking/NevagateRankingPresenter.java new file mode 100644 index 000000000..4d3a6994d --- /dev/null +++ b/src/main/java/interface_adapters/nevagateRanking/NevagateRankingPresenter.java @@ -0,0 +1,33 @@ +package interface_adapters.nevagateRanking; + +import interface_adapters.NavigationManagerJson; +import usecases.nevagateRanking.NevagateRankingOutputBoundary; +import usecases.nevagateRanking.NevagateRankingOutputData; + +/** + * Presenter for the NavigateRanking use case. + * Handles the navigation logic and delegates view updates to the NavigationManager. + */ +public class NevagateRankingPresenter implements NevagateRankingOutputBoundary { + private final NavigationManagerJson navigationManager; + + /** + * Constructs a NevagateRankingPresenter instance. + * + * @param navigationManager The navigation manager responsible for view transitions. + */ + public NevagateRankingPresenter(NavigationManagerJson navigationManager) { + this.navigationManager = navigationManager; + } + + /** + * Presents the navigation results by invoking the appropriate view transition. + * + * @param outputData The output data containing the navigation result message. + */ + @Override + public void present(NevagateRankingOutputData outputData) { + // Navigate to the Ranking view + navigationManager.showRankingView(); + } +} diff --git a/src/main/java/interface_adapters/nevagateSignup/NevagateSignupController.java b/src/main/java/interface_adapters/nevagateSignup/NevagateSignupController.java new file mode 100644 index 000000000..a122f9c56 --- /dev/null +++ b/src/main/java/interface_adapters/nevagateSignup/NevagateSignupController.java @@ -0,0 +1,31 @@ +package interface_adapters.nevagateSignup; + +import usecases.nevagateSignup.NevagateSignupInputBoundary; +import usecases.nevagateSignup.NevagateSignupInputData; + +/** + * Controller for the NavigateSignup use case. + * Acts as a bridge between the user interface and the interactor. + */ +public class NevagateSignupController { + private final NevagateSignupInputBoundary interactor; + + /** + * Constructs a NevagateSignupController instance. + * + * @param interactor The interactor responsible for processing the navigation logic. + */ + public NevagateSignupController(NevagateSignupInputBoundary interactor) { + this.interactor = interactor; + } + + /** + * Triggers the navigation to the signup page by passing input data to the interactor. + * + * @param context A string representing the navigation context (e.g., "Navigate to Signup"). + */ + public void navigateToSignup(String context) { + NevagateSignupInputData inputData = new NevagateSignupInputData(context); + interactor.execute(inputData); + } +} diff --git a/src/main/java/interface_adapters/nevagateSignup/NevagateSignupPresenter.java b/src/main/java/interface_adapters/nevagateSignup/NevagateSignupPresenter.java new file mode 100644 index 000000000..a1babe3c2 --- /dev/null +++ b/src/main/java/interface_adapters/nevagateSignup/NevagateSignupPresenter.java @@ -0,0 +1,33 @@ +package interface_adapters.nevagateSignup; + +import usecases.nevagateSignup.NevagateSignupOutputBoundary; +import usecases.nevagateSignup.NevagateSignupOutputData; +import interface_adapters.NavigationManagerJson; + +/** + * Presenter for the NavigateSignup use case. + * Handles the navigation logic and delegates view updates to the NavigationManager. + */ +public class NevagateSignupPresenter implements NevagateSignupOutputBoundary { + private final NavigationManagerJson navigationManager; + + /** + * Constructs a NevagateSignupPresenter instance. + * + * @param navigationManager The navigation manager responsible for view transitions. + */ + public NevagateSignupPresenter(NavigationManagerJson navigationManager) { + this.navigationManager = navigationManager; + } + + /** + * Presents the navigation results by invoking the appropriate view transition. + * + * @param outputData The output data containing the navigation result message. + */ + @Override + public void present(NevagateSignupOutputData outputData) { + // Navigate to the Signup view + navigationManager.showSignUpView(); + } +} diff --git a/src/main/java/interface_adapters/nevagateallowcatepage/NevagateAllowcateController.java b/src/main/java/interface_adapters/nevagateallowcatepage/NevagateAllowcateController.java new file mode 100644 index 000000000..2462e443e --- /dev/null +++ b/src/main/java/interface_adapters/nevagateallowcatepage/NevagateAllowcateController.java @@ -0,0 +1,17 @@ +package interface_adapters.nevagateallowcatepage; + +import usecases.nevagateAllowcatePage.NevagateAllowcateInputBoundary; +import usecases.nevagateAllowcatePage.NevagateAllowcateInputdata; + +public class NevagateAllowcateController { + private final NevagateAllowcateInputBoundary interactor; + + public NevagateAllowcateController(NevagateAllowcateInputBoundary interactor) { + this.interactor = interactor; + } + + public void execute() { + final NevagateAllowcateInputdata inputdata = new NevagateAllowcateInputdata(); + interactor.execute(inputdata); + } +} diff --git a/src/main/java/interface_adapters/nevagateallowcatepage/NevagateAllowcateInterface.java b/src/main/java/interface_adapters/nevagateallowcatepage/NevagateAllowcateInterface.java new file mode 100644 index 000000000..6e8428136 --- /dev/null +++ b/src/main/java/interface_adapters/nevagateallowcatepage/NevagateAllowcateInterface.java @@ -0,0 +1,7 @@ +package interface_adapters.nevagateallowcatepage; + +/** + * Nothing to show to player, Nevagate logic is concluded in Navigation managet. + */ +public interface NevagateAllowcateInterface { +} diff --git a/src/main/java/interface_adapters/nevagateallowcatepage/NevagateAllowcatePresenter.java b/src/main/java/interface_adapters/nevagateallowcatepage/NevagateAllowcatePresenter.java new file mode 100644 index 000000000..2d67c92cf --- /dev/null +++ b/src/main/java/interface_adapters/nevagateallowcatepage/NevagateAllowcatePresenter.java @@ -0,0 +1,22 @@ +package interface_adapters.nevagateallowcatepage; + +import interface_adapters.NavigationManager; +import usecases.nevagateAllowcatePage.NevagateAllowcateOutputBoundary; + +public class NevagateAllowcatePresenter implements NevagateAllowcateOutputBoundary { + private final NavigationManager navigationManager; + + public NevagateAllowcatePresenter(NavigationManager navigationManager) { + this.navigationManager = navigationManager; + } + + @Override + public void nevagateAllowcatePage() { + navigationManager.showCharacterCreationView(); + } + + @Override + public void nevagateAllowcateFail(String errormessage) { + // will not fail because this don't have any restriction. + } +} diff --git a/src/main/java/interface_adapters/nevagateevent/NevagateEventController.java b/src/main/java/interface_adapters/nevagateevent/NevagateEventController.java new file mode 100644 index 000000000..d18f14cf6 --- /dev/null +++ b/src/main/java/interface_adapters/nevagateevent/NevagateEventController.java @@ -0,0 +1,20 @@ +package interface_adapters.nevagateevent; + +import usecases.nevagateEventPage.NevagateEventInputBoundary; +import usecases.nevagateEventPage.NevagateEventInputdata; + +/** + * Controller. + */ +public class NevagateEventController { + private final NevagateEventInputBoundary interactor; + + public NevagateEventController(NevagateEventInputBoundary interactor) { + this.interactor = interactor; + } + + public void execute() { + final NevagateEventInputdata inputdata = new NevagateEventInputdata(); + interactor.execute(inputdata); + } +} diff --git a/src/main/java/interface_adapters/nevagateevent/NevagateEventInterface.java b/src/main/java/interface_adapters/nevagateevent/NevagateEventInterface.java new file mode 100644 index 000000000..b9d02facf --- /dev/null +++ b/src/main/java/interface_adapters/nevagateevent/NevagateEventInterface.java @@ -0,0 +1,8 @@ +package interface_adapters.nevagateevent; + +/** + * Not needed. + */ +public interface NevagateEventInterface { + void failureNevagateEvent(String message); +} diff --git a/src/main/java/interface_adapters/nevagateevent/NevagateEventPresenter.java b/src/main/java/interface_adapters/nevagateevent/NevagateEventPresenter.java new file mode 100644 index 000000000..211331461 --- /dev/null +++ b/src/main/java/interface_adapters/nevagateevent/NevagateEventPresenter.java @@ -0,0 +1,25 @@ +package interface_adapters.nevagateevent; + +import interface_adapters.NavigationManager; +import usecases.nevagateEventPage.NevagateEventOutputBoundary; +import usecases.nevagateEventPage.NevagateEventOutputdata; + +public class NevagateEventPresenter implements NevagateEventOutputBoundary { + private final NavigationManager navigationManager; + private final NevagateEventInterface view; + + public NevagateEventPresenter(NavigationManager navigationManager, NevagateEventInterface view) { + this.navigationManager = navigationManager; + this.view = view; + } + + @Override + public void nevagateEventPage(NevagateEventOutputdata outputdata) { + navigationManager.showEventView(); + } + + @Override + public void nevagateEventFailed(String failmessage) { + view.failureNevagateEvent(failmessage); + } +} diff --git a/src/main/java/interface_adapters/nevagategame/NevagateGameController.java b/src/main/java/interface_adapters/nevagategame/NevagateGameController.java new file mode 100644 index 000000000..1eb6a7b34 --- /dev/null +++ b/src/main/java/interface_adapters/nevagategame/NevagateGameController.java @@ -0,0 +1,17 @@ +package interface_adapters.nevagategame; + +import usecases.nevagateGame.NevagateGameInputBoundary; +import usecases.nevagateGame.NevagateGameInputdata; + +public class NevagateGameController { + private final NevagateGameInputBoundary interactor; + + public NevagateGameController(NevagateGameInputBoundary interactor) { + this.interactor = interactor; + } + + public void execute() { + final NevagateGameInputdata inputdata = new NevagateGameInputdata(); + interactor.execute(inputdata); + } +} \ No newline at end of file diff --git a/src/main/java/interface_adapters/nevagategame/NevagateGameInterface.java b/src/main/java/interface_adapters/nevagategame/NevagateGameInterface.java new file mode 100644 index 000000000..434025b16 --- /dev/null +++ b/src/main/java/interface_adapters/nevagategame/NevagateGameInterface.java @@ -0,0 +1,7 @@ +package interface_adapters.nevagategame; + +/** + * Nothing stopping player from going back. + */ +public interface NevagateGameInterface { +} diff --git a/src/main/java/interface_adapters/nevagategame/NevagateGamePresenter.java b/src/main/java/interface_adapters/nevagategame/NevagateGamePresenter.java new file mode 100644 index 000000000..a6fb2bf4d --- /dev/null +++ b/src/main/java/interface_adapters/nevagategame/NevagateGamePresenter.java @@ -0,0 +1,18 @@ +package interface_adapters.nevagategame; + +import interface_adapters.NavigationManager; +import usecases.nevagateGame.NevagateGameOutputBoundary; +import usecases.nevagateGame.NevagateGameOutputdata; + +public class NevagateGamePresenter implements NevagateGameOutputBoundary { + private NavigationManager navigationManager; + + public NevagateGamePresenter(NavigationManager navigationManager) { + this.navigationManager = navigationManager; + } + + @Override + public void prepareGamePage(NevagateGameOutputdata outputdata) { + navigationManager.showGameView(); + } +} diff --git a/src/main/java/interface_adapters/nevagategameover/NevagateGameOverController.java b/src/main/java/interface_adapters/nevagategameover/NevagateGameOverController.java new file mode 100644 index 000000000..785ac0245 --- /dev/null +++ b/src/main/java/interface_adapters/nevagategameover/NevagateGameOverController.java @@ -0,0 +1,23 @@ +package interface_adapters.nevagategameover; + +import usecases.nevagateGameover.NevagateGameOverInputBoundary; +import usecases.nevagateGameover.NevagateGameOverInputdata; + +/** + * Controller for navigate. + */ +public class NevagateGameOverController { + private final NevagateGameOverInputBoundary interactor; + + public NevagateGameOverController(NevagateGameOverInputBoundary interactor) { + this.interactor = interactor; + } + + /** + * Execute this. + */ + public void execute() { + final NevagateGameOverInputdata inputdata = new NevagateGameOverInputdata(); + interactor.execute(inputdata); + } +} diff --git a/src/main/java/interface_adapters/nevagategameover/NevagateGameOverInterface.java b/src/main/java/interface_adapters/nevagategameover/NevagateGameOverInterface.java new file mode 100644 index 000000000..fad7a8c7b --- /dev/null +++ b/src/main/java/interface_adapters/nevagategameover/NevagateGameOverInterface.java @@ -0,0 +1,7 @@ +package interface_adapters.nevagategameover; + +/** + * Not needed. + */ +public interface NevagateGameOverInterface { +} diff --git a/src/main/java/interface_adapters/nevagategameover/NevagateGameOverPresenter.java b/src/main/java/interface_adapters/nevagategameover/NevagateGameOverPresenter.java new file mode 100644 index 000000000..eb8aa1446 --- /dev/null +++ b/src/main/java/interface_adapters/nevagategameover/NevagateGameOverPresenter.java @@ -0,0 +1,21 @@ +package interface_adapters.nevagategameover; + +import interface_adapters.NavigationManager; +import usecases.nevagateGameover.NevagateGameOverOutputBoundary; +import usecases.nevagateGameover.NevagateGameOverOutputdata; + +/** + * Nevagate game over view presenter. + */ +public class NevagateGameOverPresenter implements NevagateGameOverOutputBoundary { + private NavigationManager navigationManager; + + public NevagateGameOverPresenter(NavigationManager navigationManager) { + this.navigationManager = navigationManager; + } + + @Override + public void prepareGameOver(NevagateGameOverOutputdata outputdata) { + navigationManager.showGameOverView(); + } +} diff --git a/src/main/java/interface_adapters/nevagateloginview/NevagateLoginController.java b/src/main/java/interface_adapters/nevagateloginview/NevagateLoginController.java new file mode 100644 index 000000000..29e1db0a5 --- /dev/null +++ b/src/main/java/interface_adapters/nevagateloginview/NevagateLoginController.java @@ -0,0 +1,23 @@ +package interface_adapters.nevagateloginview; + +import usecases.nevagateLogin.NevagateLoginInputBoundary; +import usecases.nevagateLogin.NevagateLoginInputData; + +/** + * Controller for navigating to the Login page. + */ +public class NevagateLoginController { + private final NevagateLoginInputBoundary inputBoundary; + + public NevagateLoginController(NevagateLoginInputBoundary inputBoundary) { + this.inputBoundary = inputBoundary; + } + + /** + * Triggers navigation to the Login page. + */ + public void navigateToLogin() { + final NevagateLoginInputData inputData = new NevagateLoginInputData(); + inputBoundary.execute(inputData); + } +} diff --git a/src/main/java/interface_adapters/nevagateloginview/NevagateLoginInterface.java b/src/main/java/interface_adapters/nevagateloginview/NevagateLoginInterface.java new file mode 100644 index 000000000..2fd320fc3 --- /dev/null +++ b/src/main/java/interface_adapters/nevagateloginview/NevagateLoginInterface.java @@ -0,0 +1,13 @@ +package interface_adapters.nevagateloginview; + +/** + * Interface for handling the Login page navigation logic. + */ +public interface NevagateLoginInterface { + /** + * Handles the navigation result and updates the UI. + * + * @param message A message indicating the result of the navigation. + */ + void onNavigate(String message); +} diff --git a/src/main/java/interface_adapters/nevagateloginview/NevagateLoginPresenter.java b/src/main/java/interface_adapters/nevagateloginview/NevagateLoginPresenter.java new file mode 100644 index 000000000..e0eec12fb --- /dev/null +++ b/src/main/java/interface_adapters/nevagateloginview/NevagateLoginPresenter.java @@ -0,0 +1,22 @@ +package interface_adapters.nevagateloginview; + +import interface_adapters.NavigationManagerJson; +import usecases.nevagateLogin.NevagateLoginOutputBoundary; +import usecases.nevagateLogin.NevagateLoginOutputData; + +/** + * Presenter for navigating to the Login page. + */ +public class NevagateLoginPresenter implements NevagateLoginOutputBoundary { + private final NavigationManagerJson navigationManager; + + public NevagateLoginPresenter(NavigationManagerJson navigationManager) { + this.navigationManager = navigationManager; + } + + @Override + public void prepareSuccessView(NevagateLoginOutputData outputData) { + // Trigger navigation via NavigationManager + navigationManager.showLoginView(); + } +} diff --git a/src/main/java/interface_adapters/nevagatemainview/NevagateMainController.java b/src/main/java/interface_adapters/nevagatemainview/NevagateMainController.java new file mode 100644 index 000000000..1e01be8eb --- /dev/null +++ b/src/main/java/interface_adapters/nevagatemainview/NevagateMainController.java @@ -0,0 +1,21 @@ +package interface_adapters.nevagatemainview; + +import usecases.navigateMain.NavigateMainInputBoundary; +import usecases.navigateMain.NavigateMainInputData; +import usecases.navigateMain.NavigateMainInputData; + +/** + * Controller for navigating to new page. + */ +public class NevagateMainController { + private final NavigateMainInputBoundary interacter; + + public NevagateMainController(NavigateMainInputBoundary interacter) { + this.interacter = interacter; + } + + public void execute() { + final NavigateMainInputData inputdata = new NavigateMainInputData(); + interacter.execute(inputdata); + } +} diff --git a/src/main/java/interface_adapters/nevagatemainview/NevagateMainInterface.java b/src/main/java/interface_adapters/nevagatemainview/NevagateMainInterface.java new file mode 100644 index 000000000..90540ed64 --- /dev/null +++ b/src/main/java/interface_adapters/nevagatemainview/NevagateMainInterface.java @@ -0,0 +1,7 @@ +package interface_adapters.nevagatemainview; + +/** + * Not needed. + */ +public interface NevagateMainInterface { +} diff --git a/src/main/java/interface_adapters/nevagatemainview/NevagateMainPresenter.java b/src/main/java/interface_adapters/nevagatemainview/NevagateMainPresenter.java new file mode 100644 index 000000000..fb8f133bb --- /dev/null +++ b/src/main/java/interface_adapters/nevagatemainview/NevagateMainPresenter.java @@ -0,0 +1,17 @@ +package interface_adapters.nevagatemainview; + +import interface_adapters.NavigationManager; +import usecases.navigateMain.NevagateMainOutputBoundary; + +public class NevagateMainPresenter implements NevagateMainOutputBoundary { + private NavigationManager navigationManager; + + public NevagateMainPresenter(NavigationManager navigationManager) { + this.navigationManager = navigationManager; + } + + @Override + public void prepareMainView() { + navigationManager.showMainView(); + } +} diff --git a/src/main/java/interface_adapters/rankinglist/RankingController.java b/src/main/java/interface_adapters/rankinglist/RankingController.java new file mode 100644 index 000000000..21737aaa7 --- /dev/null +++ b/src/main/java/interface_adapters/rankinglist/RankingController.java @@ -0,0 +1,36 @@ +package interface_adapters.rankinglist; + +import usecases.accountranking.RankingInputBoundary; +import usecases.accountranking.RankingInputData; + +/** + * The RankingController class is responsible for handling user input from the UI + * and invoking the Ranking use case to process the leaderboard retrieval logic. + * It acts as the bridge between the user interface and the application's business logic. + */ +public class RankingController { + private final RankingInputBoundary rankingUseCase; + + /** + * Constructs a new RankingController with the specified RankingInputBoundary. + * + * @param rankingUseCase The input boundary instance responsible for processing ranking requests. + */ + public RankingController(RankingInputBoundary rankingUseCase) { + this.rankingUseCase = rankingUseCase; + } + + /** + * Handles the leaderboard retrieval process by creating a RankingInputData object + * with the specified number of top players to retrieve, and passing it to the Ranking use case. + * + * @param topN The number of top players to retrieve from the leaderboard. + */ + public void handleRanking(int topN) { + // Create input data object for the use case + final RankingInputData inputData = new RankingInputData(topN); + + // Invoke the use case with the input data + rankingUseCase.execute(inputData); + } +} diff --git a/src/main/java/interface_adapters/rankinglist/RankingInterface.java b/src/main/java/interface_adapters/rankinglist/RankingInterface.java new file mode 100644 index 000000000..e5f0c08cc --- /dev/null +++ b/src/main/java/interface_adapters/rankinglist/RankingInterface.java @@ -0,0 +1,28 @@ +package interface_adapters.rankinglist; + +import java.util.List; + +/** + * The RankingInterface defines the methods that a view should implement + * to display the leaderboard and handle any errors. + */ +public interface RankingInterface { + + /** + * Updates the UI with the sorted leaderboard entries as separate data points. + * + * @param playerNames A list of player names. + * @param scores A list of player scores. + * @param daysSurvived A list of the days survived by each player. + * @param statuses A list of statuses indicating if each player won or lost. + */ + void displayRankings(List playerNames, List scores, + List daysSurvived, List statuses); + + /** + * Displays an error message in case of a failure in leaderboard retrieval. + * + * @param errorMessage The error message to display. + */ + void displayError(String errorMessage); +} diff --git a/src/main/java/interface_adapters/rankinglist/RankingPresenter.java b/src/main/java/interface_adapters/rankinglist/RankingPresenter.java new file mode 100644 index 000000000..6bd9ae4c3 --- /dev/null +++ b/src/main/java/interface_adapters/rankinglist/RankingPresenter.java @@ -0,0 +1,66 @@ +package interface_adapters.rankinglist; + +import java.util.List; +import java.util.stream.Collectors; + +import entities.PlayerRankingEntry; +import usecases.accountranking.RankingOutputBoundary; +import usecases.accountranking.RankingOutputData; + +/** + * The RankingPresenter class is responsible for converting the output data + * from the Ranking use case into a format suitable for the user interface. + * It interacts with the view via the RankingInterface. + */ +public class RankingPresenter implements RankingOutputBoundary { + // The view that will display the ranking information + private final RankingInterface view; + + /** + * Constructs a new RankingPresenter with the specified view. + * + * @param view The view that will display the leaderboard and errors. + */ + public RankingPresenter(RankingInterface view) { + this.view = view; + } + + /** + * Prepares the view for a successful leaderboard retrieval. + * Separates PlayerRankingEntry objects into individual data lists. + * + * @param outputData The output data containing the sorted leaderboard information. + */ + @Override + public void prepareSuccessView(RankingOutputData outputData) { + // Extract individual components of PlayerRankingEntry + final List playerNames = outputData.getRankings().stream() + .map(PlayerRankingEntry::getName) + .collect(Collectors.toList()); + final List scores = outputData.getRankings().stream() + .map(PlayerRankingEntry::getScore) + .collect(Collectors.toList()); + final List daysSurvived = outputData.getRankings().stream() + .map(PlayerRankingEntry::getDaysSurvived) + .collect(Collectors.toList()); + final List statuses = outputData.getRankings().stream() + .map(entry -> entry.isWon() ? "Won" : "Lost") + .collect(Collectors.toList()); + + // Update the view with separate lists + view.displayRankings(playerNames, scores, daysSurvived, statuses); + } + + /** + * Prepares the view for a failed leaderboard retrieval attempt. + * Notifies the view of the error. + * + * @param errorMessage The error message indicating why the retrieval failed. + */ + @Override + public void prepareFailureView(String errorMessage) { + // Notify the view of the failure + view.displayError(errorMessage); + } +} + diff --git a/src/main/java/interface_adapters/signup/SignupController.java b/src/main/java/interface_adapters/signup/SignupController.java new file mode 100644 index 000000000..5bbf7c0cc --- /dev/null +++ b/src/main/java/interface_adapters/signup/SignupController.java @@ -0,0 +1,37 @@ +package interface_adapters.signup; + +import usecases.accountsignup.SignupInputBoundary; +import usecases.accountsignup.SignupInputData; + +/** + * The SignupController class is responsible for handling user input from the UI + * and invoking the Signup use case to process the user registration logic. + * It acts as the bridge between the user interface and the application's business logic. + */ +public class SignupController { + private final SignupInputBoundary signupUseCase; + + /** + * Constructs a new SignupController with the specified SignupInputBoundary. + * + * @param signupUseCase The input boundary instance responsible for processing signup requests. + */ + public SignupController(SignupInputBoundary signupUseCase) { + this.signupUseCase = signupUseCase; + } + + /** + * Handles the signup process by creating a SignupInputData object with the provided + * username and password, passing it to the Signup use case. + * + * @param username The username provided by the user. + * @param password The password provided by the user. + */ + public void handleSignup(String username, String password) { + // Create input data object for the use case + final SignupInputData inputData = new SignupInputData(username, password); + + // Invoke the use case with the input data + signupUseCase.execute(inputData); + } +} diff --git a/src/main/java/interface_adapters/signup/SignupInterface.java b/src/main/java/interface_adapters/signup/SignupInterface.java new file mode 100644 index 000000000..1a30e548d --- /dev/null +++ b/src/main/java/interface_adapters/signup/SignupInterface.java @@ -0,0 +1,15 @@ +package interface_adapters.signup; + +/** + * The SignupInterface defines methods that the UI must implement + * to display the results of a signup operation or handle errors. + */ +public interface SignupInterface { + + /** + * Updates the UI to display the result of a successful signup. + * + * @param message The success message to display. + */ + void displaySignupResult(String message); +} diff --git a/src/main/java/interface_adapters/signup/SignupPresenter.java b/src/main/java/interface_adapters/signup/SignupPresenter.java new file mode 100644 index 000000000..fbcbd3c67 --- /dev/null +++ b/src/main/java/interface_adapters/signup/SignupPresenter.java @@ -0,0 +1,42 @@ +package interface_adapters.signup; + +import usecases.accountsignup.SignupOutputBoundary; +import usecases.accountsignup.SignupOutputData; + +/** + * The SignupPresenter class processes use case output for the signup operation + * and converts it into a format suitable for the UI via the SignupInterface. + */ +public class SignupPresenter implements SignupOutputBoundary { + // The UI interface to interact with + private final SignupInterface view; + + /** + * Constructs a new SignupPresenter with the specified SignupInterface. + * + * @param view The UI interface for displaying signup results. + */ + public SignupPresenter(SignupInterface view) { + this.view = view; + } + + /** + * Prepares the UI for a successful signup attempt. + * + * @param outputData The output data containing the success message. + */ + @Override + public void prepareSuccessView(SignupOutputData outputData) { + view.displaySignupResult(outputData.getMessage()); + } + + /** + * Prepares the UI for a failed signup attempt. + * + * @param outputData The output data containing the failure message. + */ + @Override + public void prepareFailureView(SignupOutputData outputData) { + view.displaySignupResult(outputData.getMessage()); + } +} diff --git a/src/main/java/interface_adapters/startallowcatepoint/AllowcateController.java b/src/main/java/interface_adapters/startallowcatepoint/AllowcateController.java new file mode 100644 index 000000000..9e18a3658 --- /dev/null +++ b/src/main/java/interface_adapters/startallowcatepoint/AllowcateController.java @@ -0,0 +1,30 @@ +package interface_adapters.startallowcatepoint; + +import usecases.startallowcate.AllowcateInputBoundary; +import usecases.startallowcate.AllowcateInputdata; + +/** + * Allowcate point controller. + */ +public class AllowcateController { + private final AllowcateInputBoundary interactor; + + public AllowcateController(AllowcateInputBoundary interactor) { + this.interactor = interactor; + } + + /** + * Execute based on player's selected attribute. + * @param generalship generalship player choosed. + * @param mobilization mobilization player choosed. + * @param thrift thrfit player choosed. + * @param luck luck. + * @param social social. + * @param point point. + */ + public void execute(int point, int social, int luck, int thrift, int mobilization, int generalship) { + final AllowcateInputdata inputdata = new AllowcateInputdata(point, social, + luck, thrift, mobilization, generalship); + interactor.execute(inputdata); + } +} diff --git a/src/main/java/interface_adapters/startallowcatepoint/AllowcateInterface.java b/src/main/java/interface_adapters/startallowcatepoint/AllowcateInterface.java new file mode 100644 index 000000000..6a92d9c85 --- /dev/null +++ b/src/main/java/interface_adapters/startallowcatepoint/AllowcateInterface.java @@ -0,0 +1,12 @@ +package interface_adapters.startallowcatepoint; + +/** + * Interface of allowcate point. + */ +public interface AllowcateInterface { + /** + * Failure message if the usecase is failed. (insuffient skill point for example) + * @param message fail message + */ + void failureAllowcate(String message); +} diff --git a/src/main/java/interface_adapters/startallowcatepoint/AllowcatePresenter.java b/src/main/java/interface_adapters/startallowcatepoint/AllowcatePresenter.java new file mode 100644 index 000000000..b5984e042 --- /dev/null +++ b/src/main/java/interface_adapters/startallowcatepoint/AllowcatePresenter.java @@ -0,0 +1,28 @@ +package interface_adapters.startallowcatepoint; + +import interface_adapters.NavigationManager; +import usecases.startallowcate.AllowcateOutputBoundary; +import usecases.startallowcate.AllowcateOutputData; + +/** + * Allowcate presenter. + */ +public class AllowcatePresenter implements AllowcateOutputBoundary { + private final NavigationManager navigationManager; + private final AllowcateInterface view; + + public AllowcatePresenter(AllowcateInterface view, NavigationManager navigationManager) { + this.view = view; + this.navigationManager = navigationManager; + } + + @Override + public void NevagateStartGame(AllowcateOutputData outputData) { + navigationManager.showGameView(); + } + + @Override + public void preparefailureview(String failmessage) { + view.failureAllowcate(failmessage); + } +} diff --git a/src/main/java/use_case/note/DataAccessException.java b/src/main/java/use_case/note/DataAccessException.java deleted file mode 100644 index b8c17920d..000000000 --- a/src/main/java/use_case/note/DataAccessException.java +++ /dev/null @@ -1,10 +0,0 @@ -package use_case.note; - -/** - * Exception thrown when there is an error with accessing data. - */ -public class DataAccessException extends Exception { - public DataAccessException(String string) { - super(string); - } -} diff --git a/src/main/java/use_case/note/NoteDataAccessInterface.java b/src/main/java/use_case/note/NoteDataAccessInterface.java deleted file mode 100644 index b71597828..000000000 --- a/src/main/java/use_case/note/NoteDataAccessInterface.java +++ /dev/null @@ -1,30 +0,0 @@ -package use_case.note; - -import entity.User; - -/** - * Interface for the NoteDAO. It consists of methods for - * both loading and saving a note. - */ -public interface NoteDataAccessInterface { - - /** - * Saves a note for a given user. This will replace any existing note. - *

The password of the user must match that of the user saved in the system.

- * @param user the user information associated with the note - * @param note the note to be saved - * @return the contents of the note - * @throws DataAccessException if the user's note can not be saved for any reason - */ - String saveNote(User user, String note) throws DataAccessException; - - /** - * Returns the note associated with the user. The password - * is not checked, so anyone can read the information. - * @param user the user information associated with the note - * @return the contents of the note - * @throws DataAccessException if the user's note can not be loaded for any reason - */ - String loadNote(User user) throws DataAccessException; - -} diff --git a/src/main/java/use_case/note/NoteInputBoundary.java b/src/main/java/use_case/note/NoteInputBoundary.java deleted file mode 100644 index b41da9bf5..000000000 --- a/src/main/java/use_case/note/NoteInputBoundary.java +++ /dev/null @@ -1,19 +0,0 @@ -package use_case.note; - -/** - * The Input Boundary for our note-related use cases. Since they are closely related, - * we have included them both in the same interface for simplicity. - */ -public interface NoteInputBoundary { - - /** - * Executes the refresh note use case. - */ - void executeRefresh(); - - /** - * Executes the save note use case. - * @param message the input data - */ - void executeSave(String message); -} diff --git a/src/main/java/use_case/note/NoteInteractor.java b/src/main/java/use_case/note/NoteInteractor.java deleted file mode 100644 index 369e9309a..000000000 --- a/src/main/java/use_case/note/NoteInteractor.java +++ /dev/null @@ -1,59 +0,0 @@ -package use_case.note; - -import entity.User; - -/** - * The "Use Case Interactor" for our two note-related use cases of refreshing - * the contents of the note and saving the contents of the note. Since they - * are closely related, we have combined them here for simplicity. - */ -public class NoteInteractor implements NoteInputBoundary { - - private final NoteDataAccessInterface noteDataAccessInterface; - private final NoteOutputBoundary noteOutputBoundary; - // Note: this program has it hardcoded which user object it is getting data for; - // you could change this if you wanted to generalize the code. For example, - // you might allow a user of the program to create a new note, which you - // could store as a "user" through the API OR you might maintain all notes - // in a JSON object stored in one common "user" stored through the API. - private final User user = new User("jonathan_calver2", "abc123"); - - public NoteInteractor(NoteDataAccessInterface noteDataAccessInterface, - NoteOutputBoundary noteOutputBoundary) { - this.noteDataAccessInterface = noteDataAccessInterface; - this.noteOutputBoundary = noteOutputBoundary; - } - - /** - * Executes the refresh note use case. - * - */ - @Override - public void executeRefresh() { - try { - - final String note = noteDataAccessInterface.loadNote(user); - noteOutputBoundary.prepareSuccessView(note); - } - catch (DataAccessException ex) { - noteOutputBoundary.prepareFailView(ex.getMessage()); - } - } - - /** - * Executes the save note use case. - * - * @param note the input data - */ - @Override - public void executeSave(String note) { - try { - - final String updatedNote = noteDataAccessInterface.saveNote(user, note); - noteOutputBoundary.prepareSuccessView(updatedNote); - } - catch (DataAccessException ex) { - noteOutputBoundary.prepareFailView(ex.getMessage()); - } - } -} diff --git a/src/main/java/use_case/note/NoteOutputBoundary.java b/src/main/java/use_case/note/NoteOutputBoundary.java deleted file mode 100644 index c0c2bb1d0..000000000 --- a/src/main/java/use_case/note/NoteOutputBoundary.java +++ /dev/null @@ -1,18 +0,0 @@ -package use_case.note; - -/** - * The output boundary for the Login Use Case. - */ -public interface NoteOutputBoundary { - /** - * Prepares the success view for the Note related Use Cases. - * @param message the output data - */ - void prepareSuccessView(String message); - - /** - * Prepares the failure view for the Note related Use Cases. - * @param errorMessage the explanation of the failure - */ - void prepareFailView(String errorMessage); -} diff --git a/src/main/java/usecases/accountlogin/LoginDataAccessInterface.java b/src/main/java/usecases/accountlogin/LoginDataAccessInterface.java new file mode 100644 index 000000000..6a1e44331 --- /dev/null +++ b/src/main/java/usecases/accountlogin/LoginDataAccessInterface.java @@ -0,0 +1,26 @@ +package usecases.accountlogin; + +/** + * Interface for accessing user data related to login. + * Defines methods for validating credentials and checking user existence. + */ +public interface LoginDataAccessInterface { + /** + * Validates the credentials of a user. + * + * @param username The username provided by the user. + * @param password The password provided by the user. + * @return True if the credentials are valid, otherwise false. + */ + boolean validateCredentials(String username, String password); + + /** + * Checks if a user with the specified username exists. + * + * @param username The username to check. + * @return True if the user exists, otherwise false. + */ + boolean doesUserExist(String username); + + void reloadData(); +} diff --git a/src/main/java/usecases/accountlogin/LoginInputBoundary.java b/src/main/java/usecases/accountlogin/LoginInputBoundary.java new file mode 100644 index 000000000..c0b169a7c --- /dev/null +++ b/src/main/java/usecases/accountlogin/LoginInputBoundary.java @@ -0,0 +1,14 @@ +package usecases.accountlogin; + +/** + * Input boundary for the login use case. + * Defines the interface for initiating the login process. + */ +public interface LoginInputBoundary { + /** + * Processes a login request with the provided input data. + * + * @param inputData The data required for login, such as username and password. + */ + void execute(LoginInputData inputData); +} diff --git a/src/main/java/usecases/accountlogin/LoginInputData.java b/src/main/java/usecases/accountlogin/LoginInputData.java new file mode 100644 index 000000000..222b2a9ef --- /dev/null +++ b/src/main/java/usecases/accountlogin/LoginInputData.java @@ -0,0 +1,39 @@ +package usecases.accountlogin; + +/** + * Data class for encapsulating input data for the login use case. + * Contains the username and password provided by the user. + */ +public class LoginInputData { + private final String username; + private final String password; + + /** + * Constructs a new LoginInputData object with the specified username and password. + * + * @param username The username provided by the user. + * @param password The password provided by the user. + */ + public LoginInputData(String username, String password) { + this.username = username; + this.password = password; + } + + /** + * Gets the username provided by the user. + * + * @return The username as a string. + */ + public String getUsername() { + return username; + } + + /** + * Gets the password provided by the user. + * + * @return The password as a string. + */ + public String getPassword() { + return password; + } +} diff --git a/src/main/java/usecases/accountlogin/LoginInteractor.java b/src/main/java/usecases/accountlogin/LoginInteractor.java new file mode 100644 index 000000000..0cf7c8463 --- /dev/null +++ b/src/main/java/usecases/accountlogin/LoginInteractor.java @@ -0,0 +1,48 @@ +package usecases.accountlogin; + +/** + * Use case interactor for login. + * Implements the core logic for processing login requests, + * including credential validation and user existence checks. + */ +public class LoginInteractor implements LoginInputBoundary { + private final LoginDataAccessInterface dataAccess; + private final LoginOutputBoundary outputBoundary; + + /** + * Constructs a LoginInteractor with the specified data access interface and output boundary. + * + * @param dataAccess The interface for accessing user data for login. + * @param outputBoundary The output boundary for presenting login results. + */ + public LoginInteractor(LoginDataAccessInterface dataAccess, LoginOutputBoundary outputBoundary) { + this.dataAccess = dataAccess; + this.outputBoundary = outputBoundary; + } + + /** + * Executes the login use case. + * Validates the user's credentials and prepares the appropriate view (success or failure). + * + * @param inputData The input data containing the username and password. + */ + @Override + public void execute(LoginInputData inputData) { + dataAccess.reloadData(); + + final String username = inputData.getUsername(); + final String password = inputData.getPassword(); + + if (!dataAccess.doesUserExist(username)) { + outputBoundary.prepareFailureView(new LoginOutputData(false, "User does not exist.")); + return; + } + + if (!dataAccess.validateCredentials(username, password)) { + outputBoundary.prepareFailureView(new LoginOutputData(false, "Invalid credentials.")); + return; + } + + outputBoundary.prepareSuccessView(new LoginOutputData(true, "Login successful!")); + } +} diff --git a/src/main/java/usecases/accountlogin/LoginOutputBoundary.java b/src/main/java/usecases/accountlogin/LoginOutputBoundary.java new file mode 100644 index 000000000..668dfb147 --- /dev/null +++ b/src/main/java/usecases/accountlogin/LoginOutputBoundary.java @@ -0,0 +1,21 @@ +package usecases.accountlogin; + +/** + * Output boundary for the login use case. + * Defines methods for preparing success and failure views. + */ +public interface LoginOutputBoundary { + /** + * Prepares the view for a successful login. + * + * @param outputData The output data containing the success message. + */ + void prepareSuccessView(LoginOutputData outputData); + + /** + * Prepares the view for a failed login attempt. + * + * @param outputData The output data containing the success message. + */ + void prepareFailureView(LoginOutputData outputData); +} diff --git a/src/main/java/usecases/accountlogin/LoginOutputData.java b/src/main/java/usecases/accountlogin/LoginOutputData.java new file mode 100644 index 000000000..d30b692d0 --- /dev/null +++ b/src/main/java/usecases/accountlogin/LoginOutputData.java @@ -0,0 +1,41 @@ +package usecases.accountlogin; + +/** + * Data class for encapsulating output data from the login use case. + * This class contains the result of the login operation, including a success indicator + * and a message detailing the outcome of the operation. + */ +public class LoginOutputData { + private final boolean loginSuccess; + private final String message; + + /** + * Constructs a new LoginOutputData object with the specified success indicator and message. + * + * @param loginSuccess A boolean indicating whether the login was successful. + * @param message A string message describing the result of the login operation. + * This can be a success message or an error message. + */ + public LoginOutputData(boolean loginSuccess, String message) { + this.loginSuccess = loginSuccess; + this.message = message; + } + + /** + * Indicates whether the login was successful. + * + * @return True if the login was successful, otherwise false. + */ + public boolean isLoginSuccess() { + return loginSuccess; + } + + /** + * Retrieves the message associated with the login operation. + * + * @return A string message representing the result of the login operation. + */ + public String getMessage() { + return message; + } +} diff --git a/src/main/java/usecases/accountranking/RankingDataAccessInterface.java b/src/main/java/usecases/accountranking/RankingDataAccessInterface.java new file mode 100644 index 000000000..2ae149aac --- /dev/null +++ b/src/main/java/usecases/accountranking/RankingDataAccessInterface.java @@ -0,0 +1,41 @@ +package usecases.accountranking; + +import java.io.IOException; +import java.util.List; + +import entities.PlayerRankingEntry; + +/** + * Interface for accessing ranking data. + * Defines methods for retrieving and updating player rankings. + */ +public interface RankingDataAccessInterface { + /** + * Retrieves the list of ranked players. + * + * @return A list of PlayerRankingEntry objects representing the leaderboard. + */ + List getLeaderboard(); + + /** + * Updates the score for a specific player. + * + * @param username The username of the player. + * @param score The new score to assign. + */ + void updateScore(String username, int score); + + /** + * Updates the ranking data for a specific player. + * If the player already exists in the ranking, their data is updated. + * If not, a new entry is created for the player. + * + * @param username The username of the player. + * @param score The final score of the player. + * @param daysSurvived The number of days the player survived in the game. + * @param won Whether the player won the game. + */ + void updateRankingData(String username, int score, int daysSurvived, boolean won); + + void reloadData() throws IOException; +} diff --git a/src/main/java/usecases/accountranking/RankingInputBoundary.java b/src/main/java/usecases/accountranking/RankingInputBoundary.java new file mode 100644 index 000000000..f799107bf --- /dev/null +++ b/src/main/java/usecases/accountranking/RankingInputBoundary.java @@ -0,0 +1,14 @@ +package usecases.accountranking; + +/** + * Input boundary for the ranking use case. + * Defines the interface for retrieving and sorting the player leaderboard. + */ +public interface RankingInputBoundary { + /** + * Executes the ranking use case with the provided input data. + * + * @param inputData The input data containing the number of top players to retrieve. + */ + void execute(RankingInputData inputData); +} diff --git a/src/main/java/usecases/accountranking/RankingInputData.java b/src/main/java/usecases/accountranking/RankingInputData.java new file mode 100644 index 000000000..6fb861d62 --- /dev/null +++ b/src/main/java/usecases/accountranking/RankingInputData.java @@ -0,0 +1,28 @@ +package usecases.accountranking; + +/** + * Data class for encapsulating input data for the ranking use case. + * Contains the number of top players to retrieve. + */ +public class RankingInputData { + // Number of top players to retrieve. + private final int topN; + + /** + * Constructs a new RankingInputData object with the specified number of top players. + * + * @param topN The number of top players to retrieve. + */ + public RankingInputData(int topN) { + this.topN = topN; + } + + /** + * Retrieves the number of top players to retrieve. + * + * @return The number of top players. + */ + public int getTopN() { + return topN; + } +} diff --git a/src/main/java/usecases/accountranking/RankingInteractor.java b/src/main/java/usecases/accountranking/RankingInteractor.java new file mode 100644 index 000000000..783cba875 --- /dev/null +++ b/src/main/java/usecases/accountranking/RankingInteractor.java @@ -0,0 +1,56 @@ +package usecases.accountranking; + +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +import entities.PlayerRankingEntry; + +/** + * Use case interactor for the ranking use case. + * Implements the core logic for sorting and presenting the player leaderboard. + */ +public class RankingInteractor implements RankingInputBoundary { + private final RankingDataAccessInterface dataAccessInterface; + private final RankingOutputBoundary outputBoundary; + + /** + * Constructs a RankingInteractor with the specified data access interface and output boundary. + * + * @param dataAccessInterface The interface for accessing ranking data. + * @param outputBoundary The output boundary for presenting the leaderboard results. + */ + public RankingInteractor(RankingDataAccessInterface dataAccessInterface, RankingOutputBoundary outputBoundary) { + this.dataAccessInterface = dataAccessInterface; + this.outputBoundary = outputBoundary; + } + + /** + * Executes the ranking use case. + * Retrieves the leaderboard data, sorts it based on the requirements, + * and prepares the appropriate view for the top N players. + * + * @param inputData The input data containing the number of top players to retrieve. + */ + @Override + public void execute(RankingInputData inputData) { + // Retrieve the unsorted list of players from the data access interface + final List rankings = dataAccessInterface.getLeaderboard(); + + if (rankings == null || rankings.isEmpty()) { + outputBoundary.prepareFailureView("No players found in the leaderboard."); + return; + } + + // Sort the players first by `won` (true > false), then by `score` in descending order + final List sortedRankings = rankings.stream() + .sorted(Comparator.comparing(PlayerRankingEntry::isWon).reversed() + .thenComparing(Comparator.comparing(PlayerRankingEntry::getScore).reversed())) + // Get only the top N players + .limit(inputData.getTopN()) + .collect(Collectors.toList()); + + // Prepare the sorted list as output data + outputBoundary.prepareSuccessView(new RankingOutputData(sortedRankings)); + } +} diff --git a/src/main/java/usecases/accountranking/RankingOutputBoundary.java b/src/main/java/usecases/accountranking/RankingOutputBoundary.java new file mode 100644 index 000000000..ef2ce58d1 --- /dev/null +++ b/src/main/java/usecases/accountranking/RankingOutputBoundary.java @@ -0,0 +1,21 @@ +package usecases.accountranking; + +/** + * Output boundary for the ranking use case. + * Defines methods for preparing success and failure views for leaderboard retrieval. + */ +public interface RankingOutputBoundary { + /** + * Prepares the view for successfully retrieved rankings. + * + * @param outputData The output data containing the leaderboard information. + */ + void prepareSuccessView(RankingOutputData outputData); + + /** + * Prepares the view for a failed ranking retrieval attempt. + * + * @param errorMessage The error message to display. + */ + void prepareFailureView(String errorMessage); +} diff --git a/src/main/java/usecases/accountranking/RankingOutputData.java b/src/main/java/usecases/accountranking/RankingOutputData.java new file mode 100644 index 000000000..5b173847c --- /dev/null +++ b/src/main/java/usecases/accountranking/RankingOutputData.java @@ -0,0 +1,31 @@ +package usecases.accountranking; + +import java.util.List; + +import entities.PlayerRankingEntry; + +/** + * Data class for encapsulating output data from the ranking use case. + * Contains the list of ranked players and their respective details. + */ +public class RankingOutputData { + private final List rankings; + + /** + * Constructs a new RankingOutputData object with the specified rankings. + * + * @param rankings A list of PlayerRankingEntry objects representing the leaderboard. + */ + public RankingOutputData(List rankings) { + this.rankings = rankings; + } + + /** + * Retrieves the list of ranked players. + * + * @return A list of PlayerRankingEntry objects. + */ + public List getRankings() { + return rankings; + } +} diff --git a/src/main/java/usecases/accountsignup/SignupDataAccessInterface.java b/src/main/java/usecases/accountsignup/SignupDataAccessInterface.java new file mode 100644 index 000000000..917ad5125 --- /dev/null +++ b/src/main/java/usecases/accountsignup/SignupDataAccessInterface.java @@ -0,0 +1,23 @@ +package usecases.accountsignup; + +/** + * Interface for accessing user data related to signup. + * Defines methods for checking username uniqueness and adding a new user. + */ +public interface SignupDataAccessInterface { + /** + * Checks if the specified username is already taken. + * + * @param username The username to check. + * @return True if the username is taken, otherwise false. + */ + boolean isUsernameTaken(String username); + + /** + * Adds a new user with the specified username and password. + * + * @param username The username for the new user. + * @param password The password for the new user. + */ + void addUser(String username, String password); +} diff --git a/src/main/java/usecases/accountsignup/SignupInputBoundary.java b/src/main/java/usecases/accountsignup/SignupInputBoundary.java new file mode 100644 index 000000000..e115ccf47 --- /dev/null +++ b/src/main/java/usecases/accountsignup/SignupInputBoundary.java @@ -0,0 +1,14 @@ +package usecases.accountsignup; + +/** + * Input boundary for the signup use case. + * Defines the interface for initiating the signup process. + */ +public interface SignupInputBoundary { + /** + * Executes the signup use case with the provided input data. + * + * @param inputData The input data containing the username and password for registration. + */ + void execute(SignupInputData inputData); +} diff --git a/src/main/java/usecases/accountsignup/SignupInputData.java b/src/main/java/usecases/accountsignup/SignupInputData.java new file mode 100644 index 000000000..87f562e70 --- /dev/null +++ b/src/main/java/usecases/accountsignup/SignupInputData.java @@ -0,0 +1,40 @@ +package usecases.accountsignup; + +/** + * Data class for encapsulating input data for the signup use case. + * This class contains the information provided by the user for registration, + * such as their desired username and password. + */ +public class SignupInputData { + private final String username; + private final String password; + + /** + * Constructs a new SignupInputData object with the specified username and password. + * + * @param username The desired username for the new account. + * @param password The desired password for the new account. + */ + public SignupInputData(String username, String password) { + this.username = username; + this.password = password; + } + + /** + * Retrieves the desired username for the new account. + * + * @return A string representing the username. + */ + public String getUsername() { + return username; + } + + /** + * Retrieves the desired password for the new account. + * + * @return A string representing the password. + */ + public String getPassword() { + return password; + } +} diff --git a/src/main/java/usecases/accountsignup/SignupInteractor.java b/src/main/java/usecases/accountsignup/SignupInteractor.java new file mode 100644 index 000000000..77d7a9c2c --- /dev/null +++ b/src/main/java/usecases/accountsignup/SignupInteractor.java @@ -0,0 +1,86 @@ +package usecases.accountsignup; + +/** + * Use case interactor for signup. + * Implements the core logic for processing user registration requests, + * including username uniqueness checks and user creation. + */ +public class SignupInteractor implements SignupInputBoundary { + private final SignupDataAccessInterface dataAccessInterface; + private final SignupOutputBoundary outputBoundary; + + /** + * Constructs a SignupInteractor with the specified data access interface and output boundary. + * + * @param dataAccessInterface The interface for accessing user data for signup. + * @param outputBoundary The output boundary for presenting signup results. + */ + public SignupInteractor(SignupDataAccessInterface dataAccessInterface, SignupOutputBoundary outputBoundary) { + this.dataAccessInterface = dataAccessInterface; + this.outputBoundary = outputBoundary; + } + + /** + * Executes the signup use case. + * Checks if the username is unique, creates a new user, and prepares the appropriate view. + * + * @param inputData The input data containing the username and password for registration. + */ + @Override + public void execute(SignupInputData inputData) { + final String username = inputData.getUsername(); + final String password = inputData.getPassword(); + + // Validate username and password format + if (!isValidUsername(username)) { + outputBoundary.prepareFailureView(new SignupOutputData(false, + "Signup failed. Username must be 5-15 characters, containing only letters and digits.")); + return; + } + + if (!isValidPassword(password)) { + outputBoundary.prepareFailureView(new SignupOutputData(false, + "Signup failed. Password must be 8-20 characters, containing at least one letter and one digit.")); + return; + } + + if (dataAccessInterface.isUsernameTaken(username)) { + outputBoundary.prepareFailureView(new SignupOutputData( + false, + "Signup failed. The username is already taken!" + )); + return; + } + + dataAccessInterface.addUser(username, password); + + outputBoundary.prepareSuccessView(new SignupOutputData( + true, + "Signup successful!" + )); + } + + /** + * Validates the username format. + * + * @param username The username to validate. + * - Must be 5-15 characters long. + * - Can only contain letters and digits (a-z, A-Z, 0-9). + * @return `true` if the username is valid, otherwise `false`. + */ + private boolean isValidUsername(String username) { + return username.matches("[a-zA-Z0-9]{5,15}"); + } + + /** + * Validates the password format. + * + * @param password The password to validate. + * - Must be 8-20 characters long. + * - Must contain at least one letter and one digit. + * @return `true` if the password is valid, otherwise `false`. + */ + private boolean isValidPassword(String password) { + return password.matches("^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{8,20}$"); + } +} diff --git a/src/main/java/usecases/accountsignup/SignupOutputBoundary.java b/src/main/java/usecases/accountsignup/SignupOutputBoundary.java new file mode 100644 index 000000000..3517b04e9 --- /dev/null +++ b/src/main/java/usecases/accountsignup/SignupOutputBoundary.java @@ -0,0 +1,21 @@ +package usecases.accountsignup; + +/** + * Output boundary for the signup use case. + * Defines methods for preparing success and failure views. + */ +public interface SignupOutputBoundary { + /** + * Prepares the view for a successful signup attempt. + * + * @param outputData The output data containing the success message. + */ + void prepareSuccessView(SignupOutputData outputData); + + /** + * Prepares the view for a failed signup attempt. + * + * @param outputData The output data containing the failure message. + */ + void prepareFailureView(SignupOutputData outputData); +} diff --git a/src/main/java/usecases/accountsignup/SignupOutputData.java b/src/main/java/usecases/accountsignup/SignupOutputData.java new file mode 100644 index 000000000..324a5ff4d --- /dev/null +++ b/src/main/java/usecases/accountsignup/SignupOutputData.java @@ -0,0 +1,41 @@ +package usecases.accountsignup; + +/** + * Data class for encapsulating output data from the signup use case. + * This class contains the result of the signup operation, including a success indicator + * and a message detailing the outcome of the operation. + */ +public class SignupOutputData { + private final boolean signupSuccess; + private final String message; + + /** + * Constructs a new SignupOutputData object with the specified success indicator and message. + * + * @param signupSuccess A boolean indicating whether the signup was successful. + * @param message A string message describing the result of the signup operation. + * This can be a success message or an error message. + */ + public SignupOutputData(boolean signupSuccess, String message) { + this.signupSuccess = signupSuccess; + this.message = message; + } + + /** + * Indicates whether the signup was successful. + * + * @return True if the signup was successful, otherwise false. + */ + public boolean isSignupSuccess() { + return signupSuccess; + } + + /** + * Retrieves the message associated with the signup operation. + * + * @return A string message representing the result of the signup operation. + */ + public String getMessage() { + return message; + } +} diff --git a/src/main/java/usecases/chatgpt/ChatGptResponseParser.java b/src/main/java/usecases/chatgpt/ChatGptResponseParser.java new file mode 100644 index 000000000..1280aade7 --- /dev/null +++ b/src/main/java/usecases/chatgpt/ChatGptResponseParser.java @@ -0,0 +1,68 @@ +package usecases.chatgpt; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Utility class to parse responses from ChatGPT API. + */ +public class ChatGptResponseParser { + + private static final int LINE_LENGTH = 50; // Adjust this value based on screen width + + /** + * Parses the response from ChatGPT and extracts the message content. + * @param response The raw JSON response from ChatGPT. + * @return The formatted assistant's response content. + * @throws Exception If the parsing fails. + */ + public static String parseEventOutcome(String response) throws Exception { + // Log the raw response + System.out.println("Raw response from ChatGPT: " + response); + + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode rootNode = objectMapper.readTree(response); + + // Navigate the response structure + JsonNode choicesNode = rootNode.path("choices"); + if (!choicesNode.isArray() || choicesNode.isEmpty()) { + throw new RuntimeException("Invalid ChatGPT response format: 'choices' array is missing or empty."); + } + + JsonNode firstChoice = choicesNode.get(0); + JsonNode messageNode = firstChoice.path("message"); + if (messageNode.isMissingNode()) { + throw new RuntimeException("Invalid ChatGPT response format: 'message' node is missing."); + } + + JsonNode contentNode = messageNode.path("content"); + if (contentNode.isMissingNode() || contentNode.asText().isEmpty()) { + throw new RuntimeException("Invalid ChatGPT response format: 'content' is missing or empty."); + } + + // Format the content to ensure it fits on the screen + return formatResponse(contentNode.asText()); + } + + /** + * Formats a long response into shorter lines with proper line breaks. + * @param responseContent The original response content. + * @return The formatted response with added line breaks. + */ + private static String formatResponse(String responseContent) { + StringBuilder formattedResponse = new StringBuilder(); + String[] words = responseContent.split(" "); + int currentLineLength = 0; + + for (String word : words) { + if (currentLineLength + word.length() + 1 > LINE_LENGTH) { + formattedResponse.append("\n"); // Add a new line + currentLineLength = 0; + } + formattedResponse.append(word).append(" "); + currentLineLength += word.length() + 1; + } + + return formattedResponse.toString().trim(); + } +} \ No newline at end of file diff --git a/src/main/java/usecases/chatgpt/ChatGptService.java b/src/main/java/usecases/chatgpt/ChatGptService.java new file mode 100644 index 000000000..06235d80e --- /dev/null +++ b/src/main/java/usecases/chatgpt/ChatGptService.java @@ -0,0 +1,82 @@ +package usecases.chatgpt; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Map; + +/** + * Service to integrate ChatGPT API. + */ +public class ChatGptService { + private static final String API_URL = "https://api.openai.com/v1/chat/completions"; + private static final String API_KEY = ""; + // enter the application key above to process. + + /** + * Sends a request to ChatGPT with the event description, player attributes, and player choice. + * + * @param eventDescription Description of the event. + * @param playerAttributes Player's attributes as key-value pairs. + * @param playerChoice The player's choice for the event. + * @return The response from ChatGPT. + * @throws Exception If an error occurs during the API call. + */ + public String getResponse(String eventDescription, Map playerAttributes, String playerChoice) throws Exception { + URL url = new URL(API_URL); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Authorization", "Bearer " + API_KEY); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setDoOutput(true); + + // Build the prompt for ChatGPT + ObjectMapper objectMapper = new ObjectMapper(); + String requestBody = objectMapper.writeValueAsString(Map.of( + "model", "gpt-4", + "messages", new Object[]{ + Map.of("role", "system", "content", "You are an AI that helps resolve events in a survival game."), + Map.of("role", "user", "content", generatePrompt(eventDescription, playerAttributes, playerChoice)) + }, + "max_tokens", 150, + "temperature", 0.7 + )); + + System.out.println("Request Body: " + requestBody); + + // Send the request + try (OutputStream os = connection.getOutputStream()) { + os.write(requestBody.getBytes()); + os.flush(); + } + + // Read the response + if (connection.getResponseCode() == 200) { + return new String(connection.getInputStream().readAllBytes()); + } else { + // Log the error response + String errorResponse = new String(connection.getErrorStream().readAllBytes()); + System.err.println("ChatGPT API Error: HTTP " + connection.getResponseCode() + " - " + errorResponse); + throw new RuntimeException("Failed to call ChatGPT API: HTTP " + connection.getResponseCode()); + } + } + + /** + * Generates the prompt for ChatGPT. + * + * @param eventDescription Description of the event. + * @param playerAttributes Player's attributes. + * @param playerChoice The player's chosen option. + * @return The formatted prompt. + */ + private String generatePrompt(String eventDescription, Map playerAttributes, String playerChoice) { + StringBuilder prompt = new StringBuilder(); + prompt.append("Event Description: ").append(eventDescription).append("\n"); + prompt.append("Player Attributes: ").append(playerAttributes).append("\n"); + prompt.append("Player Choice: ").append(playerChoice).append("\n"); + prompt.append("Provide a short paragraph describing the event outcome based on the player's choice."); + return prompt.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/usecases/dailybroadcast/BroadcastDataAccessInterface.java b/src/main/java/usecases/dailybroadcast/BroadcastDataAccessInterface.java new file mode 100644 index 000000000..745f6be2d --- /dev/null +++ b/src/main/java/usecases/dailybroadcast/BroadcastDataAccessInterface.java @@ -0,0 +1,49 @@ +package usecases.dailybroadcast; + +import entities.Inventory; +import entities.Location; +import entities.PlayerAttributes; + +/** + * Data access interface for the broadcast use case. + */ +public interface BroadcastDataAccessInterface { + /** + * Gets the player's attributes. + * + * @return The player's attributes. + */ + PlayerAttributes getPlayerAttributes(); + + /** + * Gets the player's inventory. + * + * @return The player's inventory. + */ + Inventory getInventory(); + + /** + * Updates the player's inventory. + * + * @param peopleChange The change in resources. + */ + void changePeople(int peopleChange); + + /** + * Get player's current location. + * @return location. + */ + Location getLocation(); + + /** + * Get player's action point left. + * @return action point. + */ + int getActionPoint(); + + /** + * Set player's action point. + * @param actionPoint action point. + */ + void setActionPoint(int actionPoint); +} diff --git a/src/main/java/usecases/dailybroadcast/BroadcastInputBoundary.java b/src/main/java/usecases/dailybroadcast/BroadcastInputBoundary.java new file mode 100644 index 000000000..0f980f8cf --- /dev/null +++ b/src/main/java/usecases/dailybroadcast/BroadcastInputBoundary.java @@ -0,0 +1,13 @@ +package usecases.dailybroadcast; + +/** + * Input boundary for the broadcast use case. + */ +public interface BroadcastInputBoundary { + /** + * Executes the broadcast action with the given input data. + * + * @param inputData The input data for the broadcast. + */ + void execute(BroadcastInputData inputData); +} diff --git a/src/main/java/usecases/dailybroadcast/BroadcastInputData.java b/src/main/java/usecases/dailybroadcast/BroadcastInputData.java new file mode 100644 index 000000000..9e7d316e1 --- /dev/null +++ b/src/main/java/usecases/dailybroadcast/BroadcastInputData.java @@ -0,0 +1,8 @@ +package usecases.dailybroadcast; + +/** + * Input data for the broadcast use case. + */ +public class BroadcastInputData { + +} diff --git a/src/main/java/usecases/dailybroadcast/BroadcastInteractor.java b/src/main/java/usecases/dailybroadcast/BroadcastInteractor.java new file mode 100644 index 000000000..d899157f6 --- /dev/null +++ b/src/main/java/usecases/dailybroadcast/BroadcastInteractor.java @@ -0,0 +1,42 @@ +package usecases.dailybroadcast; + +import entities.EntityConstants; +import entities.Location; +import entities.PlayerAttributes; + +/** + * Interactor for the broadcast use case. + */ +public class BroadcastInteractor implements usecases.dailybroadcast.BroadcastInputBoundary { + private final usecases.dailybroadcast.BroadcastDataAccessInterface dataAccessInterface; + private final usecases.dailybroadcast.BroadcastOutputBoundary outputBoundary; + + public BroadcastInteractor(usecases.dailybroadcast.BroadcastDataAccessInterface dataAccessInterface, + usecases.dailybroadcast.BroadcastOutputBoundary outputBoundary) { + this.dataAccessInterface = dataAccessInterface; + this.outputBoundary = outputBoundary; + } + + @Override + public void execute(usecases.dailybroadcast.BroadcastInputData inputData) { + final PlayerAttributes attributes = dataAccessInterface.getPlayerAttributes(); + final int actionpoint = dataAccessInterface.getActionPoint(); + final Location location = dataAccessInterface.getLocation(); + + if (actionpoint > 0) { + final int peoplegain = (int) Math.round(EntityConstants.BROADCASTGAIN + * (1 + attributes.getSocial() * EntityConstants.SOCIALIMPACTBROADCAST) + * location.getpeopleresourceavailable()); + final String successmessage = "Though Broadcast, " + peoplegain + " decided to join your group!"; + dataAccessInterface.setActionPoint(actionpoint - 1); + dataAccessInterface.changePeople(peoplegain); + final BroadcastOutputData outputData = new BroadcastOutputData(successmessage); + outputBoundary.prepareSuccessView(outputData); + } + else { + final String failmessage = "Cannot move, your people are tired!"; + outputBoundary.prepareFailureView(failmessage); + } + + } +} diff --git a/src/main/java/usecases/dailybroadcast/BroadcastOutputBoundary.java b/src/main/java/usecases/dailybroadcast/BroadcastOutputBoundary.java new file mode 100644 index 000000000..e1ae6794a --- /dev/null +++ b/src/main/java/usecases/dailybroadcast/BroadcastOutputBoundary.java @@ -0,0 +1,20 @@ +package usecases.dailybroadcast; + +/** + * Output boundary for the broadcast use case. + */ +public interface BroadcastOutputBoundary { + /** + * Prepares the success view for a broadcast. + * + * @param outputData The output data for the broadcast. + */ + void prepareSuccessView(BroadcastOutputData outputData); + + /** + * Prepares the failure view for a broadcast. + * + * @param errorMessage The error message for the failure. + */ + void prepareFailureView(String errorMessage); +} diff --git a/src/main/java/usecases/dailybroadcast/BroadcastOutputData.java b/src/main/java/usecases/dailybroadcast/BroadcastOutputData.java new file mode 100644 index 000000000..412315f79 --- /dev/null +++ b/src/main/java/usecases/dailybroadcast/BroadcastOutputData.java @@ -0,0 +1,17 @@ +package usecases.dailybroadcast; + +/** + * Output data for the broadcast use case. + */ +public class BroadcastOutputData { + private final String resultMessage; + + public BroadcastOutputData(String resultMessage) { + this.resultMessage = resultMessage; + + } + + public String getResultMessage() { + return resultMessage; + } +} diff --git a/src/main/java/usecases/dailygather/GatherDataAccessInterface.java b/src/main/java/usecases/dailygather/GatherDataAccessInterface.java new file mode 100644 index 000000000..75d761ac3 --- /dev/null +++ b/src/main/java/usecases/dailygather/GatherDataAccessInterface.java @@ -0,0 +1,56 @@ +package usecases.dailygather; + +import entities.Inventory; +import entities.Location; + +public interface GatherDataAccessInterface { + + /** + * Get player's inventory, we need the people data for how fast gathering. + * @return Player's inventory, have the data: people we need for calculation. + */ + Inventory getInventory(); + + /** + * This should return the location player is currently on, based on player location x and y, + * to be implemented on DAO. + * @return Location of the player, contain data we need like food and water resource available scalar etc. + */ + Location getLocation(); + + /** + * Call decreaseresourceavailable method in location object to decrease the resource scalar by day + * after a success gather, call the according change method in inventory class. + */ + void decreaseResourceavailable(); + + /** + * Change player's inventory food by the amount they gathered after successful gather use case. + * @param foodgathered foodgathered for this gather. + */ + void changeFood(int foodgathered); + + /** + * Change player's inventory water. + * @param watergathered water found in this gather. + */ + void changeWater(int watergathered); + + /** + * Change player's inventory weapon. + * @param weapongathered weapons found in this gather, in this location, by the player. + */ + void changeWeapon(int weapongathered); + + /** + * Get action point. + * @return actionpoint. + */ + int getActionPoint(); + + /** + * Set action point ot new value. + * @param actionPoint new action point. + */ + void setActionPoint(int actionPoint); +} diff --git a/src/main/java/usecases/dailygather/GatherInputBoundary.java b/src/main/java/usecases/dailygather/GatherInputBoundary.java new file mode 100644 index 000000000..9336f4c1c --- /dev/null +++ b/src/main/java/usecases/dailygather/GatherInputBoundary.java @@ -0,0 +1,14 @@ +package usecases.dailygather; + +/** + * Interface of input, which implemented by according interactor. + */ +public interface GatherInputBoundary { + + /** + * Execute the use case, with input data provided in datatype GatherInputData. + * @param inputdata the input data which is meanness for now since this action only determined by internal data. + */ + void execute(GatherInputData inputdata); +} + diff --git a/src/main/java/usecases/dailygather/GatherInputData.java b/src/main/java/usecases/dailygather/GatherInputData.java new file mode 100644 index 000000000..a4a0943a4 --- /dev/null +++ b/src/main/java/usecases/dailygather/GatherInputData.java @@ -0,0 +1,10 @@ +package usecases.dailygather; + +/** + * Gather input data, which is for player's input, the fact that player clicked on gather. + * However, we don't need this fact for now, the only reason I'm keeping this is because I want to keep the program + * predictable and uniform, as well as maintaining same structure for all use case. + */ +public class GatherInputData { + +} diff --git a/src/main/java/usecases/dailygather/GatherInteractor.java b/src/main/java/usecases/dailygather/GatherInteractor.java new file mode 100644 index 000000000..6b58ef8fe --- /dev/null +++ b/src/main/java/usecases/dailygather/GatherInteractor.java @@ -0,0 +1,65 @@ +package usecases.dailygather; + +/** + * Use case interactor for gather. + */ +public class GatherInteractor implements GatherInputBoundary { + private final GatherDataAccessInterface dataAccessInterface; + private final GatherOutputBoundary outputBoundary; + + public GatherInteractor(GatherDataAccessInterface DataAccessInterface, GatherOutputBoundary outputBoundary) { + this.dataAccessInterface = DataAccessInterface; + this.outputBoundary = outputBoundary; + } + + @Override + public void execute(GatherInputData inputdata) { + final double foodscalar = dataAccessInterface.getLocation().getfoodresourceavailable(); + final double waterscalar = dataAccessInterface.getLocation().getwaterresourceavailable(); + final double weaponscalar = dataAccessInterface.getLocation().getweaponresourceavailable(); + final int actionpoint = dataAccessInterface.getActionPoint(); + final int people = dataAccessInterface.getInventory().getPeople(); + final int foodgathered = (int) Math.round(foodscalar * Math.sqrt((double) people)); + final int watergathered = (int) Math.round(waterscalar * Math.sqrt((double) people)); + final int weapongathered = (int) Math.round(weaponscalar * Math.sqrt((double) people)); + // not sure if this is a good way of calculation towards game balance, I'll need when game can fully run to + // decide on the change. + StringBuilder successoutputmessage = new StringBuilder("Your group found "); + if (foodgathered > 0) { + successoutputmessage.append(foodgathered).append(" units of food "); + } + if (watergathered > 0) { + successoutputmessage.append(watergathered).append(" units of water "); + } + if (weapongathered > 0) { + successoutputmessage.append(weapongathered).append(" weapons"); + } + if (foodgathered == 0 && watergathered == 0 && weapongathered == 0) { + successoutputmessage = new StringBuilder("Your group found nothing this time."); + } + else { + successoutputmessage.append("."); + } + + if (isvaildgather(actionpoint)) { + dataAccessInterface.changeFood(foodgathered); + dataAccessInterface.changeWater(watergathered); + dataAccessInterface.changeWeapon(weapongathered); + dataAccessInterface.setActionPoint(actionpoint - 1); + outputBoundary.prepareSuccessView(new GatherOutputData( + successoutputmessage.toString())); + } + else { + outputBoundary.prepareFailureView("Can not gather! your people are tired!"); + } + } + + /** + * Helper function to determine validity of this gather, right now I can't think of a way of failing. + * @param actionpoint player have. + * @return vaild gather or not. + */ + public boolean isvaildgather(int actionpoint) { + return actionpoint > 0; + } +} diff --git a/src/main/java/usecases/dailygather/GatherOutputBoundary.java b/src/main/java/usecases/dailygather/GatherOutputBoundary.java new file mode 100644 index 000000000..497a5f274 --- /dev/null +++ b/src/main/java/usecases/dailygather/GatherOutputBoundary.java @@ -0,0 +1,20 @@ +package usecases.dailygather; + +/** + * Output boundary for gather use case, responsible for providing the new view after the use case executed. + */ +public interface GatherOutputBoundary { + + /** + * Prepare the view for a successful gather use case. + * @param outputdata outputdata been sent. + */ + void prepareSuccessView(GatherOutputData outputdata); + + /** + * Prepare the new for a failed gather use case, though I'm not sure how will this be failed, maybe player clicked + * on gather after used all their daily available action point. + * @param errorMessage error message for such failure. + */ + void prepareFailureView(String errorMessage); +} diff --git a/src/main/java/usecases/dailygather/GatherOutputData.java b/src/main/java/usecases/dailygather/GatherOutputData.java new file mode 100644 index 000000000..e37a685cb --- /dev/null +++ b/src/main/java/usecases/dailygather/GatherOutputData.java @@ -0,0 +1,19 @@ +package usecases.dailygather; + +/** + * Outputdata for the new view, notice the classes are already updated in execution of interactor, so this is just + * for the view, displaying successmessage as summary of the gather like "Your group found 178 food, 90 water, 10 weapon + * etc" . + */ +public class GatherOutputData { + private String successmessage; + + public GatherOutputData(String successmessage) { + this.successmessage = successmessage; + + } + + public String getSuccessmessage() { + return successmessage; + } +} diff --git a/src/main/java/usecases/dailymove/MoveDataAccessInterface.java b/src/main/java/usecases/dailymove/MoveDataAccessInterface.java new file mode 100644 index 000000000..53f48e74e --- /dev/null +++ b/src/main/java/usecases/dailymove/MoveDataAccessInterface.java @@ -0,0 +1,49 @@ +package usecases.dailymove; + +import entities.Maps; +import entities.PlayerAttributes; +import entities.PlayerLocation; + +/** + * Data access interface for move use case, retrieve player's current location, and attribute. + * attribute which we care is mobilization, which determine how fast player can move. + */ +public interface MoveDataAccessInterface { + + /** + * Return the player attributes from data access. + * @return player attribute entity. + */ + PlayerAttributes getPlayerAttributes(); + + /** + * Return the player location from data access. + * @return player location. + */ + PlayerLocation getPlayerLocation(); + + /** + * Return the map grid from data access, use to determine if vaild move on the edge etc. + * @return return map. + */ + Maps getMaps(); + + /** + * Update the player location. + * @param newx newx of player + * @param newy newy of player + */ + void updatePlayerLocation(int newx, int newy); + + /** + * Get action point they have. + * @return action point. + */ + int getActionPoint(); + + /** + * Setter for updated action point. + * @param point action point. + */ + void setActionPoint(int point); +} diff --git a/src/main/java/usecases/dailymove/MoveInputBoundary.java b/src/main/java/usecases/dailymove/MoveInputBoundary.java new file mode 100644 index 000000000..82eaf58fb --- /dev/null +++ b/src/main/java/usecases/dailymove/MoveInputBoundary.java @@ -0,0 +1,13 @@ +package usecases.dailymove; + +/** + * Input boundary of the use case move. + */ +public interface MoveInputBoundary { + + /** + * Execute the move for player based on given direction. + * @param inputdata direction player choose in MoveInputData format. + */ + void execute(MoveInputData inputdata); +} diff --git a/src/main/java/usecases/dailymove/MoveInputData.java b/src/main/java/usecases/dailymove/MoveInputData.java new file mode 100644 index 000000000..4a40ff62d --- /dev/null +++ b/src/main/java/usecases/dailymove/MoveInputData.java @@ -0,0 +1,17 @@ +package usecases.dailymove; + + +/** + * Inputdata structure for move usecase. + */ +public class MoveInputData { + private final String direction; + + public MoveInputData(String direction) { + this.direction = direction; + } + + public String getDirection() { + return direction; + } +} diff --git a/src/main/java/usecases/dailymove/MoveInteractor.java b/src/main/java/usecases/dailymove/MoveInteractor.java new file mode 100644 index 000000000..ff3c6a7e4 --- /dev/null +++ b/src/main/java/usecases/dailymove/MoveInteractor.java @@ -0,0 +1,98 @@ +package usecases.dailymove; + +import entities.EntityConstants; +import entities.PlayerLocation; + +/** + * Move use case interactor. + */ +public class MoveInteractor implements MoveInputBoundary { + private final MoveDataAccessInterface moveDataAccessObject; + private final MoveOutputBoundary moveOutputBoundary; + + public MoveInteractor(MoveDataAccessInterface moveDataAccessObject, MoveOutputBoundary moveOutputBoundary) { + this.moveDataAccessObject = moveDataAccessObject; + this.moveOutputBoundary = moveOutputBoundary; + } + + @Override + public void execute(MoveInputData moveInputData) { + // Fetch necessary data + final String direction = moveInputData.getDirection(); + final int speed = 1 + (moveDataAccessObject.getPlayerAttributes().getMobilization() + / EntityConstants.MOBILIZATIONIMPACTSPEED); + final PlayerLocation currentLocation = moveDataAccessObject.getPlayerLocation(); + final int x = currentLocation.getXcoordinate(); + final int y = currentLocation.getYcoordinate(); + final int mapWidth = moveDataAccessObject.getMaps().getGrid().size(); + final int mapHeight = moveDataAccessObject.getMaps().getGrid().get(1).size(); + final int actionpoint = moveDataAccessObject.getActionPoint(); + + // Variables for new coordinates + int newX = x; + int newY = y; + + // Determine new coordinates based on the direction + switch (direction) { + case EntityConstants.UP: + newY = Math.max(0, y - speed); + break; + case EntityConstants.DOWN: + newY = Math.min(mapHeight - 1, y + speed); + break; + case EntityConstants.LEFT: + newX = Math.max(0, x - speed); + break; + case EntityConstants.RIGHT: + newX = Math.min(mapWidth - 1, x + speed); + break; + default: + moveOutputBoundary.prepareFailureView("Invalid direction provided: " + direction); + } + + // Check if the move is valid + if (isInvalidMove(direction, x, y, newX, newY, mapWidth, mapHeight)) { + moveOutputBoundary.prepareFailureView( + "You can't move further in the " + direction + " direction; you're at the edge."); + } + else if (actionpoint > 0) { + moveDataAccessObject.updatePlayerLocation(newX, newY); + moveDataAccessObject.setActionPoint(actionpoint - 1); + final String successMessage = "You moved to position (" + newX + ", " + newY + ")."; + moveOutputBoundary.prepareSuccessView(new MoveOutputData(newX, newY, true, successMessage)); + } + else { + final String failmessage = "You can't move, your group is too tired!"; + moveOutputBoundary.prepareFailureView(failmessage); + } + } + + /** + * Helper method to check if a move is invalid. + * @param direction direction heading. + * @param mapHeight height of the map. + * @param mapWidth width of the map. + * @param newX Changed x. + * @param newY Changed y. + * @param xcoor x of player location currently. + * @param ycoor y of player location currently. + * @return Return if this is a valid move. + */ + private boolean isInvalidMove(String direction, int xcoor, int ycoor, + int newX, int newY, int mapWidth, int mapHeight) { + boolean ans = false; + if (direction.equals(EntityConstants.UP)) { + ans = newY == ycoor; + } + else if (direction.equals(EntityConstants.DOWN)) { + ans = newY == ycoor; + } + else if (direction.equals(EntityConstants.LEFT)) { + ans = newX == xcoor; + } + else if (direction.equals(EntityConstants.RIGHT)) { + ans = newX == xcoor; + } + return ans; + } +} diff --git a/src/main/java/usecases/dailymove/MoveOutputBoundary.java b/src/main/java/usecases/dailymove/MoveOutputBoundary.java new file mode 100644 index 000000000..c53a85555 --- /dev/null +++ b/src/main/java/usecases/dailymove/MoveOutputBoundary.java @@ -0,0 +1,19 @@ +package usecases.dailymove; + +/** + * Interface of output boundary. + */ +public interface MoveOutputBoundary { + + /** + * Outputs for a successful move. + * @param outputData the output for updating the view. + */ + void prepareSuccessView(MoveOutputData outputData); + + /** + * If the move the invaild, example: is on 0,0(edge) but player moved up. + * @param errorMessage message of why is invaild, for the player. + */ + void prepareFailureView(String errorMessage); +} diff --git a/src/main/java/usecases/dailymove/MoveOutputData.java b/src/main/java/usecases/dailymove/MoveOutputData.java new file mode 100644 index 000000000..350ddb427 --- /dev/null +++ b/src/main/java/usecases/dailymove/MoveOutputData.java @@ -0,0 +1,36 @@ +package usecases.dailymove; + +public class MoveOutputData { + + private final int newx; + private final int newy; + private final boolean usecasesuccess; + private final String message; + + public MoveOutputData(int newx, int newy, boolean usecasesuccess, String message) { + this.newx = newx; + this.newy = newy; + this.usecasesuccess = usecasesuccess; + this.message = message; + } + + public int getNewx() { + return newx; + } + + public int getNewy() { + return newy; + } + + public boolean isUsecasesuccess() { + return usecasesuccess; + } + + /** + * Return the success message description to player. + * @return message + */ + public String getmessage() { + return message; + } +} diff --git a/src/main/java/usecases/endprocesshorde/HordeDataAccessInterface.java b/src/main/java/usecases/endprocesshorde/HordeDataAccessInterface.java new file mode 100644 index 000000000..31895e268 --- /dev/null +++ b/src/main/java/usecases/endprocesshorde/HordeDataAccessInterface.java @@ -0,0 +1,42 @@ +package usecases.endprocesshorde; + +import entities.Horde; +import entities.Inventory; +import entities.PlayerAttributes; +import entities.PlayerInfo; + +/** + * Horde data access interface. Require the horde dataclass, player's location. Assume this is day 60, jumping to 61, + * this usecase will generate a description of outcome, jump to gameover page, displaying score. + */ +public interface HordeDataAccessInterface { + /** + * Get inventory of player. + * @return inventory of player. + */ + Inventory getInventory(); + + /** + * Get horde info. + * @return get horde info. + */ + Horde getHorde(); + + /** + * Get player attribute we need generalship. + * @return attribute of player. + */ + PlayerAttributes getPlayerAttributes(); + + /** + * Set player won states to true. + * @param won winning status updated. + */ + void setWon(boolean won); + + /** + * Get player info because we need to show the score. + * @return Player info data type. + */ + PlayerInfo getPlayerInfo(); +} diff --git a/src/main/java/usecases/endprocesshorde/HordeInputBoundary.java b/src/main/java/usecases/endprocesshorde/HordeInputBoundary.java new file mode 100644 index 000000000..701a1d6cd --- /dev/null +++ b/src/main/java/usecases/endprocesshorde/HordeInputBoundary.java @@ -0,0 +1,13 @@ +package usecases.endprocesshorde; + +/** + * Interactor will have execute method, take in inputdata and run. + */ +public interface HordeInputBoundary { + + /** + * Execute the main logic. + * @param inputData input data from player's side. + */ + void execute(HordeInputData inputData); +} diff --git a/src/main/java/usecases/endprocesshorde/HordeInputData.java b/src/main/java/usecases/endprocesshorde/HordeInputData.java new file mode 100644 index 000000000..feeae8132 --- /dev/null +++ b/src/main/java/usecases/endprocesshorde/HordeInputData.java @@ -0,0 +1,8 @@ +package usecases.endprocesshorde; + +/** + * No need of inputdata as this is automatic move, this usecase is only called when day hits 60 and player clicked + * next day. + */ +public class HordeInputData { +} diff --git a/src/main/java/usecases/endprocesshorde/HordeInteractor.java b/src/main/java/usecases/endprocesshorde/HordeInteractor.java new file mode 100644 index 000000000..6a6760f68 --- /dev/null +++ b/src/main/java/usecases/endprocesshorde/HordeInteractor.java @@ -0,0 +1,64 @@ +package usecases.endprocesshorde; + +import entities.EntityConstants; +import entities.Inventory; +import entities.PlayerAttributes; + +/** + * Interactor of horde processing, main logic happening. + */ +public class HordeInteractor implements HordeInputBoundary { + private HordeDataAccessInterface dataAccess; + private HordeOutputBoundary outputBoundary; + + public HordeInteractor(HordeDataAccessInterface dataaccess, HordeOutputBoundary outputboundary) { + this.dataAccess = dataaccess; + this.outputBoundary = outputboundary; + } + + @Override + public void execute(HordeInputData inputData) { + String message = ""; + final Inventory peopleInventory = dataAccess.getInventory(); + final int people = peopleInventory.getPeople(); + final Inventory weaponInventory = dataAccess.getInventory(); + final int weapon = weaponInventory.getWeapon(); + final PlayerAttributes playerAttributes = dataAccess.getPlayerAttributes(); + final int generalship = playerAttributes.getGeneralship(); + + final int armed = Math.min(weapon, people); + final double generalshipBonus = 1 + (generalship * 0.05); + final double firepower = armed * EntityConstants.ARMEDPEOPLEPOWER * generalshipBonus; + final double duration = dataAccess.getHorde().getDuration(); + final double peopleAmmount = dataAccess.getInventory().getPeople(); + final double thrift = dataAccess.getPlayerAttributes().getThrift(); + final double resourcerequired = duration * peopleAmmount + * (1 - EntityConstants.THRIFTIMPACTRESOURCELOSS * thrift); + final int hordeMagnitude = dataAccess.getHorde().getMagnitude(); + final int food = dataAccess.getInventory().getFood(); + final int water = dataAccess.getInventory().getWater(); + + if (firepower < hordeMagnitude) { + message = "Your groups firepower wasnt enough to stop the horde. Despite your best efforts, the" + + "overwhelming number of zombies overran your defenses."; + } + else if (food < resourcerequired) { + message = "Your group ran out of food while holding off the horde. Starvation weakened your " + + "survivors, and the zombies overwhelmed them."; + } + else if (water < resourcerequired) { + message = "Your group ran out of water during the prolonged defense. Dehydration sapped their strength, " + + "leaving them defenseless against the horde."; + } + else { + dataAccess.setWon(true); + message = "Your group successfully defended against the horde! With well-armed fighters, " + + "strong leadership, and ample supplies, you emerged victorious and kept the group safe."; + } + + final int score = dataAccess.getPlayerInfo().getScore(); + final HordeOutputData outputdata = new HordeOutputData(score, message); + outputBoundary.prepareSuccessView(outputdata); + } + +} diff --git a/src/main/java/usecases/endprocesshorde/HordeOutputBoundary.java b/src/main/java/usecases/endprocesshorde/HordeOutputBoundary.java new file mode 100644 index 000000000..f8269d3c4 --- /dev/null +++ b/src/main/java/usecases/endprocesshorde/HordeOutputBoundary.java @@ -0,0 +1,19 @@ +package usecases.endprocesshorde; + +/** + * Prepare successview, on the game over page. + */ +public interface HordeOutputBoundary { + + /** + * Prepare the success view with description of outcome and score player gained. + * @param outputData outputdata. + */ + void prepareSuccessView(HordeOutputData outputData); + + /** + * Prepare the failure view by the error message, not needed likely. + * @param errorMessage errormessage. + */ + void prepareFailureView(String errorMessage); +} diff --git a/src/main/java/usecases/endprocesshorde/HordeOutputData.java b/src/main/java/usecases/endprocesshorde/HordeOutputData.java new file mode 100644 index 000000000..99f0dbeea --- /dev/null +++ b/src/main/java/usecases/endprocesshorde/HordeOutputData.java @@ -0,0 +1,24 @@ +package usecases.endprocesshorde; + +/** + * Output data, consist of final outcome description, player's score. + */ +public class HordeOutputData { + private int points; + private String introduction; + + public HordeOutputData(int Score, String Description) { + this.points = Score; + this.introduction = Description; + } + + public int getPoints() { + + return points; + } + + public String getIntroduction() { + + return introduction; + } +} diff --git a/src/main/java/usecases/eventdecide/DecideEventDataAccessInterface.java b/src/main/java/usecases/eventdecide/DecideEventDataAccessInterface.java new file mode 100644 index 000000000..67cfe5cfd --- /dev/null +++ b/src/main/java/usecases/eventdecide/DecideEventDataAccessInterface.java @@ -0,0 +1,33 @@ +package usecases.eventdecide; + +import entities.Event; +import entities.Location; + +import java.util.ArrayList; + +/** + * Event deciding data access interface, which it need all lists of type event to get each probability of event, + * This usecase is responsible for deciding which event or events or no event happened on that day, and provide + * basic description of the event, as well as choices. consider this usecase as the before of respond usecase. + */ +public interface DecideEventDataAccessInterface { + + /** + * This method is responsible for get all event and their info. + * @return List of all events type data. + */ + ArrayList getALLEvents(); + + /** + * This method will set the decided events for that day. + * @param events events decided. + */ + void setDecidedEvents(ArrayList events); + + /** + * Get the player's current location, because certain event will only happen in certain location, Iceland + * blizzard etc. + * @return Location of the player. + */ + Location getLocation(); +} diff --git a/src/main/java/usecases/eventdecide/DecideEventInputBoundary.java b/src/main/java/usecases/eventdecide/DecideEventInputBoundary.java new file mode 100644 index 000000000..e3693c7ac --- /dev/null +++ b/src/main/java/usecases/eventdecide/DecideEventInputBoundary.java @@ -0,0 +1,13 @@ +package usecases.eventdecide; + +/** + * Input boundary of decide event, will have execute based on input data provided, in this case, input data won't be + * necessary as this is system automatic processing to the next day. + */ +public interface DecideEventInputBoundary { + /** + * Execute the decide event, which takes list of event from DAO, and inputdata. + * @param inputdata inputdata type. + */ + void execute(DecideEventInputData inputdata); +} diff --git a/src/main/java/usecases/eventdecide/DecideEventInputData.java b/src/main/java/usecases/eventdecide/DecideEventInputData.java new file mode 100644 index 000000000..2a3593042 --- /dev/null +++ b/src/main/java/usecases/eventdecide/DecideEventInputData.java @@ -0,0 +1,7 @@ +package usecases.eventdecide; + +/** + * This input data is not necessary, we need nothing more than the fact that is after a new day. + */ +public class DecideEventInputData { +} diff --git a/src/main/java/usecases/eventdecide/DecideEventInteractor.java b/src/main/java/usecases/eventdecide/DecideEventInteractor.java new file mode 100644 index 000000000..d147695e0 --- /dev/null +++ b/src/main/java/usecases/eventdecide/DecideEventInteractor.java @@ -0,0 +1,47 @@ +package usecases.eventdecide; + +import java.util.ArrayList; + +import entities.Event; +import entities.Location; + +/** + * Event decider interactor, given list of events, process it, return list of events which will be carried out + * though the day. + */ +public class DecideEventInteractor implements DecideEventInputBoundary { + private final DecideEventDataAccessInterface dataaccessobject; + private final DecideEventOutputBoundary outputboundary; + + public DecideEventInteractor(DecideEventDataAccessInterface dataaccessobject, + DecideEventOutputBoundary outputboundary) { + this.dataaccessobject = dataaccessobject; + this.outputboundary = outputboundary; + } + + @Override + public void execute(DecideEventInputData inputdata) { + final ArrayList events = dataaccessobject.getALLEvents(); + final ArrayList decidedEvents = new ArrayList<>(); + final Location location = dataaccessobject.getLocation(); + final String locationName = location.toString(); + final ArrayList decidedEventNames = new ArrayList<>(); + for (Event event : events) { + final ArrayList occuringlocations = event.getOccuringlocation(); + final double probability = event.getprobability(); + final double randomValue = Math.random(); + + if (randomValue < probability) { + if (occuringlocations.contains(locationName)) { + decidedEvents.add(event); + decidedEventNames.add(event.toString()); + // will only add if probability hits, and is one of the possible location which player is at. + } + } + } + dataaccessobject.setDecidedEvents(decidedEvents); + final DecideEventOutputData outputdata = new DecideEventOutputData(decidedEventNames); + outputboundary.prepareSuccessView(outputdata); + } + +} diff --git a/src/main/java/usecases/eventdecide/DecideEventOutputBoundary.java b/src/main/java/usecases/eventdecide/DecideEventOutputBoundary.java new file mode 100644 index 000000000..6c1b5e2a9 --- /dev/null +++ b/src/main/java/usecases/eventdecide/DecideEventOutputBoundary.java @@ -0,0 +1,19 @@ +package usecases.eventdecide; + +/** + * Deicde event, output boundary, though I can't really think of a way for it to fail, for people who are writing this, + * you can simply display "something went wrong" for fail view right now. + */ +public interface DecideEventOutputBoundary { + /** + * Outputs for a successful move. + * @param outputData the output for updating the view. + */ + void prepareSuccessView(DecideEventOutputData outputData); + + /** + * If the decide event is invaild, example: is on day 61? did player already lose?. + * @param errorMessage message of why is invaild, for the player. + */ + void prepareFailureView(String errorMessage); +} diff --git a/src/main/java/usecases/eventdecide/DecideEventOutputData.java b/src/main/java/usecases/eventdecide/DecideEventOutputData.java new file mode 100644 index 000000000..086790089 --- /dev/null +++ b/src/main/java/usecases/eventdecide/DecideEventOutputData.java @@ -0,0 +1,21 @@ +package usecases.eventdecide; + +import java.util.ArrayList; + +import entities.Event; + +/** + * Return the list of event decided, and waiting to be carried out on the following day. + * Usually, is a empty list, but as we add more event, is expected to be more. + */ +public class DecideEventOutputData { + private ArrayList events; + + public DecideEventOutputData(ArrayList events) { + this.events = events; + } + + public ArrayList getEvents() { + return events; + } +} diff --git a/src/main/java/usecases/eventinitialize/EventInitializeDataAccessInterface.java b/src/main/java/usecases/eventinitialize/EventInitializeDataAccessInterface.java new file mode 100644 index 000000000..c386066e5 --- /dev/null +++ b/src/main/java/usecases/eventinitialize/EventInitializeDataAccessInterface.java @@ -0,0 +1,16 @@ +package usecases.eventinitialize; + +import entities.Event; + +/** + * DAI of event initiaizer, assume this event is been chosen by event decider, this use case is for transform event + * to datatype which view needs, such as getting the choices, descriptions. + */ +public interface EventInitializeDataAccessInterface { + /** + * Get the event that's processing now. + * @return The event. + */ + Event getEvent(); + +} diff --git a/src/main/java/usecases/eventinitialize/EventInitializeInputBoundary.java b/src/main/java/usecases/eventinitialize/EventInitializeInputBoundary.java new file mode 100644 index 000000000..d4190625e --- /dev/null +++ b/src/main/java/usecases/eventinitialize/EventInitializeInputBoundary.java @@ -0,0 +1,12 @@ +package usecases.eventinitialize; + +/** + * Input boundary of event initializer, so interactor must have an execute method uses the inputdata. + */ +public interface EventInitializeInputBoundary { + /** + * An automatic usecase, no input from player side is needed. + * @param inputdata not really needed. + */ + void execute(EventInitializeInputData inputdata); +} diff --git a/src/main/java/usecases/eventinitialize/EventInitializeInputData.java b/src/main/java/usecases/eventinitialize/EventInitializeInputData.java new file mode 100644 index 000000000..6ab23f0c5 --- /dev/null +++ b/src/main/java/usecases/eventinitialize/EventInitializeInputData.java @@ -0,0 +1,7 @@ +package usecases.eventinitialize; + +/** + * Don't need any input data from player's side. this is automatic move. + */ +public class EventInitializeInputData { +} diff --git a/src/main/java/usecases/eventinitialize/EventInitializeInteractor.java b/src/main/java/usecases/eventinitialize/EventInitializeInteractor.java new file mode 100644 index 000000000..600e2c8b4 --- /dev/null +++ b/src/main/java/usecases/eventinitialize/EventInitializeInteractor.java @@ -0,0 +1,26 @@ +package usecases.eventinitialize; + +import java.util.Map; + +/** + * Interactor of event initialize, which tranform the given event to return output data type of description, + * and group of choices. + */ +public class EventInitializeInteractor implements EventInitializeInputBoundary { + private final EventInitializeDataAccessInterface dataAccessObject; + private final EventInitializeOutputBoundary outputBoundary; + + public EventInitializeInteractor(EventInitializeDataAccessInterface DataAccessObject, + EventInitializeOutputBoundary OutputBoundary) { + this.dataAccessObject = DataAccessObject; + this.outputBoundary = OutputBoundary; + } + + @Override + public void execute(EventInitializeInputData inputdata) { + final String description = dataAccessObject.getEvent().getdescription(); + final Map choices = dataAccessObject.getEvent().getchoices(); + final EventInitializeOutputData outputData = new EventInitializeOutputData(description, choices); + outputBoundary.prepareSuccessView(outputData); + } +} diff --git a/src/main/java/usecases/eventinitialize/EventInitializeOutputBoundary.java b/src/main/java/usecases/eventinitialize/EventInitializeOutputBoundary.java new file mode 100644 index 000000000..b6d9fd1dc --- /dev/null +++ b/src/main/java/usecases/eventinitialize/EventInitializeOutputBoundary.java @@ -0,0 +1,19 @@ +package usecases.eventinitialize; + +/** + * OutputBoundary of EventInitializer, it should display player with description, and group of choices button on the UI. + * Can't think of a way to fail, just write something went wrong in eventinitiallze if it happened. + */ +public interface EventInitializeOutputBoundary { + /** + * Outputs for a successful move. + * @param outputData the output for updating the view. + */ + void prepareSuccessView(EventInitializeOutputData outputData); + + /** + * If the use case is invaild. for example, no event was supposed to carry out but this got called. + * @param errorMessage message of why is invaild, for the player. + */ + void prepareFailureView(String errorMessage); +} diff --git a/src/main/java/usecases/eventinitialize/EventInitializeOutputData.java b/src/main/java/usecases/eventinitialize/EventInitializeOutputData.java new file mode 100644 index 000000000..9caec14ee --- /dev/null +++ b/src/main/java/usecases/eventinitialize/EventInitializeOutputData.java @@ -0,0 +1,33 @@ +package usecases.eventinitialize; + +import java.util.Map; + +/** + * The return data from interact, contain the description of the event, and choices. + */ +public class EventInitializeOutputData { + private String description; + private Map choices; + + public EventInitializeOutputData(String description, Map choices) { + this.description = description; + this.choices = choices; + } + + /** + * Get the choice for key input. + * @param key key, in number + * @return String of the choice representation. + */ + public String getChoice(int key) { + return choices.get(key); + } + + public String getDescription() { + return description; + } + + public Map getChoices() { + return choices; + } +} diff --git a/src/main/java/usecases/eventrespond/ambush/AmbushDataAccessInterface.java b/src/main/java/usecases/eventrespond/ambush/AmbushDataAccessInterface.java new file mode 100644 index 000000000..f6ee52682 --- /dev/null +++ b/src/main/java/usecases/eventrespond/ambush/AmbushDataAccessInterface.java @@ -0,0 +1,28 @@ +package usecases.eventrespond.ambush; + +import entities.Event; +import entities.Inventory; + +import java.util.Map; + +/** + * Interface for data access in the Ambush event. + */ +public interface AmbushDataAccessInterface { + Event getEvent(); + void removeEvent(); + Inventory getInventory(); + + /** + * Returns player attributes as a map. + * Key: Attribute name (e.g., "Social"). + * Value: Attribute value. + * @return Map of player attributes. + */ + Map getPlayerAttributesAsMap(); + + void changeFood(int amount); + void changeWater(int amount); + void changeWeapon(int amount); + void changePeople(int amount); +} \ No newline at end of file diff --git a/src/main/java/usecases/eventrespond/ambush/AmbushEventInteractor.java b/src/main/java/usecases/eventrespond/ambush/AmbushEventInteractor.java new file mode 100644 index 000000000..aaf50c644 --- /dev/null +++ b/src/main/java/usecases/eventrespond/ambush/AmbushEventInteractor.java @@ -0,0 +1,92 @@ +package usecases.eventrespond.ambush; + +import entities.EntityConstants; +import entities.EventAmbush; +import usecases.chatgpt.ChatGptService; +import usecases.chatgpt.ChatGptResponseParser; + +import java.util.Map; + +/** + * Interactor for handling player responses to an Ambush event. + * Delegates response generation to ChatGPT and applies game logic based on the response. + */ +public class AmbushEventInteractor implements AmbushInputBoundary { + private final AmbushDataAccessInterface dataAccess; + private final AmbushOutputBoundary outputBoundary; + private final ChatGptService chatGptService; + + public AmbushEventInteractor(AmbushDataAccessInterface dataAccess, + AmbushOutputBoundary outputBoundary, + ChatGptService chatGptService) { + this.dataAccess = dataAccess; + this.outputBoundary = outputBoundary; + this.chatGptService = chatGptService; + } + + @Override + public void execute(AmbushInputData inputData) { + EventAmbush ambushEvent = (EventAmbush) dataAccess.getEvent(); + Map playerAttributes = dataAccess.getPlayerAttributesAsMap(); + int playerChoice = inputData.getChoice(); + + try { + // Determine the choice description + String choiceDescription = ambushEvent.getchoices().get(playerChoice); + + // Call ChatGPT to generate the event outcome + String chatResponse = chatGptService.getResponse(ambushEvent.getdescription(), playerAttributes, choiceDescription); + + // Parse the ChatGPT response + String eventOutcome = ChatGptResponseParser.parseEventOutcome(chatResponse); + + // Apply game logic based on the player's choice + int foodChange = 0, waterChange = 0, weaponChange = 0, peopleChange = 0; + if (playerChoice == EntityConstants.FIRSTCHOICE) { + // Fight back logic + if (dataAccess.getInventory().getfirepower() >= EntityConstants.AMBUSHPOWER) { + foodChange = EntityConstants.AMBUSHFIGHTSUCCESSRESOURCEFOOD; + waterChange = EntityConstants.AMBUSHFIGHTSUCCESSRESOURCEWATER; + weaponChange = EntityConstants.AMBUSHFIGHTSUCCESSRESOURCEWEAPON; + peopleChange = EntityConstants.AMBUSHFIGHTSUCCESSRESOURCEPEOPLE; + } else { + foodChange = EntityConstants.AMBUSHFAILRESOURCEFOOD; + waterChange = EntityConstants.AMBUSHFAILRESOURCEWATER; + weaponChange = EntityConstants.AMBUSHFAILRESOURCEWEAPON; + peopleChange = EntityConstants.AMBUSHFAILRESOURCEPEOPLE; + } + } else if (playerChoice == EntityConstants.SECONDCHOICE) { + // Pay the bandits logic + foodChange = EntityConstants.AMBUSHFAILRESOURCEFOOD; + waterChange = EntityConstants.AMBUSHFAILRESOURCEWATER; + weaponChange = EntityConstants.AMBUSHFAILRESOURCEWEAPON; + } else if (playerChoice == EntityConstants.THIRDCHOICE) { + // Negotiate logic + if (playerAttributes.getOrDefault("Social", 0) >= EntityConstants.AMBUSHNEGOTIATE) { + // Success logic + } else { + foodChange = EntityConstants.AMBUSHFAILRESOURCEFOOD; + waterChange = EntityConstants.AMBUSHFAILRESOURCEWATER; + weaponChange = EntityConstants.AMBUSHFAILRESOURCEWEAPON; + } + } else { + throw new IllegalArgumentException("Invalid player choice: " + playerChoice); + } + + // Apply inventory changes + dataAccess.changeFood(foodChange); + dataAccess.changeWater(waterChange); + dataAccess.changeWeapon(weaponChange); + dataAccess.changePeople(peopleChange); + dataAccess.removeEvent(); + + // Prepare output + String inventoryMessage = "Resources changed: Food " + foodChange + ", Water " + waterChange + "."; + AmbushOutputData outputData = new AmbushOutputData(eventOutcome, foodChange, waterChange, weaponChange, peopleChange, inventoryMessage); + outputBoundary.prepareSuccessView(outputData); + + } catch (Exception e) { + outputBoundary.prepareFailureView("Failed to process ChatGPT response: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/java/usecases/eventrespond/ambush/AmbushInputBoundary.java b/src/main/java/usecases/eventrespond/ambush/AmbushInputBoundary.java new file mode 100644 index 000000000..4b3d499df --- /dev/null +++ b/src/main/java/usecases/eventrespond/ambush/AmbushInputBoundary.java @@ -0,0 +1,8 @@ +package usecases.eventrespond.ambush; + +/** + * Input boundary for handling Ambush event responses. + */ +public interface AmbushInputBoundary { + void execute(AmbushInputData inputData); +} diff --git a/src/main/java/usecases/eventrespond/ambush/AmbushInputData.java b/src/main/java/usecases/eventrespond/ambush/AmbushInputData.java new file mode 100644 index 000000000..6d021c3c8 --- /dev/null +++ b/src/main/java/usecases/eventrespond/ambush/AmbushInputData.java @@ -0,0 +1,16 @@ +package usecases.eventrespond.ambush; + +/** + * Input data for the Ambush event, representing the player's choice. + */ +public class AmbushInputData { + private final int choice; + + public AmbushInputData(int choice) { + this.choice = choice; + } + + public int getChoice() { + return choice; + } +} diff --git a/src/main/java/usecases/eventrespond/ambush/AmbushOutputBoundary.java b/src/main/java/usecases/eventrespond/ambush/AmbushOutputBoundary.java new file mode 100644 index 000000000..91efeba9d --- /dev/null +++ b/src/main/java/usecases/eventrespond/ambush/AmbushOutputBoundary.java @@ -0,0 +1,11 @@ +package usecases.eventrespond.ambush; + +import usecases.eventrespond.ambush.AmbushOutputData; + +/** + * Output boundary for handling Ambush event results. + */ +public interface AmbushOutputBoundary { + void prepareSuccessView(AmbushOutputData outputData); + void prepareFailureView(String errorMessage); +} diff --git a/src/main/java/usecases/eventrespond/ambush/AmbushOutputData.java b/src/main/java/usecases/eventrespond/ambush/AmbushOutputData.java new file mode 100644 index 000000000..5257b23fd --- /dev/null +++ b/src/main/java/usecases/eventrespond/ambush/AmbushOutputData.java @@ -0,0 +1,46 @@ +package usecases.eventrespond.ambush; + +/** + * Output data for the Ambush event, representing the outcome and resource changes. + */ +public class AmbushOutputData { + private final String message; + private final int foodChange; + private final int waterChange; + private final int weaponChange; + private final int peopleChange; + private final String inventoryMessage; + + public AmbushOutputData(String message, int foodChange, int waterChange, int weaponChange, int peopleChange, String inventoryMessage) { + this.message = message; + this.foodChange = foodChange; + this.waterChange = waterChange; + this.weaponChange = weaponChange; + this.peopleChange = peopleChange; + this.inventoryMessage = inventoryMessage; + } + + public String getMessage() { + return message; + } + + public int getFoodChange() { + return foodChange; + } + + public int getWaterChange() { + return waterChange; + } + + public int getWeaponChange() { + return weaponChange; + } + + public int getPeopleChange() { + return peopleChange; + } + + public String getInventoryMessage() { + return inventoryMessage; + } +} diff --git a/src/main/java/usecases/eventrespond/blizzard/BlizzardDataAccessInterface.java b/src/main/java/usecases/eventrespond/blizzard/BlizzardDataAccessInterface.java new file mode 100644 index 000000000..7433b5e95 --- /dev/null +++ b/src/main/java/usecases/eventrespond/blizzard/BlizzardDataAccessInterface.java @@ -0,0 +1,26 @@ +package usecases.eventrespond.blizzard; + +import entities.Event; +import entities.Inventory; + +import java.util.Map; + +/** + * Interface for data access in the Blizzard event. + */ +public interface BlizzardDataAccessInterface { + Event getEvent(); + void removeEvent(); + Inventory getInventory(); + + /** + * Returns player attributes as a map. + * Key: Attribute name (e.g., "Social"). + * Value: Attribute value. + * @return Map of player attributes. + */ + Map getPlayerAttributesAsMap(); + + void changeFood(int amount); + void changeWater(int amount); +} \ No newline at end of file diff --git a/src/main/java/usecases/eventrespond/blizzard/BlizzardEventInteractor.java b/src/main/java/usecases/eventrespond/blizzard/BlizzardEventInteractor.java new file mode 100644 index 000000000..dfe245d8c --- /dev/null +++ b/src/main/java/usecases/eventrespond/blizzard/BlizzardEventInteractor.java @@ -0,0 +1,66 @@ +package usecases.eventrespond.blizzard; + +import entities.EntityConstants; +import entities.EventBlizzard; +import usecases.chatgpt.ChatGptService; +import usecases.chatgpt.ChatGptResponseParser; + +import java.util.Map; + +/** + * Interactor for handling player responses to a Blizzard event. + */ +public class BlizzardEventInteractor implements BlizzardInputBoundary { + private final BlizzardDataAccessInterface dataAccess; + private final BlizzardOutputBoundary outputBoundary; + private final ChatGptService chatGptService; + + public BlizzardEventInteractor(BlizzardDataAccessInterface dataAccess, + BlizzardOutputBoundary outputBoundary, + ChatGptService chatGptService) { + this.dataAccess = dataAccess; + this.outputBoundary = outputBoundary; + this.chatGptService = chatGptService; + } + + @Override + public void execute(BlizzardInputData inputData) { + EventBlizzard blizzardEvent = (EventBlizzard) dataAccess.getEvent(); + Map playerAttributes = dataAccess.getPlayerAttributesAsMap(); + int playerChoice = inputData.getChoice(); + + try { + String choiceDescription = blizzardEvent.getchoices().get(playerChoice); + + String chatResponse = chatGptService.getResponse(blizzardEvent.getdescription(), playerAttributes, choiceDescription); + + String eventOutcome = ChatGptResponseParser.parseEventOutcome(chatResponse); + + int foodChange = 0, waterChange = 0; + + if (playerChoice == EntityConstants.FIRSTCHOICE) { + foodChange = EntityConstants.BLIZZARDRESOURCELOSSFOOD / 2; + waterChange = EntityConstants.BLIZZARDRESOURCELOSSWATER / 2; + } else if (playerChoice == EntityConstants.SECONDCHOICE) { + foodChange = EntityConstants.BLIZZARDRESOURCELOSSFOOD; + waterChange = EntityConstants.BLIZZARDRESOURCELOSSWATER; + } else if (playerChoice == EntityConstants.THIRDCHOICE) { + foodChange = EntityConstants.BLIZZARDRESOURCELOSSFOOD * 2; + waterChange = EntityConstants.BLIZZARDRESOURCELOSSWATER * 2; + } else { + throw new IllegalArgumentException("Invalid player choice: " + playerChoice); + } + + dataAccess.changeFood(foodChange); + dataAccess.changeWater(waterChange); + dataAccess.removeEvent(); + + String inventoryMessage = "Resources changed: Food " + foodChange + ", Water " + waterChange + "."; + BlizzardOutputData outputData = new BlizzardOutputData(eventOutcome, foodChange, waterChange, 0, 0, inventoryMessage); + outputBoundary.prepareSuccessView(outputData); + + } catch (Exception e) { + outputBoundary.prepareFailureView("Failed to process ChatGPT response: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/java/usecases/eventrespond/blizzard/BlizzardInputBoundary.java b/src/main/java/usecases/eventrespond/blizzard/BlizzardInputBoundary.java new file mode 100644 index 000000000..61e91a8c9 --- /dev/null +++ b/src/main/java/usecases/eventrespond/blizzard/BlizzardInputBoundary.java @@ -0,0 +1,8 @@ +package usecases.eventrespond.blizzard; + +/** + * Input boundary for handling Blizzard event responses. + */ +public interface BlizzardInputBoundary { + void execute(BlizzardInputData inputData); +} diff --git a/src/main/java/usecases/eventrespond/blizzard/BlizzardInputData.java b/src/main/java/usecases/eventrespond/blizzard/BlizzardInputData.java new file mode 100644 index 000000000..c4d0b0f58 --- /dev/null +++ b/src/main/java/usecases/eventrespond/blizzard/BlizzardInputData.java @@ -0,0 +1,16 @@ +package usecases.eventrespond.blizzard; + +/** + * Input data for the Blizzard event, representing the player's choice. + */ +public class BlizzardInputData { + private final int choice; + + public BlizzardInputData(int choice) { + this.choice = choice; + } + + public int getChoice() { + return choice; + } +} diff --git a/src/main/java/usecases/eventrespond/blizzard/BlizzardOutputBoundary.java b/src/main/java/usecases/eventrespond/blizzard/BlizzardOutputBoundary.java new file mode 100644 index 000000000..3caa42aa2 --- /dev/null +++ b/src/main/java/usecases/eventrespond/blizzard/BlizzardOutputBoundary.java @@ -0,0 +1,11 @@ +package usecases.eventrespond.blizzard; + +import usecases.eventrespond.blizzard.BlizzardOutputData; + +/** + * Output boundary for handling Blizzard event results. + */ +public interface BlizzardOutputBoundary { + void prepareSuccessView(BlizzardOutputData outputData); + void prepareFailureView(String errorMessage); +} diff --git a/src/main/java/usecases/eventrespond/blizzard/BlizzardOutputData.java b/src/main/java/usecases/eventrespond/blizzard/BlizzardOutputData.java new file mode 100644 index 000000000..b9fce8123 --- /dev/null +++ b/src/main/java/usecases/eventrespond/blizzard/BlizzardOutputData.java @@ -0,0 +1,46 @@ +package usecases.eventrespond.blizzard; + +/** + * Output data for the Blizzard event, representing the outcome and resource changes. + */ +public class BlizzardOutputData { + private final String message; + private final int foodChange; + private final int waterChange; + private final int weaponChange; + private final int peopleChange; + private final String inventoryMessage; + + public BlizzardOutputData(String message, int foodChange, int waterChange, int weaponChange, int peopleChange, String inventoryMessage) { + this.message = message; + this.foodChange = foodChange; + this.waterChange = waterChange; + this.weaponChange = weaponChange; + this.peopleChange = peopleChange; + this.inventoryMessage = inventoryMessage; + } + + public String getMessage() { + return message; + } + + public int getFoodChange() { + return foodChange; + } + + public int getWaterChange() { + return waterChange; + } + + public int getWeaponChange() { + return weaponChange; + } + + public int getPeopleChange() { + return peopleChange; + } + + public String getInventoryMessage() { + return inventoryMessage; + } +} diff --git a/src/main/java/usecases/eventrespond/flood/FloodDataAccessInterface.java b/src/main/java/usecases/eventrespond/flood/FloodDataAccessInterface.java new file mode 100644 index 000000000..8ca7892a6 --- /dev/null +++ b/src/main/java/usecases/eventrespond/flood/FloodDataAccessInterface.java @@ -0,0 +1,27 @@ +package usecases.eventrespond.flood; + +import entities.Event; +import entities.Inventory; + +import java.util.Map; + +/** + * Interface for data access in the Flood event. + */ +public interface FloodDataAccessInterface { + Event getEvent(); + void removeEvent(); + Inventory getInventory(); + + /** + * Returns player attributes as a map. + * Key: Attribute name (e.g., "Social"). + * Value: Attribute value. + * @return Map of player attributes. + */ + Map getPlayerAttributesAsMap(); + + void changeFood(int amount); + void changeWater(int amount); + void changePeople(int amount); +} \ No newline at end of file diff --git a/src/main/java/usecases/eventrespond/flood/FloodEventInteractor.java b/src/main/java/usecases/eventrespond/flood/FloodEventInteractor.java new file mode 100644 index 000000000..fbdc4fef3 --- /dev/null +++ b/src/main/java/usecases/eventrespond/flood/FloodEventInteractor.java @@ -0,0 +1,68 @@ +package usecases.eventrespond.flood; + +import entities.EntityConstants; +import entities.EventFlood; +import usecases.chatgpt.ChatGptService; +import usecases.chatgpt.ChatGptResponseParser; + +import java.util.Map; + +/** + * Interactor for handling player responses to a Flood event. + */ +public class FloodEventInteractor implements FloodInputBoundary { + private final FloodDataAccessInterface dataAccess; + private final FloodOutputBoundary outputBoundary; + private final ChatGptService chatGptService; + + public FloodEventInteractor(FloodDataAccessInterface dataAccess, + FloodOutputBoundary outputBoundary, + ChatGptService chatGptService) { + this.dataAccess = dataAccess; + this.outputBoundary = outputBoundary; + this.chatGptService = chatGptService; + } + + @Override + public void execute(FloodInputData inputData) { + EventFlood floodEvent = (EventFlood) dataAccess.getEvent(); + Map playerAttributes = dataAccess.getPlayerAttributesAsMap(); + int playerChoice = inputData.getChoice(); + + try { + String choiceDescription = floodEvent.getchoices().get(playerChoice); + + String chatResponse = chatGptService.getResponse(floodEvent.getdescription(), playerAttributes, choiceDescription); + + String eventOutcome = ChatGptResponseParser.parseEventOutcome(chatResponse); + + int foodChange = 0, waterChange = 0, peopleChange = 0; + + if (playerChoice == EntityConstants.FIRSTCHOICE) { + foodChange = EntityConstants.FLOODRESOURCELOSSFOOD; + peopleChange = EntityConstants.FLOODPEOPLELOSSLOW; + } else if (playerChoice == EntityConstants.SECONDCHOICE) { + foodChange = EntityConstants.FLOODRESOURCELOSSSECURE; + peopleChange = EntityConstants.FLOODPEOPLELOSSMODERATE; + } else if (playerChoice == EntityConstants.THIRDCHOICE) { + foodChange = EntityConstants.FLOODRESOURCELOSSHIGH; + peopleChange = EntityConstants.FLOODPEOPLELOSSHIGH; + } else { + throw new IllegalArgumentException("Invalid player choice: " + playerChoice); + } + + dataAccess.changeFood(foodChange); + dataAccess.changeWater(waterChange); + dataAccess.changePeople(peopleChange); + dataAccess.removeEvent(); + + String inventoryMessage = "Resources changed: Food " + foodChange + ", Water " + waterChange + + ", People " + peopleChange + "."; + FloodOutputData outputData = new FloodOutputData(eventOutcome, foodChange, waterChange, 0, peopleChange, inventoryMessage); + outputBoundary.prepareSuccessView(outputData); + + } catch (Exception e) { + outputBoundary.prepareFailureView("Failed to process ChatGPT response: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/java/usecases/eventrespond/flood/FloodInputBoundary.java b/src/main/java/usecases/eventrespond/flood/FloodInputBoundary.java new file mode 100644 index 000000000..b38d18e8d --- /dev/null +++ b/src/main/java/usecases/eventrespond/flood/FloodInputBoundary.java @@ -0,0 +1,8 @@ +package usecases.eventrespond.flood; + +/** + * Input boundary for handling Flood event responses. + */ +public interface FloodInputBoundary { + void execute(FloodInputData inputData); +} diff --git a/src/main/java/usecases/eventrespond/flood/FloodInputData.java b/src/main/java/usecases/eventrespond/flood/FloodInputData.java new file mode 100644 index 000000000..8177fa256 --- /dev/null +++ b/src/main/java/usecases/eventrespond/flood/FloodInputData.java @@ -0,0 +1,16 @@ +package usecases.eventrespond.flood; + +/** + * Input data for the Flood event, representing the player's choice. + */ +public class FloodInputData { + private final int choice; + + public FloodInputData(int choice) { + this.choice = choice; + } + + public int getChoice() { + return choice; + } +} diff --git a/src/main/java/usecases/eventrespond/flood/FloodOutputBoundary.java b/src/main/java/usecases/eventrespond/flood/FloodOutputBoundary.java new file mode 100644 index 000000000..91e421120 --- /dev/null +++ b/src/main/java/usecases/eventrespond/flood/FloodOutputBoundary.java @@ -0,0 +1,11 @@ +package usecases.eventrespond.flood; + +import usecases.eventrespond.flood.FloodOutputData; + +/** + * Output boundary for handling Flood event results. + */ +public interface FloodOutputBoundary { + void prepareSuccessView(FloodOutputData outputData); + void prepareFailureView(String errorMessage); +} diff --git a/src/main/java/usecases/eventrespond/flood/FloodOutputData.java b/src/main/java/usecases/eventrespond/flood/FloodOutputData.java new file mode 100644 index 000000000..ab8525e91 --- /dev/null +++ b/src/main/java/usecases/eventrespond/flood/FloodOutputData.java @@ -0,0 +1,46 @@ +package usecases.eventrespond.flood; + +/** + * Output data for the Flood event, representing the outcome and resource changes. + */ +public class FloodOutputData { + private final String message; + private final int foodChange; + private final int waterChange; + private final int weaponChange; + private final int peopleChange; + private final String inventoryMessage; + + public FloodOutputData(String message, int foodChange, int waterChange, int weaponChange, int peopleChange, String inventoryMessage) { + this.message = message; + this.foodChange = foodChange; + this.waterChange = waterChange; + this.weaponChange = weaponChange; + this.peopleChange = peopleChange; + this.inventoryMessage = inventoryMessage; + } + + public String getMessage() { + return message; + } + + public int getFoodChange() { + return foodChange; + } + + public int getWaterChange() { + return waterChange; + } + + public int getWeaponChange() { + return weaponChange; + } + + public int getPeopleChange() { + return peopleChange; + } + + public String getInventoryMessage() { + return inventoryMessage; + } +} diff --git a/src/main/java/usecases/eventrespond/survivor/SurvivorDataAccessInterface.java b/src/main/java/usecases/eventrespond/survivor/SurvivorDataAccessInterface.java new file mode 100644 index 000000000..c0fd3f8c1 --- /dev/null +++ b/src/main/java/usecases/eventrespond/survivor/SurvivorDataAccessInterface.java @@ -0,0 +1,27 @@ +package usecases.eventrespond.survivor; + +import entities.Event; +import entities.Inventory; + +import java.util.Map; + +/** + * Interface for data access in the Survivor Encounter event. + */ +public interface SurvivorDataAccessInterface { + Event getEvent(); + void removeEvent(); + Inventory getInventory(); + + /** + * Returns player attributes as a map. + * Key: Attribute name (e.g., "Social"). + * Value: Attribute value. + * @return Map of player attributes. + */ + Map getPlayerAttributesAsMap(); + + void changeFood(int amount); + void changeWeapon(int amount); + void changePeople(int amount); +} \ No newline at end of file diff --git a/src/main/java/usecases/eventrespond/survivor/SurvivorEventInteractor.java b/src/main/java/usecases/eventrespond/survivor/SurvivorEventInteractor.java new file mode 100644 index 000000000..d23e29e0d --- /dev/null +++ b/src/main/java/usecases/eventrespond/survivor/SurvivorEventInteractor.java @@ -0,0 +1,67 @@ +package usecases.eventrespond.survivor; + +import entities.EntityConstants; +import entities.EventSurvivorJoins; +import usecases.chatgpt.ChatGptService; +import usecases.chatgpt.ChatGptResponseParser; + +import java.util.Map; + +/** + * Interactor for handling player responses to a Survivor event. + */ +public class SurvivorEventInteractor implements SurvivorInputBoundary { + private final SurvivorDataAccessInterface dataAccess; + private final SurvivorOutputBoundary outputBoundary; + private final ChatGptService chatGptService; + + public SurvivorEventInteractor(SurvivorDataAccessInterface dataAccess, + SurvivorOutputBoundary outputBoundary, + ChatGptService chatGptService) { + this.dataAccess = dataAccess; + this.outputBoundary = outputBoundary; + this.chatGptService = chatGptService; + } + + @Override + public void execute(SurvivorInputData inputData) { + EventSurvivorJoins survivorEvent = (EventSurvivorJoins) dataAccess.getEvent(); + Map playerAttributes = dataAccess.getPlayerAttributesAsMap(); + int playerChoice = inputData.getChoice(); + + try { + String choiceDescription = survivorEvent.getchoices().get(playerChoice); + + String chatResponse = chatGptService.getResponse(survivorEvent.getdescription(), playerAttributes, choiceDescription); + + String eventOutcome = ChatGptResponseParser.parseEventOutcome(chatResponse); + + int foodChange = 0, waterChange = 0, suppliesChange = 0, peopleChange = 0; + + if (playerChoice == EntityConstants.FIRSTCHOICE) { + peopleChange = EntityConstants.SURVIVORACCEPTPEOPLEGAIN; + } else if (playerChoice == EntityConstants.SECONDCHOICE) { + // Reject survivors, no changes needed + } else if (playerChoice == EntityConstants.THIRDCHOICE) { + if (dataAccess.getInventory().getfirepower() >= EntityConstants.SURVIVORROBBERYPOWER) { + // Gain resources logic + } else { + // Robbery fail logic + } + } else { + throw new IllegalArgumentException("Invalid player choice: " + playerChoice); + } + + dataAccess.changePeople(peopleChange); + dataAccess.removeEvent(); + + String inventoryMessage = "Resources changed: Food " + foodChange + ", Water " + waterChange + + ", Supplies " + suppliesChange + ", People " + peopleChange + "."; + SurvivorOutputData outputData = new SurvivorOutputData(eventOutcome, foodChange, waterChange, suppliesChange, peopleChange, inventoryMessage); + outputBoundary.prepareSuccessView(outputData); + + } catch (Exception e) { + outputBoundary.prepareFailureView("Failed to process ChatGPT response: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/java/usecases/eventrespond/survivor/SurvivorInputBoundary.java b/src/main/java/usecases/eventrespond/survivor/SurvivorInputBoundary.java new file mode 100644 index 000000000..657b9f8de --- /dev/null +++ b/src/main/java/usecases/eventrespond/survivor/SurvivorInputBoundary.java @@ -0,0 +1,8 @@ +package usecases.eventrespond.survivor; + +/** + * Input boundary for handling Survivor event responses. + */ +public interface SurvivorInputBoundary { + void execute(SurvivorInputData inputData); +} diff --git a/src/main/java/usecases/eventrespond/survivor/SurvivorInputData.java b/src/main/java/usecases/eventrespond/survivor/SurvivorInputData.java new file mode 100644 index 000000000..22d0e9570 --- /dev/null +++ b/src/main/java/usecases/eventrespond/survivor/SurvivorInputData.java @@ -0,0 +1,16 @@ +package usecases.eventrespond.survivor; + +/** + * Input data for the Survivor event, representing the player's choice. + */ +public class SurvivorInputData { + private final int choice; + + public SurvivorInputData(int choice) { + this.choice = choice; + } + + public int getChoice() { + return choice; + } +} diff --git a/src/main/java/usecases/eventrespond/survivor/SurvivorOutputBoundary.java b/src/main/java/usecases/eventrespond/survivor/SurvivorOutputBoundary.java new file mode 100644 index 000000000..bf19df957 --- /dev/null +++ b/src/main/java/usecases/eventrespond/survivor/SurvivorOutputBoundary.java @@ -0,0 +1,11 @@ +package usecases.eventrespond.survivor; + +import usecases.eventrespond.survivor.SurvivorOutputData; + +/** + * Output boundary for handling Survivor event results. + */ +public interface SurvivorOutputBoundary { + void prepareSuccessView(SurvivorOutputData outputData); + void prepareFailureView(String errorMessage); +} diff --git a/src/main/java/usecases/eventrespond/survivor/SurvivorOutputData.java b/src/main/java/usecases/eventrespond/survivor/SurvivorOutputData.java new file mode 100644 index 000000000..35a8a0b82 --- /dev/null +++ b/src/main/java/usecases/eventrespond/survivor/SurvivorOutputData.java @@ -0,0 +1,46 @@ +package usecases.eventrespond.survivor; + +/** + * Output data for the Survivor event, representing the outcome and resource changes. + */ +public class SurvivorOutputData { + private final String message; + private final int foodChange; + private final int waterChange; + private final int suppliesChange; + private final int peopleChange; + private final String inventoryMessage; + + public SurvivorOutputData(String message, int foodChange, int waterChange, int suppliesChange, int peopleChange, String inventoryMessage) { + this.message = message; + this.foodChange = foodChange; + this.waterChange = waterChange; + this.suppliesChange = suppliesChange; + this.peopleChange = peopleChange; + this.inventoryMessage = inventoryMessage; + } + + public String getMessage() { + return message; + } + + public int getFoodChange() { + return foodChange; + } + + public int getWaterChange() { + return waterChange; + } + + public int getSuppliesChange() { + return suppliesChange; + } + + public int getPeopleChange() { + return peopleChange; + } + + public String getInventoryMessage() { + return inventoryMessage; + } +} diff --git a/src/main/java/usecases/eventrespond/trader/TraderDataAccessInterface.java b/src/main/java/usecases/eventrespond/trader/TraderDataAccessInterface.java new file mode 100644 index 000000000..9058cf05c --- /dev/null +++ b/src/main/java/usecases/eventrespond/trader/TraderDataAccessInterface.java @@ -0,0 +1,36 @@ +package usecases.eventrespond.trader; + +import entities.Event; +import entities.Inventory; +import entities.PlayerAttributes; + +import java.util.Map; + +/** + * Interface for data access in the Trader Encounter event. + */ +public interface TraderDataAccessInterface { + Event getEvent(); + void removeEvent(); + Inventory getInventory(); + + /** + * Returns player attributes as a map. + * Key: Attribute name (e.g., "Social"). + * Value: Attribute value. + * @return Map of player attributes. + */ + Map getPlayerAttributesAsMap(); + + /** + * Returns player attributes as an object. + * This is used when specific attribute methods are needed. + * @return PlayerAttributes object. + */ + PlayerAttributes getPlayerAttributes(); + + void changeFood(int amount); + void changeWater(int amount); + void changeWeapon(int amount); + void changePeople(int amount); +} \ No newline at end of file diff --git a/src/main/java/usecases/eventrespond/trader/TraderEventInteractor.java b/src/main/java/usecases/eventrespond/trader/TraderEventInteractor.java new file mode 100644 index 000000000..e5fdf81c2 --- /dev/null +++ b/src/main/java/usecases/eventrespond/trader/TraderEventInteractor.java @@ -0,0 +1,64 @@ +package usecases.eventrespond.trader; + +import entities.EntityConstants; +import entities.EventTraderEncounter; +import usecases.chatgpt.ChatGptService; +import usecases.chatgpt.ChatGptResponseParser; + +import java.util.Map; + +/** + * Interactor for handling player responses to a Trader event. + */ +public class TraderEventInteractor implements TraderInputBoundary { + private final TraderDataAccessInterface dataAccess; + private final TraderOutputBoundary outputBoundary; + private final ChatGptService chatGptService; + + public TraderEventInteractor(TraderDataAccessInterface dataAccess, + TraderOutputBoundary outputBoundary, + ChatGptService chatGptService) { + this.dataAccess = dataAccess; + this.outputBoundary = outputBoundary; + this.chatGptService = chatGptService; + } + + @Override + public void execute(TraderInputData inputData) { + EventTraderEncounter traderEvent = (EventTraderEncounter) dataAccess.getEvent(); + Map playerAttributes = dataAccess.getPlayerAttributesAsMap(); + int playerChoice = inputData.getChoice(); + + try { + String choiceDescription = traderEvent.getchoices().get(playerChoice); + + String chatResponse = chatGptService.getResponse(traderEvent.getdescription(), playerAttributes, choiceDescription); + + String eventOutcome = ChatGptResponseParser.parseEventOutcome(chatResponse); + + int foodChange = 0, waterChange = 0, suppliesChange = 0, peopleChange = 0; + + if (playerChoice == EntityConstants.FIRSTCHOICE) { + // Trade logic + } else if (playerChoice == EntityConstants.SECONDCHOICE) { + // Ignore logic + } else if (playerChoice == EntityConstants.THIRDCHOICE) { + // Rob logic + } else { + throw new IllegalArgumentException("Invalid player choice: " + playerChoice); + } + + dataAccess.changeFood(foodChange); + dataAccess.changeWeapon(suppliesChange); + dataAccess.removeEvent(); + + String inventoryMessage = "Resources changed: Food " + foodChange + ", Water " + waterChange + + ", Supplies " + suppliesChange + ", People " + peopleChange + "."; + TraderOutputData outputData = new TraderOutputData(eventOutcome, foodChange, waterChange, suppliesChange, peopleChange, inventoryMessage); + outputBoundary.prepareSuccessView(outputData); + + } catch (Exception e) { + outputBoundary.prepareFailureView("Failed to process ChatGPT response: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/java/usecases/eventrespond/trader/TraderInputBoundary.java b/src/main/java/usecases/eventrespond/trader/TraderInputBoundary.java new file mode 100644 index 000000000..10d7642be --- /dev/null +++ b/src/main/java/usecases/eventrespond/trader/TraderInputBoundary.java @@ -0,0 +1,8 @@ +package usecases.eventrespond.trader; + +/** + * Input boundary for handling Trader event responses. + */ +public interface TraderInputBoundary { + void execute(TraderInputData inputData); +} diff --git a/src/main/java/usecases/eventrespond/trader/TraderInputData.java b/src/main/java/usecases/eventrespond/trader/TraderInputData.java new file mode 100644 index 000000000..65adfb71d --- /dev/null +++ b/src/main/java/usecases/eventrespond/trader/TraderInputData.java @@ -0,0 +1,16 @@ +package usecases.eventrespond.trader; + +/** + * Input data for the Trader event, representing the player's choice. + */ +public class TraderInputData { + private final int choice; + + public TraderInputData(int choice) { + this.choice = choice; + } + + public int getChoice() { + return choice; + } +} diff --git a/src/main/java/usecases/eventrespond/trader/TraderOutputBoundary.java b/src/main/java/usecases/eventrespond/trader/TraderOutputBoundary.java new file mode 100644 index 000000000..92a17e6e6 --- /dev/null +++ b/src/main/java/usecases/eventrespond/trader/TraderOutputBoundary.java @@ -0,0 +1,11 @@ +package usecases.eventrespond.trader; + +import usecases.eventrespond.trader.TraderOutputData; + +/** + * Output boundary for handling Trader event results. + */ +public interface TraderOutputBoundary { + void prepareSuccessView(TraderOutputData outputData); + void prepareFailureView(String errorMessage); +} diff --git a/src/main/java/usecases/eventrespond/trader/TraderOutputData.java b/src/main/java/usecases/eventrespond/trader/TraderOutputData.java new file mode 100644 index 000000000..296efc0a0 --- /dev/null +++ b/src/main/java/usecases/eventrespond/trader/TraderOutputData.java @@ -0,0 +1,46 @@ +package usecases.eventrespond.trader; + +/** + * Output data for the Trader event, representing the outcome and resource changes. + */ +public class TraderOutputData { + private final String message; + private final int foodChange; + private final int waterChange; + private final int suppliesChange; + private final int peopleChange; + private final String inventoryMessage; + + public TraderOutputData(String message, int foodChange, int waterChange, int suppliesChange, int peopleChange, String inventoryMessage) { + this.message = message; + this.foodChange = foodChange; + this.waterChange = waterChange; + this.suppliesChange = suppliesChange; + this.peopleChange = peopleChange; + this.inventoryMessage = inventoryMessage; + } + + public String getMessage() { + return message; + } + + public int getFoodChange() { + return foodChange; + } + + public int getWaterChange() { + return waterChange; + } + + public int getSuppliesChange() { + return suppliesChange; + } + + public int getPeopleChange() { + return peopleChange; + } + + public String getInventoryMessage() { + return inventoryMessage; + } +} diff --git a/src/main/java/usecases/fetchcurrentevent/CurrentEventDataAccessInterface.java b/src/main/java/usecases/fetchcurrentevent/CurrentEventDataAccessInterface.java new file mode 100644 index 000000000..634706da8 --- /dev/null +++ b/src/main/java/usecases/fetchcurrentevent/CurrentEventDataAccessInterface.java @@ -0,0 +1,10 @@ +package usecases.fetchcurrentevent; + +import entities.Event; + +/** + * Current event data access. + */ +public interface CurrentEventDataAccessInterface { + Event getEvent(); +} diff --git a/src/main/java/usecases/fetchcurrentevent/CurrentEventInputBoundary.java b/src/main/java/usecases/fetchcurrentevent/CurrentEventInputBoundary.java new file mode 100644 index 000000000..8c54ae57c --- /dev/null +++ b/src/main/java/usecases/fetchcurrentevent/CurrentEventInputBoundary.java @@ -0,0 +1,8 @@ +package usecases.fetchcurrentevent; + +/** + * Execute. + */ +public interface CurrentEventInputBoundary { + void execute(CurrentEventInputData inputData); +} diff --git a/src/main/java/usecases/fetchcurrentevent/CurrentEventInputData.java b/src/main/java/usecases/fetchcurrentevent/CurrentEventInputData.java new file mode 100644 index 000000000..bc83f21fe --- /dev/null +++ b/src/main/java/usecases/fetchcurrentevent/CurrentEventInputData.java @@ -0,0 +1,7 @@ +package usecases.fetchcurrentevent; + +/** + * Inputdata not needed. + */ +public class CurrentEventInputData { +} diff --git a/src/main/java/usecases/fetchcurrentevent/CurrentEventInteractor.java b/src/main/java/usecases/fetchcurrentevent/CurrentEventInteractor.java new file mode 100644 index 000000000..fa9c05137 --- /dev/null +++ b/src/main/java/usecases/fetchcurrentevent/CurrentEventInteractor.java @@ -0,0 +1,23 @@ +package usecases.fetchcurrentevent; + +import entities.Event; + +/** + * Current event interactor. + */ +public class CurrentEventInteractor implements CurrentEventInputBoundary { + private CurrentEventDataAccessInterface dataaccess; + private CurrentEventOutputBoundary outputBoundary; + + public CurrentEventInteractor(CurrentEventDataAccessInterface dataaccess, + CurrentEventOutputBoundary outputBoundary) { + this.dataaccess = dataaccess; + this.outputBoundary = outputBoundary; + } + + @Override + public void execute(CurrentEventInputData inputData) { + final Event event = dataaccess.getEvent(); + outputBoundary.presentcurrentEvent(new CurrentEventOutputData(event)); + } +} diff --git a/src/main/java/usecases/fetchcurrentevent/CurrentEventOutputBoundary.java b/src/main/java/usecases/fetchcurrentevent/CurrentEventOutputBoundary.java new file mode 100644 index 000000000..f4623596a --- /dev/null +++ b/src/main/java/usecases/fetchcurrentevent/CurrentEventOutputBoundary.java @@ -0,0 +1,10 @@ +package usecases.fetchcurrentevent; + +import entities.Event; + +/** + * Not needed as this is simply just passing the current event. + */ +public interface CurrentEventOutputBoundary { + void presentcurrentEvent(CurrentEventOutputData currentEventOutputData); +} diff --git a/src/main/java/usecases/fetchcurrentevent/CurrentEventOutputData.java b/src/main/java/usecases/fetchcurrentevent/CurrentEventOutputData.java new file mode 100644 index 000000000..062031951 --- /dev/null +++ b/src/main/java/usecases/fetchcurrentevent/CurrentEventOutputData.java @@ -0,0 +1,18 @@ +package usecases.fetchcurrentevent; + +import entities.Event; + +/** + * Not needed, nothing to present to UI. + */ +public class CurrentEventOutputData { + private Event currentEvent; + + public CurrentEventOutputData(Event currentEvent) { + this.currentEvent = currentEvent; + } + + public Event getCurrentEvent() { + return currentEvent; + } +} diff --git a/src/main/java/usecases/fetchresource/FetchDataAccessInterface.java b/src/main/java/usecases/fetchresource/FetchDataAccessInterface.java new file mode 100644 index 000000000..9b6a8c762 --- /dev/null +++ b/src/main/java/usecases/fetchresource/FetchDataAccessInterface.java @@ -0,0 +1,22 @@ +package usecases.fetchresource; + +import entities.Inventory; +import entities.PlayerInfo; + +/** + * Data access of fetch, get player inventory, as well as num of day and action points left. + */ +public interface FetchDataAccessInterface { + + /** + * Get player's inventory. + * @return inventory + */ + Inventory getInventory(); + + /** + * Get player info, we need action point, and days. + * @return player info. + */ + PlayerInfo getPlayerInfo(); +} diff --git a/src/main/java/usecases/fetchresource/FetchInputBoundary.java b/src/main/java/usecases/fetchresource/FetchInputBoundary.java new file mode 100644 index 000000000..c8553514b --- /dev/null +++ b/src/main/java/usecases/fetchresource/FetchInputBoundary.java @@ -0,0 +1,13 @@ +package usecases.fetchresource; + +/** + * Input boundary for fetch. + */ +public interface FetchInputBoundary { + + /** + * Get the input data and execute. + * @param inputData inputdata type from player side, no needed. + */ + void execute(FetchInputData inputData); +} diff --git a/src/main/java/usecases/fetchresource/FetchInputData.java b/src/main/java/usecases/fetchresource/FetchInputData.java new file mode 100644 index 000000000..5135be42f --- /dev/null +++ b/src/main/java/usecases/fetchresource/FetchInputData.java @@ -0,0 +1,7 @@ +package usecases.fetchresource; + +/** + * Auto matic move, nothing needed. + */ +public class FetchInputData { +} diff --git a/src/main/java/usecases/fetchresource/FetchInteractor.java b/src/main/java/usecases/fetchresource/FetchInteractor.java new file mode 100644 index 000000000..b91248a4b --- /dev/null +++ b/src/main/java/usecases/fetchresource/FetchInteractor.java @@ -0,0 +1,24 @@ +package usecases.fetchresource; + +/** + * Data access interactor for fetch, this is used to provide real time and updated resource player had to display. + * Will get called after any usecase that changed player's inventory. + */ +public class FetchInteractor implements FetchInputBoundary { + private FetchDataAccessInterface dataaccess; + private FetchOutputBoundary outputBoundary; + + public FetchInteractor(FetchDataAccessInterface dataaccess, FetchOutputBoundary outputBoundary) { + this.dataaccess = dataaccess; + this.outputBoundary = outputBoundary; + } + + @Override + public void execute(FetchInputData inputData) { + final FetchOutputData outputdata = new FetchOutputData(dataaccess.getInventory().getFood(), + dataaccess.getInventory().getWater(), dataaccess.getInventory().getPeople(), + dataaccess.getInventory().getWeapon(), dataaccess.getPlayerInfo().getDaysSurvived(), + dataaccess.getPlayerInfo().getActionPoint()); + outputBoundary.prepareSuccessview(outputdata); + } +} diff --git a/src/main/java/usecases/fetchresource/FetchOutputBoundary.java b/src/main/java/usecases/fetchresource/FetchOutputBoundary.java new file mode 100644 index 000000000..eb21fdd2b --- /dev/null +++ b/src/main/java/usecases/fetchresource/FetchOutputBoundary.java @@ -0,0 +1,13 @@ +package usecases.fetchresource; + +/** + * Output boundary for fetch. + */ +public interface FetchOutputBoundary { + + /** + * Prepare success view given outputdata. + * @param outputdata outputdata, which are like food, water, people, weapon. + */ + void prepareSuccessview(FetchOutputData outputdata); +} diff --git a/src/main/java/usecases/fetchresource/FetchOutputData.java b/src/main/java/usecases/fetchresource/FetchOutputData.java new file mode 100644 index 000000000..881225b2f --- /dev/null +++ b/src/main/java/usecases/fetchresource/FetchOutputData.java @@ -0,0 +1,46 @@ +package usecases.fetchresource; + +/** + * Output datatype for fetch, which fethes all the thing in inventory. + */ +public class FetchOutputData { + private int food; + private int water; + private int people; + private int weapon; + private int day; + private int actionpoint; + + public FetchOutputData(int food, int water, int people, int weapon, int day, int actionpoint) { + this.food = food; + this.water = water; + this.people = people; + this.weapon = weapon; + this.day = day; + this.actionpoint = actionpoint; + } + + public int getFood() { + return food; + } + + public int getWater() { + return water; + } + + public int getPeople() { + return people; + } + + public int getWeapon() { + return weapon; + } + + public int getDay() { + return day; + } + + public int getActionpoint() { + return actionpoint; + } +} diff --git a/src/main/java/usecases/gamelosedetecter/LoseDataAccessInterface.java b/src/main/java/usecases/gamelosedetecter/LoseDataAccessInterface.java new file mode 100644 index 000000000..84057eb36 --- /dev/null +++ b/src/main/java/usecases/gamelosedetecter/LoseDataAccessInterface.java @@ -0,0 +1,14 @@ +package usecases.gamelosedetecter; + +import entities.Inventory; +import entities.PlayerInfo; + +/** + * Use player's inventory to decide if they lose, if any is 0. + */ +public interface LoseDataAccessInterface { + Inventory getInventory(); + + PlayerInfo getPlayerInfo(); + +} diff --git a/src/main/java/usecases/gamelosedetecter/LoseInputBoundary.java b/src/main/java/usecases/gamelosedetecter/LoseInputBoundary.java new file mode 100644 index 000000000..501bea3bb --- /dev/null +++ b/src/main/java/usecases/gamelosedetecter/LoseInputBoundary.java @@ -0,0 +1,8 @@ +package usecases.gamelosedetecter; + +/** + * Input boundary, execute. + */ +public interface LoseInputBoundary { + void execute(LoseInputData inputData); +} diff --git a/src/main/java/usecases/gamelosedetecter/LoseInputData.java b/src/main/java/usecases/gamelosedetecter/LoseInputData.java new file mode 100644 index 000000000..c1ea62ac7 --- /dev/null +++ b/src/main/java/usecases/gamelosedetecter/LoseInputData.java @@ -0,0 +1,7 @@ +package usecases.gamelosedetecter; + +/** + * Not needed. + */ +public class LoseInputData { +} diff --git a/src/main/java/usecases/gamelosedetecter/LoseInteractor.java b/src/main/java/usecases/gamelosedetecter/LoseInteractor.java new file mode 100644 index 000000000..53a780c27 --- /dev/null +++ b/src/main/java/usecases/gamelosedetecter/LoseInteractor.java @@ -0,0 +1,48 @@ +package usecases.gamelosedetecter; + +import entities.Inventory; + +/** + * Interface for lose check. + */ +public class LoseInteractor implements LoseInputBoundary { + private LoseDataAccessInterface dataaccess; + private LoseOutputBoundary outputBoundary; + + public LoseInteractor(LoseDataAccessInterface dataaccess, LoseOutputBoundary outputBoundary) { + this.dataaccess = dataaccess; + this.outputBoundary = outputBoundary; + } + + @Override + public void execute(LoseInputData inputData) { + String loseMessage = ""; + final Inventory inventory = dataaccess.getInventory(); + final int food = inventory.getFood(); + final int water = inventory.getWater(); + final int weapon = inventory.getWeapon(); + final int people = inventory.getPeople(); + + if (food <= 0) { + loseMessage = "Without food, morale crumbled. The group dispersed, unable to survive together any longer."; + } + else if (water <= 0) { + loseMessage = "With no water to sustain them, the group suffered dehydration. One by one, they perished."; + } + else if (people <= 0) { + loseMessage = "Everyone in your group has perished. There is no one left to continue the journey."; + } + else if (weapon <= 0) { + loseMessage = "Defenseless and exposed, your group was overtaken by a hostile faction. " + + "They took everything by force."; + } + + if (!loseMessage.isEmpty()) { + // Call output boundary with the failure message + final int score = dataaccess.getPlayerInfo().getScore(); + final LoseOutputData outputData = new LoseOutputData(loseMessage, score); + outputBoundary.preapareGameoverEarly(outputData); + } + // do nothing if player is not losing. + } +} diff --git a/src/main/java/usecases/gamelosedetecter/LoseOutputBoundary.java b/src/main/java/usecases/gamelosedetecter/LoseOutputBoundary.java new file mode 100644 index 000000000..b95efa084 --- /dev/null +++ b/src/main/java/usecases/gamelosedetecter/LoseOutputBoundary.java @@ -0,0 +1,8 @@ +package usecases.gamelosedetecter; + +/** + * Output Boundary. + */ +public interface LoseOutputBoundary { + void preapareGameoverEarly(LoseOutputData loseOutputData); +} diff --git a/src/main/java/usecases/gamelosedetecter/LoseOutputData.java b/src/main/java/usecases/gamelosedetecter/LoseOutputData.java new file mode 100644 index 000000000..ded427406 --- /dev/null +++ b/src/main/java/usecases/gamelosedetecter/LoseOutputData.java @@ -0,0 +1,22 @@ +package usecases.gamelosedetecter; + +/** + * Display brief description, how and why you lose. + */ +public class LoseOutputData { + private String losedescription; + private int score; + + public LoseOutputData(String losedescription, int score) { + this.losedescription = losedescription; + this.score = score; + } + + public String getLosedescription() { + return losedescription; + } + + public int getScore() { + return score; + } +} diff --git a/src/main/java/usecases/gameminimap/MinimapDataAccessInterface.java b/src/main/java/usecases/gameminimap/MinimapDataAccessInterface.java new file mode 100644 index 000000000..e6662cf06 --- /dev/null +++ b/src/main/java/usecases/gameminimap/MinimapDataAccessInterface.java @@ -0,0 +1,22 @@ +package usecases.gameminimap; + +import entities.Maps; +import entities.PlayerLocation; + +/** + * To return the minimap (default) 9x9 , we need player's location, and whole map. + */ +public interface MinimapDataAccessInterface { + + /** + * Get the current player location in player location data type(x and y all stored). + * @return Player's location. + */ + PlayerLocation getPlayerLocation(); + + /** + * Get the maps of the this game. + * @return Map of the current game. + */ + Maps getMaps(); +} diff --git a/src/main/java/usecases/gameminimap/MinimapInputBoundary.java b/src/main/java/usecases/gameminimap/MinimapInputBoundary.java new file mode 100644 index 000000000..e5d3e413b --- /dev/null +++ b/src/main/java/usecases/gameminimap/MinimapInputBoundary.java @@ -0,0 +1,14 @@ +package usecases.gameminimap; + +/** + * Providing inputdata, the interactor takes it and execute, though we don't need input from + * player's side as it is automatic move. + */ +public interface MinimapInputBoundary { + + /** + * Execute the interactor, providing inputdata. + * @param inputdata inputdata type, we don't really need that. + */ + void execute(MinimapInputData inputdata); +} diff --git a/src/main/java/usecases/gameminimap/MinimapInputData.java b/src/main/java/usecases/gameminimap/MinimapInputData.java new file mode 100644 index 000000000..d761c570c --- /dev/null +++ b/src/main/java/usecases/gameminimap/MinimapInputData.java @@ -0,0 +1,7 @@ +package usecases.gameminimap; + +/** + * Since this is automatic move, no data from player's side is needed. + */ +public class MinimapInputData { +} diff --git a/src/main/java/usecases/gameminimap/MinimapInteractor.java b/src/main/java/usecases/gameminimap/MinimapInteractor.java new file mode 100644 index 000000000..892ed7e81 --- /dev/null +++ b/src/main/java/usecases/gameminimap/MinimapInteractor.java @@ -0,0 +1,48 @@ +package usecases.gameminimap; + +import java.util.ArrayList; + +import entities.EntityConstants; +import entities.Location; + +/** + * Minimap usecase interactor, given nothing from player's side, only data of player's location, and map. + * Return the list of list of char used for mini map view prepare. + */ +public class MinimapInteractor implements MinimapInputBoundary { + private MinimapDataAccessInterface dataaccess; + private MinimapOutputBoundary outputBoundary; + + public MinimapInteractor(MinimapDataAccessInterface dataaccess, MinimapOutputBoundary outputBoundary) { + this.dataaccess = dataaccess; + this.outputBoundary = outputBoundary; + } + + @Override + public void execute(MinimapInputData inputdata) { + final ArrayList> minimap = new ArrayList(); + final ArrayList> grids = dataaccess.getMaps().getGrid(); + final int xcoor = dataaccess.getPlayerLocation().getXcoordinate(); + final int minxcoor = xcoor - EntityConstants.MINIMAPRADIUS; + final int maxxcoor = xcoor + EntityConstants.MINIMAPRADIUS; + final int ycoor = dataaccess.getPlayerLocation().getYcoordinate(); + final int minycoor = ycoor - EntityConstants.MINIMAPRADIUS; + final int maxycoor = ycoor + EntityConstants.MINIMAPRADIUS; + for (int y = minycoor; y <= maxycoor; y++) { + final ArrayList row = new ArrayList(); + for (int x = minxcoor; x <= maxxcoor; x++) { + if (EntityConstants.MAPWIDTH >= x + 1 && EntityConstants.MAPHEIGHT >= y + 1 && x >= 0 && y >= 0) { + row.add(grids.get(y).get(x).toString().substring(0, 1)); + // get the first letter as representative of map grid. + } + else { + row.add(" "); + // empty representing outside of Map + } + } + minimap.add(row); + } + final MinimapOutputData outputData = new MinimapOutputData(minimap); + outputBoundary.preparesuccessview(outputData); + } +} diff --git a/src/main/java/usecases/gameminimap/MinimapOutputBoundary.java b/src/main/java/usecases/gameminimap/MinimapOutputBoundary.java new file mode 100644 index 000000000..55b12d431 --- /dev/null +++ b/src/main/java/usecases/gameminimap/MinimapOutputBoundary.java @@ -0,0 +1,13 @@ +package usecases.gameminimap; + +/** + * The output Boundary of minimap usecase, prepare successview. + */ +public interface MinimapOutputBoundary { + + /** + * If the minimap usecase was a success, this should prepare the view on the minimap using the list of list of char. + * @param outputdata list of list of char representing each location type. + */ + void preparesuccessview(MinimapOutputData outputdata); +} diff --git a/src/main/java/usecases/gameminimap/MinimapOutputData.java b/src/main/java/usecases/gameminimap/MinimapOutputData.java new file mode 100644 index 000000000..095602648 --- /dev/null +++ b/src/main/java/usecases/gameminimap/MinimapOutputData.java @@ -0,0 +1,18 @@ +package usecases.gameminimap; + +import java.util.ArrayList; + +/** + * Output data type of minimap, this is list of list of single letter string representation of location. + */ +public class MinimapOutputData { + private ArrayList> minimap; + + public MinimapOutputData(ArrayList> minimap) { + this.minimap = minimap; + } + + public ArrayList> getMinimap() { + return minimap; + } +} diff --git a/src/main/java/usecases/gamenewday/NewdayDataAccessInterface.java b/src/main/java/usecases/gamenewday/NewdayDataAccessInterface.java new file mode 100644 index 000000000..85c5e82ae --- /dev/null +++ b/src/main/java/usecases/gamenewday/NewdayDataAccessInterface.java @@ -0,0 +1,90 @@ +package usecases.gamenewday; + +import entities.*; + +import java.util.ArrayList; + +/** + * Newday data access, require player's info because we care and need to update days and score. + * Require inventory because this part is for updating recources, how many lose, how many found depended on people num. + * Require player attribute because thrift is scalar to resource lost (food and water) + */ +public interface NewdayDataAccessInterface { + /** + * Get the player info we needed, score and days. + * @return playerinfo datatype. + */ + PlayerInfo getPlayerInfo(); + + /** + * Get location of there player is at, because we need temperature to calculate resource loss as well. + * @return the player's current location, in order to get current temperature. + */ + Location getLocation(); + + /** + * Get the player inventory we need, food water, people, firearm etc. + * @return inventory. + */ + Inventory getInventory(); + + /** + * Set the number of days player survived to new value. (+1) + * @param days new days + */ + void setDaysSurvived(int days); + + /** + * Set the score to new value. + * @param score new score. + */ + void setScore(int score); + + /** + * The amount of food change during new day process. + * @param food food changed + */ + void changeFood(int food); + + /** + * The amount of water change during the new day process. + * @param water water changed + */ + void changeWater(int water); + + /** + * The amount of people change during the new day process. + * @param people people changed + */ + void changePeople(int people); + + /** + * The amount of weapon change during the new day process. + * @param weapon weapon changed + */ + void changeWeapon(int weapon); + + /** + * The player attribute, which thrift is what we care about. + * @return return player attribute. + */ + PlayerAttributes getPlayerAttributes(); + + /** + * Get description of the horde on day 59 before update, so horde description appear on day 60. + * @return return the description of the horde. + */ + Horde getHorde(); + + /** + * Reset to 3 action point. + * @param actionPoints action points. + */ + void setActionPoint(int actionPoints); + + /** + * Get unprocessed events to see if player is capable of skipping. + * @return unprocessed events. + */ + ArrayList getUnprocessedEvents(); +} diff --git a/src/main/java/usecases/gamenewday/NewdayInputBoundary.java b/src/main/java/usecases/gamenewday/NewdayInputBoundary.java new file mode 100644 index 000000000..7dc39ace5 --- /dev/null +++ b/src/main/java/usecases/gamenewday/NewdayInputBoundary.java @@ -0,0 +1,13 @@ +package usecases.gamenewday; + +/** + * Input boundary of the newday, so interactor must have this execute method. + */ +public interface NewdayInputBoundary { + /** + * Execute the move for player based on given direction. + * @param inputdata execute, based on inputdata of player's input given. + * But actually, no inputdata is needed except for the fact player press the key for next day/ + */ + void execute(NewdayInputData inputdata); +} diff --git a/src/main/java/usecases/gamenewday/NewdayInputData.java b/src/main/java/usecases/gamenewday/NewdayInputData.java new file mode 100644 index 000000000..5143ad4eb --- /dev/null +++ b/src/main/java/usecases/gamenewday/NewdayInputData.java @@ -0,0 +1,8 @@ +package usecases.gamenewday; + +/** + * Input data from player ui side, which is nothing because we don't need anything to decide how everything is change + * form outside. + */ +public class NewdayInputData { +} diff --git a/src/main/java/usecases/gamenewday/NewdayInteractor.java b/src/main/java/usecases/gamenewday/NewdayInteractor.java new file mode 100644 index 000000000..97009a8b9 --- /dev/null +++ b/src/main/java/usecases/gamenewday/NewdayInteractor.java @@ -0,0 +1,137 @@ +package usecases.gamenewday; + +import entities.EntityConstants; + +/** + * Newday interactor, where logic happen. + */ +public class NewdayInteractor implements NewdayInputBoundary { + private final NewdayDataAccessInterface newdayDataAccessObject; + private final NewdayOutputBoundary newdayOutputBoundary; + + public NewdayInteractor(NewdayDataAccessInterface newdayDataAccessObject, + NewdayOutputBoundary newdayOutputBoundary) { + this.newdayDataAccessObject = newdayDataAccessObject; + this.newdayOutputBoundary = newdayOutputBoundary; + } + + @Override + public void execute(NewdayInputData inputdata) { + final int thrift = newdayDataAccessObject.getPlayerAttributes().getThrift(); + final int people = newdayDataAccessObject.getInventory().getPeople(); + final double temp = newdayDataAccessObject.getLocation().gettemperature(); + final int score = newdayDataAccessObject.getPlayerInfo().getScore(); + + // Message builder for day summary + final StringBuilder messageBuilder = new StringBuilder("Another day has passed. Here's what happened:\n"); + boolean success = true; + String failMessage = ""; + + // 1. Fail if there are unfinished events + if (!newdayDataAccessObject.getUnprocessedEvents().isEmpty()) { + success = false; + failMessage = "There are unfinished events. You must address them before starting a new day."; + } + // 2. Fail if the maximum day has been reached or exceeded + else if (newdayDataAccessObject.getPlayerInfo().getDaysSurvived() >= EntityConstants.MAXNUMDAY) { + success = false; + failMessage = "You have reached the maximum number of days. The game is over."; + } + + if (success) { + // 3. If days survived is less than 59, apply resource gain/loss logic + if (newdayDataAccessObject.getPlayerInfo().getDaysSurvived() < EntityConstants.MAXNUMDAY - 1) { + applyResourceChanges(messageBuilder, thrift, people, temp, score); + } + // 4. If it's day 59, display the horde description logic + else { + final double temperature = newdayDataAccessObject.getLocation().gettemperature(); + final double threat = newdayDataAccessObject.getLocation().getthreatlevel(); + messageBuilder.append(newdayDataAccessObject.getHorde().getDescription(threat, temperature)); + } + + // Update state and prepare success output + final NewdayOutputData outputData = new NewdayOutputData(messageBuilder.toString(), true, ""); + newdayOutputBoundary.prepareSuccessView(outputData); + + // Update player state for the new day + newdayDataAccessObject.setActionPoint(EntityConstants.STARTERACTIONPOINT); + newdayDataAccessObject.setDaysSurvived(newdayDataAccessObject.getPlayerInfo().getDaysSurvived() + 1); + } + else { + // Prepare failure output + newdayOutputBoundary.prepareFailureView(failMessage); + } + } + + private void applyResourceChanges(StringBuilder messageBuilder, int thrift, int people, double temp, int score) { + incrementResources(messageBuilder, people, score); + decrementResources(messageBuilder, thrift, people, temp); + } + + private void incrementResources(StringBuilder messageBuilder, int people, int score) { + // Food gain + final double foodScalar = newdayDataAccessObject.getLocation().getfoodresourceavailable(); + final double foodGain = people * EntityConstants.PEOPLEGAINPERFOOD * foodScalar; + newdayDataAccessObject.changeFood((int) foodGain); + messageBuilder.append(" - Food gained: ").append((int) foodGain).append(EntityConstants.NEWLINE); + + // Water gain + final double waterScalar = newdayDataAccessObject.getLocation().getwaterresourceavailable(); + final double waterGain = people * EntityConstants.PEOPLEGAINPERWATER * waterScalar; + newdayDataAccessObject.changeWater((int) waterGain); + messageBuilder.append(" - Water gained: ").append((int) waterGain).append(EntityConstants.NEWLINE); + + int newScore = score + (int) foodGain + (int) waterGain; + + // People gain + final double peopleGain = people * (EntityConstants.PEOPLEBASEJOINRATE + * newdayDataAccessObject.getLocation().getpeopleresourceavailable()); + newdayDataAccessObject.changePeople((int) peopleGain); + messageBuilder.append(" - New members joined: ").append((int) peopleGain).append(EntityConstants.NEWLINE); + newScore += (int) peopleGain; + + // Weaponry gain + double weaponGain = peopleGain + people * EntityConstants.PEOPLEGAINPERWEAPON; + weaponGain = weaponGain * newdayDataAccessObject.getLocation().getweaponresourceavailable(); + newdayDataAccessObject.changeWeapon((int) weaponGain); + messageBuilder.append(" - Weaponry gained: ").append((int) weaponGain).append(EntityConstants.NEWLINE); + + newScore += (int) weaponGain + EntityConstants.NEWDAYSCORE; + + newdayDataAccessObject.setScore(newScore); + } + + private void decrementResources(StringBuilder messageBuilder, int thrift, int people, double temp) { + // Food loss + final double baseTemp = EntityConstants.DEFAULTTEMP; + final double tempDiff = temp - baseTemp; + double foodLoss = people * EntityConstants.PEOPLELOSSPERFOOD; + if (tempDiff < 0) { + foodLoss += Math.abs(tempDiff); + } + foodLoss = foodLoss * (1 - thrift * EntityConstants.THRIFTIMPACTRESOURCELOSS); + newdayDataAccessObject.changeFood((int) foodLoss * -1); + messageBuilder.append(" - Food lost: ").append((int) foodLoss).append(EntityConstants.NEWLINE); + + // Water loss + double waterLoss = people * EntityConstants.PEOPLELOSSPERWATER; + if (tempDiff > 0) { + waterLoss += Math.abs(tempDiff); + } + waterLoss = waterLoss * (1 - thrift * EntityConstants.THRIFTIMPACTRESOURCELOSS); + newdayDataAccessObject.changeWater((int) waterLoss * -1); + messageBuilder.append(" - Water lost: ").append((int) waterLoss).append(EntityConstants.NEWLINE); + + // People loss + final double peopleLoss = people * (EntityConstants.PEOPLEBASEDEATHRATE + * newdayDataAccessObject.getLocation().getthreatlevel()); + newdayDataAccessObject.changePeople((int) peopleLoss * -1); + messageBuilder.append(" - People lost: ").append((int) peopleLoss).append(EntityConstants.NEWLINE); + + // Weaponry loss + final double weaponLoss = peopleLoss * (1 - thrift * EntityConstants.THRIFTIMPACTRESOURCELOSS); + newdayDataAccessObject.changeWeapon((int) weaponLoss * -1); + messageBuilder.append(" - Weaponry lost: ").append((int) weaponLoss).append(EntityConstants.NEWLINE); + } +} diff --git a/src/main/java/usecases/gamenewday/NewdayOutputBoundary.java b/src/main/java/usecases/gamenewday/NewdayOutputBoundary.java new file mode 100644 index 000000000..cadba6996 --- /dev/null +++ b/src/main/java/usecases/gamenewday/NewdayOutputBoundary.java @@ -0,0 +1,18 @@ +package usecases.gamenewday; + +/** + * Output boundary for newday, either prepare a success use case view with message returned as output data, or failed. + */ +public interface NewdayOutputBoundary { + /** + * Outputs for a successful move. + * @param outputData the output for updating the view. + */ + void prepareSuccessView(NewdayOutputData outputData); + + /** + * If the usecase is invaild, example: 60 days this get called so intend to move to 61. + * @param errorMessage message of why is invaild, for the player. + */ + void prepareFailureView(String errorMessage); +} diff --git a/src/main/java/usecases/gamenewday/NewdayOutputData.java b/src/main/java/usecases/gamenewday/NewdayOutputData.java new file mode 100644 index 000000000..9735a798a --- /dev/null +++ b/src/main/java/usecases/gamenewday/NewdayOutputData.java @@ -0,0 +1,30 @@ +package usecases.gamenewday; + +/** + * Output data of newday after is done, should return a message saying what happened, how many people gained, lose, etc. + * Or, was the usecase a success, would will for example if already 60 days and still called this use case to day 61. + */ +public class NewdayOutputData { + private String message; + private boolean success; + private String failmessage; + + public NewdayOutputData(String message, boolean success, String failmessage) { + this.message = message; + this.success = success; + this.failmessage = failmessage; + } + + public String getMessage() { + return message; + } + + public boolean isSuccess() { + return success; + } + + public String getFailmessage() { + return failmessage; + } +} + diff --git a/src/main/java/usecases/gameplacedescription/PlaceDescriptionDataAccessInterface.java b/src/main/java/usecases/gameplacedescription/PlaceDescriptionDataAccessInterface.java new file mode 100644 index 000000000..5c28a240e --- /dev/null +++ b/src/main/java/usecases/gameplacedescription/PlaceDescriptionDataAccessInterface.java @@ -0,0 +1,15 @@ +package usecases.gameplacedescription; + +import entities.Location; + +/** + * Require location info like temperature, threat level etc for more specific and smart description. + */ +public interface PlaceDescriptionDataAccessInterface { + + /** + * The location of the player's current position. + * @return location. + */ + Location getLocation(); +} diff --git a/src/main/java/usecases/gameplacedescription/PlaceDescriptionInputBoundary.java b/src/main/java/usecases/gameplacedescription/PlaceDescriptionInputBoundary.java new file mode 100644 index 000000000..dadbeb094 --- /dev/null +++ b/src/main/java/usecases/gameplacedescription/PlaceDescriptionInputBoundary.java @@ -0,0 +1,12 @@ +package usecases.gameplacedescription; + +/** + * Input boundary of place description, which a interactor should have execute method, providing input data. + */ +public interface PlaceDescriptionInputBoundary { + /** + * Execute by retuning the description of the location. + * @param inputdata not really needed as this is automatic move. + */ + void execute(PlaceDescriptionInputData inputdata); +} diff --git a/src/main/java/usecases/gameplacedescription/PlaceDescriptionInputData.java b/src/main/java/usecases/gameplacedescription/PlaceDescriptionInputData.java new file mode 100644 index 000000000..8dc4f1c13 --- /dev/null +++ b/src/main/java/usecases/gameplacedescription/PlaceDescriptionInputData.java @@ -0,0 +1,4 @@ +package usecases.gameplacedescription; + +public class PlaceDescriptionInputData { +} diff --git a/src/main/java/usecases/gameplacedescription/PlaceDescriptionInteractor.java b/src/main/java/usecases/gameplacedescription/PlaceDescriptionInteractor.java new file mode 100644 index 000000000..a085c9d2e --- /dev/null +++ b/src/main/java/usecases/gameplacedescription/PlaceDescriptionInteractor.java @@ -0,0 +1,27 @@ +package usecases.gameplacedescription; + +import entities.Location; + +/** + * Place Description interactor, based on location information, generate the description for the player, + * which is for the view. + */ +public class PlaceDescriptionInteractor implements PlaceDescriptionInputBoundary { + private PlaceDescriptionDataAccessInterface dataAccess; + private PlaceDescriptionOutputBoundary outputBoundary; + + public PlaceDescriptionInteractor(PlaceDescriptionDataAccessInterface dataaccess, + PlaceDescriptionOutputBoundary outputboundary) { + this.dataAccess = dataaccess; + this.outputBoundary = outputboundary; + } + + @Override + public void execute(PlaceDescriptionInputData Inputdata) { + final Location location = dataAccess.getLocation(); + final String description = location.getDescription(); + final PlaceDescriptionOutputData outputdata = new PlaceDescriptionOutputData(description); + outputBoundary.preparesuccessview(outputdata); + + } +} diff --git a/src/main/java/usecases/gameplacedescription/PlaceDescriptionOutputBoundary.java b/src/main/java/usecases/gameplacedescription/PlaceDescriptionOutputBoundary.java new file mode 100644 index 000000000..994a44d1c --- /dev/null +++ b/src/main/java/usecases/gameplacedescription/PlaceDescriptionOutputBoundary.java @@ -0,0 +1,21 @@ +package usecases.gameplacedescription; + +/** + * Output boundary of place description. success view will display the place description for the player, giving them + * basic information of the place, for example how dangerous it is? cold or warm? etc + */ +public interface PlaceDescriptionOutputBoundary { + + /** + * Prepare the view if the usecase is a success, which display the description generated by interactor. + * @param data contain description required. + */ + void preparesuccessview(PlaceDescriptionOutputData data); + + /** + * Prepare fialure view, This shouldn't happen as long as player is inside the map grid, but player is always + * inside the grid if move usecase was correct. + * @param failmessage failmessage ? + */ + void preparefailureview(String failmessage); +} diff --git a/src/main/java/usecases/gameplacedescription/PlaceDescriptionOutputData.java b/src/main/java/usecases/gameplacedescription/PlaceDescriptionOutputData.java new file mode 100644 index 000000000..bcb6e1ddb --- /dev/null +++ b/src/main/java/usecases/gameplacedescription/PlaceDescriptionOutputData.java @@ -0,0 +1,16 @@ +package usecases.gameplacedescription; + +/** + * Output data for this usecase, which is just description. + */ +public class PlaceDescriptionOutputData { + private String description; + + public PlaceDescriptionOutputData(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } +} diff --git a/src/main/java/usecases/navigateMain/NavigateMainDataAccessInterface.java b/src/main/java/usecases/navigateMain/NavigateMainDataAccessInterface.java new file mode 100644 index 000000000..aa027eecf --- /dev/null +++ b/src/main/java/usecases/navigateMain/NavigateMainDataAccessInterface.java @@ -0,0 +1,7 @@ +package usecases.navigateMain; + +/** + * Data access, need decided events. + */ +public interface NavigateMainDataAccessInterface { +} diff --git a/src/main/java/usecases/navigateMain/NavigateMainInputBoundary.java b/src/main/java/usecases/navigateMain/NavigateMainInputBoundary.java new file mode 100644 index 000000000..ca3cd09f4 --- /dev/null +++ b/src/main/java/usecases/navigateMain/NavigateMainInputBoundary.java @@ -0,0 +1,8 @@ +package usecases.navigateMain; + +/** + * Execute method. + */ +public interface NavigateMainInputBoundary { + public void execute(NavigateMainInputData inputdata); +} diff --git a/src/main/java/usecases/navigateMain/NavigateMainInputData.java b/src/main/java/usecases/navigateMain/NavigateMainInputData.java new file mode 100644 index 000000000..5f2675bcf --- /dev/null +++ b/src/main/java/usecases/navigateMain/NavigateMainInputData.java @@ -0,0 +1,9 @@ +package usecases.navigateMain; + +/** + * Not needed, no restriction to go back. + */ +// public class NavigateMainInputdata { +// } +public class NavigateMainInputData { +} \ No newline at end of file diff --git a/src/main/java/usecases/navigateMain/NavigateMainInteractor.java b/src/main/java/usecases/navigateMain/NavigateMainInteractor.java new file mode 100644 index 000000000..d2f13c5d0 --- /dev/null +++ b/src/main/java/usecases/navigateMain/NavigateMainInteractor.java @@ -0,0 +1,20 @@ +package usecases.navigateMain; + +/** + * Nevagate interactor. + */ +public class NavigateMainInteractor implements NavigateMainInputBoundary { + private final NavigateMainDataAccessInterface dataAccess; + private final NevagateMainOutputBoundary outputBoundary; + + public NavigateMainInteractor(NavigateMainDataAccessInterface dataaccess, + NevagateMainOutputBoundary outputboundary) { + this.dataAccess = dataaccess; + this.outputBoundary = outputboundary; + } + + @Override + public void execute(NavigateMainInputData inputdata) { + outputBoundary.prepareMainView(); + } +} diff --git a/src/main/java/usecases/navigateMain/NavigateMainOutputdata.java b/src/main/java/usecases/navigateMain/NavigateMainOutputdata.java new file mode 100644 index 000000000..e2959f53c --- /dev/null +++ b/src/main/java/usecases/navigateMain/NavigateMainOutputdata.java @@ -0,0 +1,7 @@ +package usecases.navigateMain; + +/** + * No output data is needed to go back. + */ +public class NavigateMainOutputdata { +} diff --git a/src/main/java/usecases/navigateMain/NevagateMainOutputBoundary.java b/src/main/java/usecases/navigateMain/NevagateMainOutputBoundary.java new file mode 100644 index 000000000..765455b55 --- /dev/null +++ b/src/main/java/usecases/navigateMain/NevagateMainOutputBoundary.java @@ -0,0 +1,9 @@ +package usecases.navigateMain; + +/** + * OutputBOundary, should be able to have method go back to main page. + */ +public interface NevagateMainOutputBoundary { + + void prepareMainView(); +} diff --git a/src/main/java/usecases/nevagateAllowcatePage/NevagateAllowcateDataAccessInterface.java b/src/main/java/usecases/nevagateAllowcatePage/NevagateAllowcateDataAccessInterface.java new file mode 100644 index 000000000..a3355e566 --- /dev/null +++ b/src/main/java/usecases/nevagateAllowcatePage/NevagateAllowcateDataAccessInterface.java @@ -0,0 +1,7 @@ +package usecases.nevagateAllowcatePage; + +/** + * Go to allowcate page use case data access, not data required. + */ +public interface NevagateAllowcateDataAccessInterface { +} diff --git a/src/main/java/usecases/nevagateAllowcatePage/NevagateAllowcateInputBoundary.java b/src/main/java/usecases/nevagateAllowcatePage/NevagateAllowcateInputBoundary.java new file mode 100644 index 000000000..8dd93cf26 --- /dev/null +++ b/src/main/java/usecases/nevagateAllowcatePage/NevagateAllowcateInputBoundary.java @@ -0,0 +1,14 @@ +package usecases.nevagateAllowcatePage; + +/** + * Input boundary for nevagate to allowcare page usecase. + */ +public interface NevagateAllowcateInputBoundary { + + /** + * Execute, which checks can use go to next page or not, is yes call next page in presentor, is not only display + * error message. + * @param inputdata inputdatatype, not needed. + */ + void execute(NevagateAllowcateInputdata inputdata); +} diff --git a/src/main/java/usecases/nevagateAllowcatePage/NevagateAllowcateInputdata.java b/src/main/java/usecases/nevagateAllowcatePage/NevagateAllowcateInputdata.java new file mode 100644 index 000000000..b699a22c7 --- /dev/null +++ b/src/main/java/usecases/nevagateAllowcatePage/NevagateAllowcateInputdata.java @@ -0,0 +1,7 @@ +package usecases.nevagateAllowcatePage; + +/** + * Not needed. + */ +public class NevagateAllowcateInputdata { +} diff --git a/src/main/java/usecases/nevagateAllowcatePage/NevagateAllowcateInteractor.java b/src/main/java/usecases/nevagateAllowcatePage/NevagateAllowcateInteractor.java new file mode 100644 index 000000000..b8f3a6890 --- /dev/null +++ b/src/main/java/usecases/nevagateAllowcatePage/NevagateAllowcateInteractor.java @@ -0,0 +1,22 @@ +package usecases.nevagateAllowcatePage; + +/** + * Interactor for nevagate, cehck if player is able to go to next page. + */ +public class NevagateAllowcateInteractor implements NevagateAllowcateInputBoundary { + private final NevagateAllowcateDataAccessInterface dataAccess; + private final NevagateAllowcateOutputBoundary outputBoundary; + + public NevagateAllowcateInteractor(NevagateAllowcateDataAccessInterface dataAccess, + NevagateAllowcateOutputBoundary outputBoundary) { + this.dataAccess = dataAccess; + this.outputBoundary = outputBoundary; + } + + @Override + public void execute(NevagateAllowcateInputdata inputdata) { + // player should be able to go as long as they clicked the new game, so nothing is stopping them. + outputBoundary.nevagateAllowcatePage(); + // go to allowcate page. + } +} diff --git a/src/main/java/usecases/nevagateAllowcatePage/NevagateAllowcateOutputBoundary.java b/src/main/java/usecases/nevagateAllowcatePage/NevagateAllowcateOutputBoundary.java new file mode 100644 index 000000000..b27ccfad5 --- /dev/null +++ b/src/main/java/usecases/nevagateAllowcatePage/NevagateAllowcateOutputBoundary.java @@ -0,0 +1,18 @@ +package usecases.nevagateAllowcatePage; + +/** + * Output boundary, should be able to go to allowcate point page or, it not able restrict player. + */ +public interface NevagateAllowcateOutputBoundary { + + /** + * If player is able to go. + */ + void nevagateAllowcatePage(); + + /** + * If player is restricted. + * @param errormessage error message. + */ + void nevagateAllowcateFail(String errormessage); +} diff --git a/src/main/java/usecases/nevagateAllowcatePage/NevagateAllowcateOutputdata.java b/src/main/java/usecases/nevagateAllowcatePage/NevagateAllowcateOutputdata.java new file mode 100644 index 000000000..1014d1cab --- /dev/null +++ b/src/main/java/usecases/nevagateAllowcatePage/NevagateAllowcateOutputdata.java @@ -0,0 +1,7 @@ +package usecases.nevagateAllowcatePage; + +/** + * Outputdata for presentation, not needed. + */ +public class NevagateAllowcateOutputdata { +} diff --git a/src/main/java/usecases/nevagateEventPage/NevagateEventDataAccessInterface.java b/src/main/java/usecases/nevagateEventPage/NevagateEventDataAccessInterface.java new file mode 100644 index 000000000..40cdc197d --- /dev/null +++ b/src/main/java/usecases/nevagateEventPage/NevagateEventDataAccessInterface.java @@ -0,0 +1,16 @@ +package usecases.nevagateEventPage; + +import entities.Event; + +import java.util.ArrayList; + +/** + * Not needed. + */ +public interface NevagateEventDataAccessInterface { + /** + * Get all events decided for that day. + * @return events. + */ + ArrayList getDecidedEvents(); +} diff --git a/src/main/java/usecases/nevagateEventPage/NevagateEventInputBoundary.java b/src/main/java/usecases/nevagateEventPage/NevagateEventInputBoundary.java new file mode 100644 index 000000000..eb8dc9164 --- /dev/null +++ b/src/main/java/usecases/nevagateEventPage/NevagateEventInputBoundary.java @@ -0,0 +1,8 @@ +package usecases.nevagateEventPage; + +/** + * Execute method. + */ +public interface NevagateEventInputBoundary { + public void execute(NevagateEventInputdata inputData); +} diff --git a/src/main/java/usecases/nevagateEventPage/NevagateEventInputdata.java b/src/main/java/usecases/nevagateEventPage/NevagateEventInputdata.java new file mode 100644 index 000000000..fbbf65ccb --- /dev/null +++ b/src/main/java/usecases/nevagateEventPage/NevagateEventInputdata.java @@ -0,0 +1,7 @@ +package usecases.nevagateEventPage; + +/** + * not needed. + */ +public class NevagateEventInputdata { +} diff --git a/src/main/java/usecases/nevagateEventPage/NevagateEventInteractor.java b/src/main/java/usecases/nevagateEventPage/NevagateEventInteractor.java new file mode 100644 index 000000000..947b44113 --- /dev/null +++ b/src/main/java/usecases/nevagateEventPage/NevagateEventInteractor.java @@ -0,0 +1,31 @@ +package usecases.nevagateEventPage; + +import entities.Event; +import java.util.ArrayList; + +/** + * Interactor, determine if player is able to press and go to event. + * Only able to go when there is event. eventdecided is not empty. + */ +public class NevagateEventInteractor implements NevagateEventInputBoundary { + private NevagateEventDataAccessInterface dataaccess; + private NevagateEventOutputBoundary EventOutputBoundary; + + public NevagateEventInteractor(NevagateEventDataAccessInterface dataaccess, + NevagateEventOutputBoundary EventOutputBoundary) { + this.dataaccess = dataaccess; + this.EventOutputBoundary = EventOutputBoundary; + } + + @Override + public void execute(NevagateEventInputdata inputdata) { + final ArrayList events = dataaccess.getDecidedEvents(); + if (events.size() > 0) { + final NevagateEventOutputdata nevagateEventOutputdata = new NevagateEventOutputdata(); + EventOutputBoundary.nevagateEventPage(nevagateEventOutputdata); + } + else { + EventOutputBoundary.nevagateEventFailed("Peaceful day, no event happened."); + } + } +} diff --git a/src/main/java/usecases/nevagateEventPage/NevagateEventOutputBoundary.java b/src/main/java/usecases/nevagateEventPage/NevagateEventOutputBoundary.java new file mode 100644 index 000000000..f1cf5cc9a --- /dev/null +++ b/src/main/java/usecases/nevagateEventPage/NevagateEventOutputBoundary.java @@ -0,0 +1,10 @@ +package usecases.nevagateEventPage; + +/** + * Navigate or navigate failed. + */ +public interface NevagateEventOutputBoundary { + void nevagateEventPage(NevagateEventOutputdata outputdata); + + void nevagateEventFailed(String failmessage); +} diff --git a/src/main/java/usecases/nevagateEventPage/NevagateEventOutputdata.java b/src/main/java/usecases/nevagateEventPage/NevagateEventOutputdata.java new file mode 100644 index 000000000..5bc9e58f9 --- /dev/null +++ b/src/main/java/usecases/nevagateEventPage/NevagateEventOutputdata.java @@ -0,0 +1,7 @@ +package usecases.nevagateEventPage; + +/** + * Outputdata. + */ +public class NevagateEventOutputdata { +} diff --git a/src/main/java/usecases/nevagateGame/NevagateGameDataAccessInterface.java b/src/main/java/usecases/nevagateGame/NevagateGameDataAccessInterface.java new file mode 100644 index 000000000..33edfdfaa --- /dev/null +++ b/src/main/java/usecases/nevagateGame/NevagateGameDataAccessInterface.java @@ -0,0 +1,7 @@ +package usecases.nevagateGame; + +/** + * Not needed, we don't need info from database. + */ +public interface NevagateGameDataAccessInterface { +} diff --git a/src/main/java/usecases/nevagateGame/NevagateGameInputBoundary.java b/src/main/java/usecases/nevagateGame/NevagateGameInputBoundary.java new file mode 100644 index 000000000..31e52c8b9 --- /dev/null +++ b/src/main/java/usecases/nevagateGame/NevagateGameInputBoundary.java @@ -0,0 +1,8 @@ +package usecases.nevagateGame; + +/** + * Execute method is gurenteed. + */ +public interface NevagateGameInputBoundary { + void execute(NevagateGameInputdata InputData); +} diff --git a/src/main/java/usecases/nevagateGame/NevagateGameInputdata.java b/src/main/java/usecases/nevagateGame/NevagateGameInputdata.java new file mode 100644 index 000000000..d15dccf80 --- /dev/null +++ b/src/main/java/usecases/nevagateGame/NevagateGameInputdata.java @@ -0,0 +1,7 @@ +package usecases.nevagateGame; + +/** + * Input from player side. + */ +public class NevagateGameInputdata { +} diff --git a/src/main/java/usecases/nevagateGame/NevagateGameInteractor.java b/src/main/java/usecases/nevagateGame/NevagateGameInteractor.java new file mode 100644 index 000000000..b1948e52a --- /dev/null +++ b/src/main/java/usecases/nevagateGame/NevagateGameInteractor.java @@ -0,0 +1,18 @@ +package usecases.nevagateGame; + +public class NevagateGameInteractor implements NevagateGameInputBoundary{ + private NevagateGameDataAccessInterface dataaccess; + private NevagateGameOutputBoundary outputboundary; + + public NevagateGameInteractor(NevagateGameDataAccessInterface dataaccess, + NevagateGameOutputBoundary outputboundary) { + this.dataaccess = dataaccess; + this.outputboundary = outputboundary; + } + + @Override + public void execute(NevagateGameInputdata InputData) { + final NevagateGameOutputdata outputdata = new NevagateGameOutputdata(); + outputboundary.prepareGamePage(outputdata); + } +} diff --git a/src/main/java/usecases/nevagateGame/NevagateGameOutputBoundary.java b/src/main/java/usecases/nevagateGame/NevagateGameOutputBoundary.java new file mode 100644 index 000000000..2efdbb611 --- /dev/null +++ b/src/main/java/usecases/nevagateGame/NevagateGameOutputBoundary.java @@ -0,0 +1,8 @@ +package usecases.nevagateGame; + +/** + * Contain method to jumo to game main page. + */ +public interface NevagateGameOutputBoundary { + void prepareGamePage(NevagateGameOutputdata outputdata); +} diff --git a/src/main/java/usecases/nevagateGame/NevagateGameOutputdata.java b/src/main/java/usecases/nevagateGame/NevagateGameOutputdata.java new file mode 100644 index 000000000..ef939d669 --- /dev/null +++ b/src/main/java/usecases/nevagateGame/NevagateGameOutputdata.java @@ -0,0 +1,7 @@ +package usecases.nevagateGame; + +/** + * Not needed. + */ +public class NevagateGameOutputdata { +} diff --git a/src/main/java/usecases/nevagateGameover/NevagateGameOverDataAccessInterface.java b/src/main/java/usecases/nevagateGameover/NevagateGameOverDataAccessInterface.java new file mode 100644 index 000000000..78ee03824 --- /dev/null +++ b/src/main/java/usecases/nevagateGameover/NevagateGameOverDataAccessInterface.java @@ -0,0 +1,7 @@ +package usecases.nevagateGameover; + +/** + * Not needed. + */ +public interface NevagateGameOverDataAccessInterface { +} diff --git a/src/main/java/usecases/nevagateGameover/NevagateGameOverInputBoundary.java b/src/main/java/usecases/nevagateGameover/NevagateGameOverInputBoundary.java new file mode 100644 index 000000000..6b5e82df9 --- /dev/null +++ b/src/main/java/usecases/nevagateGameover/NevagateGameOverInputBoundary.java @@ -0,0 +1,8 @@ +package usecases.nevagateGameover; + +/** + * Execute. + */ +public interface NevagateGameOverInputBoundary { + void execute(NevagateGameOverInputdata inputdata); +} diff --git a/src/main/java/usecases/nevagateGameover/NevagateGameOverInputdata.java b/src/main/java/usecases/nevagateGameover/NevagateGameOverInputdata.java new file mode 100644 index 000000000..5e11fff36 --- /dev/null +++ b/src/main/java/usecases/nevagateGameover/NevagateGameOverInputdata.java @@ -0,0 +1,7 @@ +package usecases.nevagateGameover; + +/** + * Not needed. + */ +public class NevagateGameOverInputdata { +} diff --git a/src/main/java/usecases/nevagateGameover/NevagateGameOverInteractor.java b/src/main/java/usecases/nevagateGameover/NevagateGameOverInteractor.java new file mode 100644 index 000000000..1cf0d6749 --- /dev/null +++ b/src/main/java/usecases/nevagateGameover/NevagateGameOverInteractor.java @@ -0,0 +1,21 @@ +package usecases.nevagateGameover; + +/** + * Interactor, only for navigating to the desired page. + */ +public class NevagateGameOverInteractor implements NevagateGameOverInputBoundary { + private NevagateGameOverDataAccessInterface dataaccess; + private NevagateGameOverOutputBoundary outputBoundary; + + public NevagateGameOverInteractor(NevagateGameOverDataAccessInterface dataaccess, + NevagateGameOverOutputBoundary outputBoundary) { + this.dataaccess = dataaccess; + this.outputBoundary = outputBoundary; + } + + @Override + public void execute(NevagateGameOverInputdata inputdata) { + final NevagateGameOverOutputdata outputdata = new NevagateGameOverOutputdata(); + outputBoundary.prepareGameOver(outputdata); + } +} diff --git a/src/main/java/usecases/nevagateGameover/NevagateGameOverOutputBoundary.java b/src/main/java/usecases/nevagateGameover/NevagateGameOverOutputBoundary.java new file mode 100644 index 000000000..d2f4c694b --- /dev/null +++ b/src/main/java/usecases/nevagateGameover/NevagateGameOverOutputBoundary.java @@ -0,0 +1,5 @@ +package usecases.nevagateGameover; + +public interface NevagateGameOverOutputBoundary { + void prepareGameOver(NevagateGameOverOutputdata outputdata); +} diff --git a/src/main/java/usecases/nevagateGameover/NevagateGameOverOutputdata.java b/src/main/java/usecases/nevagateGameover/NevagateGameOverOutputdata.java new file mode 100644 index 000000000..d1138ac7c --- /dev/null +++ b/src/main/java/usecases/nevagateGameover/NevagateGameOverOutputdata.java @@ -0,0 +1,7 @@ +package usecases.nevagateGameover; + +/** + * Not needed. + */ +public class NevagateGameOverOutputdata { +} diff --git a/src/main/java/usecases/nevagateLogin/NevagateLoginDataAccessInterface.java b/src/main/java/usecases/nevagateLogin/NevagateLoginDataAccessInterface.java new file mode 100644 index 000000000..bfcd01140 --- /dev/null +++ b/src/main/java/usecases/nevagateLogin/NevagateLoginDataAccessInterface.java @@ -0,0 +1,8 @@ +package usecases.nevagateLogin; + +/** + * Data Access Interface for navigating to the Login page. + * Define any data-related dependencies required for navigation. + */ +public interface NevagateLoginDataAccessInterface { +} diff --git a/src/main/java/usecases/nevagateLogin/NevagateLoginInputBoundary.java b/src/main/java/usecases/nevagateLogin/NevagateLoginInputBoundary.java new file mode 100644 index 000000000..ebc8ba7a3 --- /dev/null +++ b/src/main/java/usecases/nevagateLogin/NevagateLoginInputBoundary.java @@ -0,0 +1,14 @@ +package usecases.nevagateLogin; + +/** + * Input Boundary for navigating to the Login page. + * Acts as the entry point for the use case. + */ +public interface NevagateLoginInputBoundary { + /** + * Executes the navigation to the Login page with the provided input data. + * + * @param inputData The input data required for navigation. + */ + void execute(NevagateLoginInputData inputData); +} diff --git a/src/main/java/usecases/nevagateLogin/NevagateLoginInputData.java b/src/main/java/usecases/nevagateLogin/NevagateLoginInputData.java new file mode 100644 index 000000000..b70386a0d --- /dev/null +++ b/src/main/java/usecases/nevagateLogin/NevagateLoginInputData.java @@ -0,0 +1,7 @@ +package usecases.nevagateLogin; + +/** + * Input Data for the NevagateLogin use case. + */ +public class NevagateLoginInputData { +} diff --git a/src/main/java/usecases/nevagateLogin/NevagateLoginInteractor.java b/src/main/java/usecases/nevagateLogin/NevagateLoginInteractor.java new file mode 100644 index 000000000..c9288461d --- /dev/null +++ b/src/main/java/usecases/nevagateLogin/NevagateLoginInteractor.java @@ -0,0 +1,19 @@ +package usecases.nevagateLogin; + +/** + * Interactor for navigating to the Login page. + * Contains the core business logic for navigation. + */ +public class NevagateLoginInteractor implements NevagateLoginInputBoundary { + private final NevagateLoginOutputBoundary outputBoundary; + + public NevagateLoginInteractor(NevagateLoginOutputBoundary outputBoundary) { + this.outputBoundary = outputBoundary; + } + + @Override + public void execute(NevagateLoginInputData inputData) { + // Perform any necessary logic here (e.g., logging, validation). + outputBoundary.prepareSuccessView(new NevagateLoginOutputData("Navigating to Login Page...")); + } +} diff --git a/src/main/java/usecases/nevagateLogin/NevagateLoginOutputBoundary.java b/src/main/java/usecases/nevagateLogin/NevagateLoginOutputBoundary.java new file mode 100644 index 000000000..f468cdda3 --- /dev/null +++ b/src/main/java/usecases/nevagateLogin/NevagateLoginOutputBoundary.java @@ -0,0 +1,14 @@ +package usecases.nevagateLogin; + +/** + * Output Boundary for navigating to the Login page. + * Handles presentation logic for the use case. + */ +public interface NevagateLoginOutputBoundary { + /** + * Prepares the view for successful navigation. + * + * @param outputData The output data for navigation. + */ + void prepareSuccessView(NevagateLoginOutputData outputData); +} diff --git a/src/main/java/usecases/nevagateLogin/NevagateLoginOutputData.java b/src/main/java/usecases/nevagateLogin/NevagateLoginOutputData.java new file mode 100644 index 000000000..81ccce647 --- /dev/null +++ b/src/main/java/usecases/nevagateLogin/NevagateLoginOutputData.java @@ -0,0 +1,16 @@ +package usecases.nevagateLogin; + +/** + * Output Data for the NevagateLogin use case. + */ +public class NevagateLoginOutputData { + private final String message; + + public NevagateLoginOutputData(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } +} diff --git a/src/main/java/usecases/nevagateRanking/NevagateRankingDataAccessInterface.java b/src/main/java/usecases/nevagateRanking/NevagateRankingDataAccessInterface.java new file mode 100644 index 000000000..fb525c37a --- /dev/null +++ b/src/main/java/usecases/nevagateRanking/NevagateRankingDataAccessInterface.java @@ -0,0 +1,7 @@ +package usecases.nevagateRanking; + +/** + * Interface for data access logic related to navigating to the ranking page. + */ +public interface NevagateRankingDataAccessInterface { +} diff --git a/src/main/java/usecases/nevagateRanking/NevagateRankingInputBoundary.java b/src/main/java/usecases/nevagateRanking/NevagateRankingInputBoundary.java new file mode 100644 index 000000000..ee4cdc253 --- /dev/null +++ b/src/main/java/usecases/nevagateRanking/NevagateRankingInputBoundary.java @@ -0,0 +1,14 @@ +package usecases.nevagateRanking; + +/** + * The input boundary interface for the NavigateRanking use case. + * Acts as an entry point for triggering the navigation logic to the ranking page. + */ +public interface NevagateRankingInputBoundary { + /** + * Executes the navigation to the ranking page. + * + * @param inputData The data required for navigation, such as context information. + */ + void execute(NevagateRankingInputData inputData); +} diff --git a/src/main/java/usecases/nevagateRanking/NevagateRankingInputData.java b/src/main/java/usecases/nevagateRanking/NevagateRankingInputData.java new file mode 100644 index 000000000..f3fc12da7 --- /dev/null +++ b/src/main/java/usecases/nevagateRanking/NevagateRankingInputData.java @@ -0,0 +1,26 @@ +package usecases.nevagateRanking; + +/** + * Input data class for the NavigateRanking use case. + */ +public class NevagateRankingInputData { + private final String context; + + /** + * Constructs a NevagateRankingInputData instance. + * + * @param context A string representing the navigation context (e.g., "Navigate to Ranking"). + */ + public NevagateRankingInputData(String context) { + this.context = context; + } + + /** + * Gets the navigation context. + * + * @return A string representing the context. + */ + public String getContext() { + return context; + } +} diff --git a/src/main/java/usecases/nevagateRanking/NevagateRankingInteractor.java b/src/main/java/usecases/nevagateRanking/NevagateRankingInteractor.java new file mode 100644 index 000000000..38d6bf06a --- /dev/null +++ b/src/main/java/usecases/nevagateRanking/NevagateRankingInteractor.java @@ -0,0 +1,30 @@ +package usecases.nevagateRanking; + +/** + * The interactor for the NavigateRanking use case. + * Implements the business logic for navigating to the ranking page. + */ +public class NevagateRankingInteractor implements NevagateRankingInputBoundary { + private final NevagateRankingOutputBoundary outputBoundary; + + /** + * Constructs a NevagateRankingInteractor instance. + * + * @param outputBoundary The output boundary for presenting the navigation results. + */ + public NevagateRankingInteractor(NevagateRankingOutputBoundary outputBoundary) { + this.outputBoundary = outputBoundary; + } + + /** + * Executes the navigation to the ranking page by invoking the output boundary. + * + * @param inputData The input data containing navigation context information. + */ + @Override + public void execute(NevagateRankingInputData inputData) { + // Prepare output data + final NevagateRankingOutputData outputData = new NevagateRankingOutputData("Navigating to Ranking"); + outputBoundary.present(outputData); + } +} diff --git a/src/main/java/usecases/nevagateRanking/NevagateRankingOutputBoundary.java b/src/main/java/usecases/nevagateRanking/NevagateRankingOutputBoundary.java new file mode 100644 index 000000000..9fc8da7b4 --- /dev/null +++ b/src/main/java/usecases/nevagateRanking/NevagateRankingOutputBoundary.java @@ -0,0 +1,14 @@ +package usecases.nevagateRanking; + +/** + * The output boundary interface for the NavigateRanking use case. + * Defines the contract for presenting the results of the navigation process. + */ +public interface NevagateRankingOutputBoundary { + /** + * Presents the output data for the navigation logic. + * + * @param outputData The output data containing navigation results. + */ + void present(NevagateRankingOutputData outputData); +} diff --git a/src/main/java/usecases/nevagateRanking/NevagateRankingOutputData.java b/src/main/java/usecases/nevagateRanking/NevagateRankingOutputData.java new file mode 100644 index 000000000..b121628bb --- /dev/null +++ b/src/main/java/usecases/nevagateRanking/NevagateRankingOutputData.java @@ -0,0 +1,27 @@ +package usecases.nevagateRanking; + +/** + * Output data class for the NavigateRanking use case. + * Encapsulates the results of the navigation process. + */ +public class NevagateRankingOutputData { + private final String message; + + /** + * Constructs a NevagateRankingOutputData instance. + * + * @param message A message indicating the navigation result. + */ + public NevagateRankingOutputData(String message) { + this.message = message; + } + + /** + * Gets the navigation result message. + * + * @return A string containing the result message. + */ + public String getMessage() { + return message; + } +} diff --git a/src/main/java/usecases/nevagateSignup/NevagateSignupDataAccessInterface.java b/src/main/java/usecases/nevagateSignup/NevagateSignupDataAccessInterface.java new file mode 100644 index 000000000..ae8dd743e --- /dev/null +++ b/src/main/java/usecases/nevagateSignup/NevagateSignupDataAccessInterface.java @@ -0,0 +1,7 @@ +package usecases.nevagateSignup; + +/** + * Interface for data access logic related to navigating to the signup page. + */ +public interface NevagateSignupDataAccessInterface { +} \ No newline at end of file diff --git a/src/main/java/usecases/nevagateSignup/NevagateSignupInputBoundary.java b/src/main/java/usecases/nevagateSignup/NevagateSignupInputBoundary.java new file mode 100644 index 000000000..93b8a1661 --- /dev/null +++ b/src/main/java/usecases/nevagateSignup/NevagateSignupInputBoundary.java @@ -0,0 +1,13 @@ +package usecases.nevagateSignup; + +/** + * The input boundary interface for the NavigateSignup use case. + */ +public interface NevagateSignupInputBoundary { + /** + * Executes the navigation to the signup page. + * + * @param inputData The data required for navigation, e.g., user context. + */ + void execute(NevagateSignupInputData inputData); +} diff --git a/src/main/java/usecases/nevagateSignup/NevagateSignupInputData.java b/src/main/java/usecases/nevagateSignup/NevagateSignupInputData.java new file mode 100644 index 000000000..7677a3dbf --- /dev/null +++ b/src/main/java/usecases/nevagateSignup/NevagateSignupInputData.java @@ -0,0 +1,27 @@ +package usecases.nevagateSignup; + +/** + * Input data class for the NavigateSignup use case. + * Encapsulates the necessary information to trigger the navigation logic. + */ +public class NevagateSignupInputData { + private final String context; + + /** + * Constructs a NevagateSignupInputData instance. + * + * @param context A string representing the navigation context (e.g., "Navigate to Signup"). + */ + public NevagateSignupInputData(String context) { + this.context = context; + } + + /** + * Gets the navigation context. + * + * @return A string representing the context. + */ + public String getContext() { + return context; + } +} diff --git a/src/main/java/usecases/nevagateSignup/NevagateSignupInteractor.java b/src/main/java/usecases/nevagateSignup/NevagateSignupInteractor.java new file mode 100644 index 000000000..c45a25edb --- /dev/null +++ b/src/main/java/usecases/nevagateSignup/NevagateSignupInteractor.java @@ -0,0 +1,30 @@ +package usecases.nevagateSignup; + +/** + * The interactor for the NavigateSignup use case. + * Implements the business logic for navigating to the signup page. + */ +public class NevagateSignupInteractor implements NevagateSignupInputBoundary { + private final NevagateSignupOutputBoundary outputBoundary; + + /** + * Constructs a NevagateSignupInteractor instance. + * + * @param outputBoundary The output boundary for presenting the navigation results. + */ + public NevagateSignupInteractor(NevagateSignupOutputBoundary outputBoundary) { + this.outputBoundary = outputBoundary; + } + + /** + * Executes the navigation to the signup page by invoking the output boundary. + * + * @param inputData The input data containing navigation context information. + */ + @Override + public void execute(NevagateSignupInputData inputData) { + // Prepare output data + NevagateSignupOutputData outputData = new NevagateSignupOutputData("Navigating to Signup"); + outputBoundary.present(outputData); + } +} diff --git a/src/main/java/usecases/nevagateSignup/NevagateSignupOutputBoundary.java b/src/main/java/usecases/nevagateSignup/NevagateSignupOutputBoundary.java new file mode 100644 index 000000000..62d839a62 --- /dev/null +++ b/src/main/java/usecases/nevagateSignup/NevagateSignupOutputBoundary.java @@ -0,0 +1,14 @@ +package usecases.nevagateSignup; + +/** + * The output boundary interface for the NavigateSignup use case. + * Defines the contract for presenting the results of the navigation process. + */ +public interface NevagateSignupOutputBoundary { + /** + * Presents the output data for the navigation logic. + * + * @param outputData The output data containing navigation results. + */ + void present(NevagateSignupOutputData outputData); +} diff --git a/src/main/java/usecases/nevagateSignup/NevagateSignupOutputData.java b/src/main/java/usecases/nevagateSignup/NevagateSignupOutputData.java new file mode 100644 index 000000000..c4dabe776 --- /dev/null +++ b/src/main/java/usecases/nevagateSignup/NevagateSignupOutputData.java @@ -0,0 +1,28 @@ +package usecases.nevagateSignup; + + +/** + * Output data class for the NavigateSignup use case. + * Encapsulates the results of the navigation process. + */ +public class NevagateSignupOutputData { + private final String message; + + /** + * Constructs a NevagateSignupOutputData instance. + * + * @param message A message indicating the navigation result. + */ + public NevagateSignupOutputData(String message) { + this.message = message; + } + + /** + * Gets the navigation result message. + * + * @return A string containing the result message. + */ + public String getMessage() { + return message; + } +} diff --git a/src/main/java/usecases/startallowcate/AllowcateDataAccessInterface.java b/src/main/java/usecases/startallowcate/AllowcateDataAccessInterface.java new file mode 100644 index 000000000..eb6f23bc7 --- /dev/null +++ b/src/main/java/usecases/startallowcate/AllowcateDataAccessInterface.java @@ -0,0 +1,51 @@ +package usecases.startallowcate; + +import entities.PlayerAttributes; + +/** + * Data access interface for allowcating attribute points, assume allowcate a point each time. + */ +public interface AllowcateDataAccessInterface { + + /** + * We need this to decrease point, and increase according attribute which player selected. + * @return current Playerattribute class type. + */ + PlayerAttributes getPlayerAttributes(); + + /** + * Set social to new social value. + * @param social new social attribute. + */ + void setSocial(int social); + + /** + * Set luck to new luck value. + * @param luck new luck attribute. + */ + void setLuck(int luck); + + /** + * Set thrift to new thrift value. + * @param thrift new thrift attribute. + */ + void setThrift(int thrift); + + /** + * Set mobilization to new mobilization value. + * @param mobilization new mobilization attribute. + */ + void setMobilization(int mobilization); + + /** + * Set generalship to new social value. + * @param generalship new generalship attribute. + */ + void setGeneralship(int generalship); + + /** + * Set point to new point value. + * @param point new point. + */ + void setPoint(int point); +} diff --git a/src/main/java/usecases/startallowcate/AllowcateInputBoundary.java b/src/main/java/usecases/startallowcate/AllowcateInputBoundary.java new file mode 100644 index 000000000..2a8cf7c37 --- /dev/null +++ b/src/main/java/usecases/startallowcate/AllowcateInputBoundary.java @@ -0,0 +1,14 @@ +package usecases.startallowcate; + +/** + * Input boundary of allowcate, interactor implement this and should have execute method. + */ +public interface AllowcateInputBoundary { + + /** + * Execute this, which decrement point and increment which point player chose. With output data being all newly + * update points and attributes. + * @param inputdata inputdata from player side, should + */ + void execute(AllowcateInputdata inputdata); +} diff --git a/src/main/java/usecases/startallowcate/AllowcateInputdata.java b/src/main/java/usecases/startallowcate/AllowcateInputdata.java new file mode 100644 index 000000000..be878ebac --- /dev/null +++ b/src/main/java/usecases/startallowcate/AllowcateInputdata.java @@ -0,0 +1,48 @@ +package usecases.startallowcate; + +/** + * Inputdata type, contain all we need to know from player's side, + * which is which attribute they choose by name in string. + * (all lowercase except first letter format as in entityconstant) + */ +public class AllowcateInputdata { + private int point; + private int social; + private int luck; + private int thrift; + private int mobilization; + private int generalship; + + public AllowcateInputdata(int point, int social, int luck, int thrift, int mobilization, int generalship) { + this.point = point; + this.social = social; + this.luck = luck; + this.thrift = thrift; + this.mobilization = mobilization; + this.generalship = generalship; + } + + public int getPoint() { + return point; + } + + public int getSocial() { + return social; + } + + public int getLuck() { + return luck; + } + + public int getThrift() { + return thrift; + } + + public int getMobilization() { + return mobilization; + } + + public int getGeneralship() { + return generalship; + } +} diff --git a/src/main/java/usecases/startallowcate/AllowcateInteractor.java b/src/main/java/usecases/startallowcate/AllowcateInteractor.java new file mode 100644 index 000000000..02e983930 --- /dev/null +++ b/src/main/java/usecases/startallowcate/AllowcateInteractor.java @@ -0,0 +1,42 @@ +package usecases.startallowcate; + +/** + * Allowcate interactor, decrease point by one, add attribute select by one, if point was greater than 0. + * If points are less than 0, fail and return fail message. + */ +public class AllowcateInteractor implements AllowcateInputBoundary { + private AllowcateDataAccessInterface allowcateDataAccessInterface; + private AllowcateOutputBoundary allowcateOutputBoundary; + + public AllowcateInteractor(AllowcateDataAccessInterface allowcateDataAccessInterface, + AllowcateOutputBoundary allowcateOutputBoundary) { + this.allowcateDataAccessInterface = allowcateDataAccessInterface; + this.allowcateOutputBoundary = allowcateOutputBoundary; + + } + + @Override + public void execute(AllowcateInputdata inputdata) { + String failmessage = " "; + + // Check if points are available + if (inputdata.getPoint() > 0) { + failmessage = "Not all attribute points used!"; + allowcateOutputBoundary.preparefailureview(failmessage); + } + else if (inputdata.getPoint() == 0) { + allowcateDataAccessInterface.setPoint(inputdata.getPoint()); + allowcateDataAccessInterface.setSocial(inputdata.getSocial()); + allowcateDataAccessInterface.setLuck(inputdata.getLuck()); + allowcateDataAccessInterface.setMobilization(inputdata.getMobilization()); + allowcateDataAccessInterface.setThrift(inputdata.getThrift()); + allowcateDataAccessInterface.setGeneralship(inputdata.getGeneralship()); + final AllowcateOutputData outputData = new AllowcateOutputData(); + allowcateOutputBoundary.NevagateStartGame(outputData); + } + else { + failmessage = "Insufficient points!"; + allowcateOutputBoundary.preparefailureview(failmessage); + } + } +} diff --git a/src/main/java/usecases/startallowcate/AllowcateOutputBoundary.java b/src/main/java/usecases/startallowcate/AllowcateOutputBoundary.java new file mode 100644 index 000000000..b4b5654ef --- /dev/null +++ b/src/main/java/usecases/startallowcate/AllowcateOutputBoundary.java @@ -0,0 +1,18 @@ +package usecases.startallowcate; + +/** + * Output boundary of allowcate, preparesuccessview here, newly updated attributes, or failed view with failed message. + */ +public interface AllowcateOutputBoundary { + /** + * If success, then use new updated attributes stored in outputdata to create new view for player. + * @param outputData all new updated attribute point. + */ + void NevagateStartGame(AllowcateOutputData outputData); + + /** + * If failure, such as points is already zero, show player this is invaild move, or don't let them click at all. + * @param failmessage fail message. + */ + void preparefailureview(String failmessage); +} diff --git a/src/main/java/usecases/startallowcate/AllowcateOutputData.java b/src/main/java/usecases/startallowcate/AllowcateOutputData.java new file mode 100644 index 000000000..5f86f69f7 --- /dev/null +++ b/src/main/java/usecases/startallowcate/AllowcateOutputData.java @@ -0,0 +1,8 @@ +package usecases.startallowcate; + +/** + * Outputdata type for the view side, which contain newly updated attributes and points left for them to update view. + */ +public class AllowcateOutputData { + +} diff --git a/src/main/java/view/CharacterCreationView.java b/src/main/java/view/CharacterCreationView.java new file mode 100644 index 000000000..0deeb376e --- /dev/null +++ b/src/main/java/view/CharacterCreationView.java @@ -0,0 +1,269 @@ +package view; + +import java.awt.Container; +import java.awt.Font; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.SpringLayout; + +import interface_adapters.nevagatemainview.NevagateMainController; +import interface_adapters.startallowcatepoint.AllowcateController; +import interface_adapters.startallowcatepoint.AllowcateInterface; + +/** + * Character creation view that allows players to allocate points to various attributes + * such as Social, Luck, Mobilization, Thrift, and Generalship. + * This view also provides navigation to the main menu and starting the game. + */ +public class CharacterCreationView extends JFrame implements AllowcateInterface { + public static final String TEXT_SOCIAL = "Social"; + public static final String TEXT_LUCK = "Luck"; + public static final String TEXT_THRIFT = "Thrift"; + public static final String TEXT_MOBILIZATION = "Mobilization"; + public static final String TEXT_GENERALSHIP = "Generalship"; + private int points = Constants.TWENTY; + private final JLabel pointsLabel; + private final JLabel socialLabel; + private final JLabel luckLabel; + private final JLabel mobilizationLabel; + private final JLabel thriftLabel; + private final JLabel generalshipLabel; + private int social; + private int luck; + private int mobilization; + private int thrift; + private int generalship; + private AllowcateController allowcateController; + private NevagateMainController nevagateMainController; + + @SuppressWarnings({"checkstyle:LambdaParameterName", "checkstyle:SuppressWarnings", + "checkstyle:ExecutableStatementCount"}) + public CharacterCreationView() { + super("Build Your Character"); + + // Set up container and layout + final Container container = getContentPane(); + final SpringLayout layout = new SpringLayout(); + container.setLayout(layout); + + // Points Label + pointsLabel = new JLabel("Points: " + points); + pointsLabel.setFont(new Font("Serif", Font.BOLD, Constants.TWENTY)); + container.add(pointsLabel); + + // Attribute Labels and Buttons + socialLabel = new JLabel("Social: " + social); + final JButton socialButton = createButton(TEXT_SOCIAL); + container.add(socialLabel); + container.add(socialButton); + + luckLabel = new JLabel("Luck: " + luck); + final JButton luckButton = createButton(TEXT_LUCK); + container.add(luckLabel); + container.add(luckButton); + + mobilizationLabel = new JLabel("Mobilization: " + mobilization); + final JButton mobilizationButton = createButton(TEXT_MOBILIZATION); + container.add(mobilizationLabel); + container.add(mobilizationButton); + + thriftLabel = new JLabel("Thrift: " + thrift); + final JButton thriftButton = createButton(TEXT_THRIFT); + container.add(thriftLabel); + container.add(thriftButton); + + generalshipLabel = new JLabel("Generalship: " + generalship); + final JButton generalshipButton = createButton(TEXT_GENERALSHIP); + container.add(generalshipLabel); + container.add(generalshipButton); + + // Back and Start Game Buttons + final JButton backButton = new JButton("Back"); + final JButton startGameButton = new JButton("Start Game"); + container.add(backButton); + container.add(startGameButton); + + // Layout constraints + extracted(layout, container, socialButton, luckButton, mobilizationButton, + thriftButton, generalshipButton, backButton, startGameButton); + + // Button Action Listeners + addListeners(socialButton, luckButton, mobilizationButton, thriftButton, generalshipButton); + + backButton.addActionListener(e -> { + nevagateMainController.execute(); + }); + + startGameButton.addActionListener(e -> { + allowcateController.execute(points, social, luck, thrift, mobilization, generalship); + }); + + // Window settings + setSize(Constants.FOUR_HUNDRED, Constants.SIX_HUNDRED); + setDefaultCloseOperation(EXIT_ON_CLOSE); + setResizable(false); + setVisible(false); + } + + /** + * Sets the AllowcateController and NevagateMainController for this instance. + * + * @param AllowcateController the instance of {@code AllowcateController} to set + * @param NevagateMainController the instance of {@code NevagateMainController} to set + */ + public void setAllowcateController(AllowcateController AllowcateController, + NevagateMainController NevagateMainController) { + this.allowcateController = AllowcateController; + this.nevagateMainController = NevagateMainController; + } + + /** + * Adds action listeners to the buttons for allocating points to attributes. + * + * @param socialButton Button to increase Social attribute. + * @param luckButton Button to increase Luck attribute. + * @param mobilizationButton Button to increase Mobilization attribute. + * @param thriftButton Button to increase Thrift attribute. + * @param generalshipButton Button to increase Generalship attribute. + */ + @SuppressWarnings({"checkstyle:LambdaParameterName", "checkstyle:SuppressWarnings"}) + private void addListeners(JButton socialButton, JButton luckButton, JButton mobilizationButton, + JButton thriftButton, JButton generalshipButton) { + socialButton.addActionListener(e -> updatePoints(TEXT_SOCIAL)); + luckButton.addActionListener(e -> updatePoints(TEXT_LUCK)); + mobilizationButton.addActionListener(e -> updatePoints(TEXT_MOBILIZATION)); + thriftButton.addActionListener(e -> updatePoints(TEXT_THRIFT)); + generalshipButton.addActionListener(e -> updatePoints(TEXT_GENERALSHIP)); + } + + private void extracted(SpringLayout layout, Container container, JButton socialButton, JButton luckButton, + JButton mobilizationButton, JButton thriftButton, JButton generalshipButton, + JButton backButton, JButton startGameButton) { + layout.putConstraint(SpringLayout.WEST, pointsLabel, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.NORTH, pointsLabel, Constants.TWENTY, SpringLayout.NORTH, container); + + layout.putConstraint(SpringLayout.WEST, socialLabel, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.NORTH, socialLabel, Constants.TWENTY, SpringLayout.SOUTH, pointsLabel); + layout.putConstraint(SpringLayout.WEST, socialButton, Constants.TWENTY, SpringLayout.EAST, socialLabel); + layout.putConstraint(SpringLayout.NORTH, socialButton, 0, SpringLayout.NORTH, socialLabel); + + layout.putConstraint(SpringLayout.WEST, luckLabel, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.NORTH, luckLabel, Constants.TWENTY, SpringLayout.SOUTH, socialLabel); + layout.putConstraint(SpringLayout.WEST, luckButton, Constants.TWENTY, SpringLayout.EAST, luckLabel); + layout.putConstraint(SpringLayout.NORTH, luckButton, 0, SpringLayout.NORTH, luckLabel); + + layout.putConstraint(SpringLayout.WEST, mobilizationLabel, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.NORTH, mobilizationLabel, Constants.TWENTY, SpringLayout.SOUTH, luckLabel); + layout.putConstraint(SpringLayout.WEST, mobilizationButton, Constants.TWENTY, SpringLayout.EAST, + mobilizationLabel); + layout.putConstraint(SpringLayout.NORTH, mobilizationButton, 0, SpringLayout.NORTH, mobilizationLabel); + + layout.putConstraint(SpringLayout.WEST, thriftLabel, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.NORTH, thriftLabel, Constants.TWENTY, SpringLayout.SOUTH, mobilizationLabel); + layout.putConstraint(SpringLayout.WEST, thriftButton, Constants.TWENTY, SpringLayout.EAST, thriftLabel); + layout.putConstraint(SpringLayout.NORTH, thriftButton, 0, SpringLayout.NORTH, thriftLabel); + + layout.putConstraint(SpringLayout.WEST, generalshipLabel, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.NORTH, generalshipLabel, Constants.TWENTY, SpringLayout.SOUTH, thriftLabel); + layout.putConstraint(SpringLayout.WEST, generalshipButton, Constants.TWENTY, SpringLayout.EAST, + generalshipLabel); + layout.putConstraint(SpringLayout.NORTH, generalshipButton, 0, SpringLayout.NORTH, generalshipLabel); + + layout.putConstraint(SpringLayout.WEST, backButton, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.SOUTH, backButton, -Constants.TWENTY, SpringLayout.SOUTH, container); + + layout.putConstraint(SpringLayout.EAST, startGameButton, -Constants.TWENTY, SpringLayout.EAST, container); + layout.putConstraint(SpringLayout.SOUTH, startGameButton, -Constants.TWENTY, SpringLayout.SOUTH, container); + } + + /** + * Creates a button with a given label and font style. + * + * @param text The text to display on the button. + * @return A new JButton instance. + */ + private JButton createButton(String text) { + final JButton button = new JButton("+"); + button.setFont(new Font("Arial", Font.PLAIN, Constants.TWENTY)); + button.setActionCommand(text); + return button; + } + + /** + * Updates the points allocation for a specific attribute. + * + * @param attribute The name of the attribute to update. + */ + private void updatePoints(String attribute) { + if (points > 0) { + switch (attribute) { + case "Social": + social++; + socialLabel.setText("Social: " + social); + break; + case "Luck": + luck++; + luckLabel.setText("Luck: " + luck); + break; + case "Mobilization": + mobilization++; + mobilizationLabel.setText("Mobilization: " + mobilization); + break; + case "Thrift": + thrift++; + thriftLabel.setText("Thrift: " + thrift); + break; + case "Generalship": + generalship++; + generalshipLabel.setText("Generalship: " + generalship); + break; + default: + // No action needed + break; + } + points--; + pointsLabel.setText("Points: " + points); + } + else { + JOptionPane.showMessageDialog(this, "No points left!", "Warning", + JOptionPane.WARNING_MESSAGE); + } + } + + /** + * Renders the component by setting its size and making it visible. + * The size is set to 400x600 pixels. + */ + public void render() { + setSize(Constants.FOUR_HUNDRED, Constants.SIX_HUNDRED); + setVisible(true); + } + + /** + * Disables the rendering of the component by changing its size and making it invisible. + * The size is set to 400x400 pixels. + */ + public void disrender() { + setSize(Constants.FOUR_HUNDRED, Constants.FOUR_HUNDRED); + setVisible(false); + } + + /** + * Displays a failure message when allocation fails. + * + * @param message The error message to display. + */ + @Override + public void failureAllowcate(String message) { + // Display the failure message in a dialog box + JOptionPane.showMessageDialog( + this, + message, + "Allocation Failed", + JOptionPane.ERROR_MESSAGE + ); + } +} diff --git a/src/main/java/view/Constants.java b/src/main/java/view/Constants.java new file mode 100644 index 000000000..ea7bcf812 --- /dev/null +++ b/src/main/java/view/Constants.java @@ -0,0 +1,34 @@ +package view; + +import java.awt.*; + +/** + * A utility class containing constants used throughout the program. + * These constants represent various numerical values and a theme color + * for consistent usage across different components. + */ +public class Constants { + public static final int MINIMAPSIZE = 12; + public static final int THREE = 3; + public static final int FIVE = 5; + public static final int TEN = 10; + public static final int FIFTEEN = 15; + public static final int TWENTY = 20; + public static final int TWENTYFIVE = 25; + public static final int THIRTY = 30; + public static final int FORTY = 40; + public static final int FIFTY = 50; + public static final int SIXTY = 60; + public static final int EIGHTY = 80; + public static final int ONE_HUNDRED = 100; + public static final int TWO_HUNDRED = 200; + public static final int THREE_HUNDRED = 300; + public static final int FOUR_HUNDRED = 400; + public static final int FIVE_HUNDRED = 500; + public static final int SIX_HUNDRED = 600; + public static final int EIGHT_HUNDRED = 800; + public static final int ONE_THOUSAND = 1000; + + /** Theme color used throughout the program. */ + public static final Color THEME_COLOR = new Color(140, 70, 20); +} diff --git a/src/main/java/view/EventView.java b/src/main/java/view/EventView.java new file mode 100644 index 000000000..8ff190eb6 --- /dev/null +++ b/src/main/java/view/EventView.java @@ -0,0 +1,272 @@ +package view; + +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.event.ActionListener; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SpringLayout; + +import interface_adapters.EventManager; +import interface_adapters.eventinitializer.EventInitializerController; +import interface_adapters.eventinitializer.EventInitializerInterface; +import interface_adapters.eventrespond.ambush.AmbushResponseInterface; +import interface_adapters.eventrespond.blizzard.BlizzardResponseInterface; +import interface_adapters.eventrespond.flood.FloodResponseInterface; +import interface_adapters.eventrespond.survivor.SurvivorResponseInterface; +import interface_adapters.eventrespond.trader.TraderResponseInterface; +import interface_adapters.fetchcurrentevent.FetchEventController; +import interface_adapters.fetchcurrentevent.FetchEventInterface; +import interface_adapters.nevagategame.NevagateGameController; +import interface_adapters.nevagategame.NevagateGameInterface; + +/** + * Represents the view for displaying and interacting with events in the game. + */ +public class EventView extends JFrame implements EventInitializerInterface, + AmbushResponseInterface, BlizzardResponseInterface, TraderResponseInterface, + FloodResponseInterface, SurvivorResponseInterface, FetchEventInterface, NevagateGameInterface { + + // UI components as instance variables + private final JLabel eventLabel; + private final JTextArea descriptionArea; + private final JScrollPane descriptionScrollPane; + private final JButton fightButton; + private final JButton negotiateButton; + private final JButton fleeButton; + private final JButton backButton; + private final SpringLayout layout; + + private EventInitializerController eventInitializerController; + private EventManager eventManager; + private FetchEventController fetchEventController; + private NevagateGameController nevagateGameController; + + /** + * Constructs the EventView UI and initializes components. + */ + public EventView() { + super("Event"); + + // Initialize the container and layout + final Container container = getContentPane(); + layout = new SpringLayout(); + container.setLayout(layout); + + // Initialize UI components + eventLabel = new JLabel("Event:"); + eventLabel.setFont(new Font("Serif", Font.BOLD, Constants.TWENTY)); + + // Initialize the description area + descriptionArea = new JTextArea("Event description goes here..."); + descriptionArea.setEditable(false); + descriptionArea.setBackground(Color.LIGHT_GRAY); + descriptionArea.setBorder(BorderFactory.createLineBorder(Color.BLACK)); + descriptionArea.setLineWrap(true); + descriptionArea.setWrapStyleWord(true); + + // Wrap the description area in a scroll pane + // Now it's an instance variable + descriptionScrollPane = new JScrollPane(descriptionArea); + descriptionScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + descriptionScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + descriptionScrollPane.setPreferredSize(new Dimension(Constants.FOUR_HUNDRED, Constants.ONE_HUNDRED)); + + // Buttons + fightButton = new JButton("Fight"); + negotiateButton = new JButton("Negotiate"); + fleeButton = new JButton("Flee"); + backButton = new JButton("Back"); + + // Add components to container + containerContent(container); + + // Call applyLayoutConstraints to position components + applyLayoutConstraints(container); + + // Add button listeners + fightButton.addActionListener(event -> { + fetchEventController.execute(); + // also reset event manager event string. + eventManager.execute(1); + }); + + negotiateButton.addActionListener(event -> { + fetchEventController.execute(); + // also reset event manager event string. + eventManager.execute(2); + }); + + fleeButton.addActionListener(event -> { + fetchEventController.execute(); + // also reset event manager event string. + eventManager.execute(Constants.THREE); + }); + + backButton.addActionListener(event -> { + nevagateGameController.execute(); + }); + + // Window settings + setSize(Constants.SIX_HUNDRED, Constants.FOUR_HUNDRED); + setDefaultCloseOperation(EXIT_ON_CLOSE); + setResizable(false); + setVisible(false); + } + + /** + * Sets the controllers required for handling events and navigation. + * + * @param inieventInitializerController Controller for event initialization. + * @param inifetchEventController Controller for fetching event details. + * @param ininevagateGameController Controller for game navigation. + */ + public void setController(EventInitializerController inieventInitializerController, + FetchEventController inifetchEventController, + NevagateGameController ininevagateGameController) { + this.eventInitializerController = inieventInitializerController; + this.fetchEventController = inifetchEventController; + this.nevagateGameController = ininevagateGameController; + } + + /** + * Sets the event manager responsible for handling event-related data. + * + * @param inieventManager The event manager instance. + */ + public void setManager(EventManager inieventManager) { + this.eventManager = inieventManager; + } + + private void containerContent(Container container) { + container.add(eventLabel); + // Add the scroll pane, not just the text area + container.add(descriptionScrollPane); + container.add(fightButton); + container.add(negotiateButton); + container.add(fleeButton); + container.add(backButton); + } + + /** + * Applies layout constraints to the UI components. + * + * @param container The parent container. + */ + private void applyLayoutConstraints(Container container) { + // Event Label Constraints + layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, eventLabel, 0, SpringLayout.HORIZONTAL_CENTER, container); + layout.putConstraint(SpringLayout.NORTH, eventLabel, Constants.TWENTY, SpringLayout.NORTH, container); + + // Description Scroll Pane Constraints + layout.putConstraint(SpringLayout.WEST, descriptionScrollPane, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.EAST, descriptionScrollPane, -Constants.TWENTY, SpringLayout.EAST, container); + layout.putConstraint(SpringLayout.NORTH, descriptionScrollPane, Constants.TWENTY, + SpringLayout.SOUTH, eventLabel); + layout.putConstraint(SpringLayout.SOUTH, descriptionScrollPane, -Constants.ONE_HUNDRED, + SpringLayout.SOUTH, container); + + // Fight Button Constraints + layout.putConstraint(SpringLayout.WEST, fightButton, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.NORTH, fightButton, Constants.TWENTY, SpringLayout.SOUTH, + descriptionScrollPane); + + // Negotiate Button Constraints + layout.putConstraint(SpringLayout.WEST, negotiateButton, Constants.TWENTY, SpringLayout.EAST, fightButton); + layout.putConstraint(SpringLayout.NORTH, negotiateButton, 0, SpringLayout.NORTH, fightButton); + + // Flee Button Constraints + layout.putConstraint(SpringLayout.WEST, fleeButton, Constants.TWENTY, SpringLayout.EAST, negotiateButton); + layout.putConstraint(SpringLayout.NORTH, fleeButton, 0, SpringLayout.NORTH, fightButton); + + // Back Button Constraints + layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, backButton, 0, SpringLayout.HORIZONTAL_CENTER, container); + layout.putConstraint(SpringLayout.NORTH, backButton, Constants.TWENTY, SpringLayout.SOUTH, fightButton); + } + + /** + * Adds default action listeners to buttons. + * + * @param returnToGameViewListener The listener to return to the GameView. + */ + private void addListeners(ActionListener returnToGameViewListener) { + fightButton.addActionListener(returnToGameViewListener); + negotiateButton.addActionListener(returnToGameViewListener); + fleeButton.addActionListener(returnToGameViewListener); + backButton.addActionListener(returnToGameViewListener); + } + + /** + * Renders the component by initializing required events, setting its size, + * and making it visible. + * + *

This method triggers the execution of the eventInitializerController + * and adjusts the component's size to a predefined value. Finally, it makes + * the component visible to the user.

+ */ + public void render() { + eventInitializerController.execute(); + setSize(Constants.FOUR_HUNDRED, Constants.FOUR_HUNDRED); + setVisible(true); + } + + /** + * Disables the rendering of the component by maintaining its size but + * making it invisible. + * + *

This method adjusts the component's size to a predefined value but + * ensures that it is not visible to the user.

+ */ + public void disrender() { + setSize(Constants.FOUR_HUNDRED, Constants.FOUR_HUNDRED); + setVisible(false); + } + + @Override + public void updateUiEventInitializer(String eventdescription, String option1, String option2, String option3) { + descriptionArea.setText(eventdescription); + fightButton.setText(option1); + negotiateButton.setText(option2); + fleeButton.setText(option3); + } + + @Override + public void failureEventInitializer(String failmessage) { + JOptionPane.showMessageDialog(this, failmessage, "Error", JOptionPane.ERROR_MESSAGE); + } + + @Override + public void updateUiResponse(String message) { + JOptionPane.showMessageDialog( + this, + message, + "Notification", + JOptionPane.INFORMATION_MESSAGE + ); + nevagateGameController.execute(); + // return to game. + } + + @Override + public void failureResponse(String errorMessage) { + JOptionPane.showMessageDialog( + this, + errorMessage, + "Invaild choice", + JOptionPane.ERROR_MESSAGE + ); + } + + @Override + public void setEventName(String event) { + eventManager.setActiveEvent(event); + } +} diff --git a/src/main/java/view/GameOverView.java b/src/main/java/view/GameOverView.java new file mode 100644 index 000000000..dce6bc571 --- /dev/null +++ b/src/main/java/view/GameOverView.java @@ -0,0 +1,176 @@ +package view; + +import java.awt.Color; +import java.awt.Container; +import java.awt.Font; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JTextArea; +import javax.swing.SpringLayout; + +import app.RestartGameController; +import interface_adapters.NavigationManagerJson; +import interface_adapters.endprocesshorde.HordeInterface; +import interface_adapters.gamelosedetecter.LoseInterface; +import interface_adapters.nevagatemainview.NevagateMainController; +import interface_adapters.nevagatemainview.NevagateMainInterface; + +/** + * Represents the "Game Over" view in the application. + * Provides UI components for displaying the game result and returning to the main menu. + */ +public class GameOverView extends JFrame implements LoseInterface, HordeInterface, NevagateMainInterface { + // Make it an instance variable + private final JLabel scoreLabel; + // Make it an instance variable + private final JTextArea descriptionArea; + private NevagateMainController nevagateMainController; + private NavigationManagerJson navigationManager; + private RestartGameController restartGameController; + + /** + * Constructs the GameOverView UI and initializes all components. + */ + public GameOverView() { + super("Game Over"); + + final Container container = getContentPane(); + final SpringLayout layout = new SpringLayout(); + container.setLayout(layout); + + // Title label + final JLabel titleLabel = new JLabel("Game Over"); + titleLabel.setFont(new Font("Serif", Font.BOLD, Constants.TWENTY)); + container.add(titleLabel); + + // Score label + // Initialize with a default value + scoreLabel = new JLabel("Score: 0"); + scoreLabel.setFont(new Font("Serif", Font.PLAIN, Constants.TWENTY)); + container.add(scoreLabel); + + // Description area + descriptionArea = new JTextArea("Game description goes here..."); + descriptionArea.setEditable(false); + descriptionArea.setBackground(Color.LIGHT_GRAY); + descriptionArea.setBorder(BorderFactory.createLineBorder(Color.BLACK)); + descriptionArea.setLineWrap(true); + // Ensure long text wraps + descriptionArea.setWrapStyleWord(true); + container.add(descriptionArea); + + // Main menu button + final JButton mainMenuButton = new JButton("Main Menu"); + mainMenuButton.setFont(new Font("Arial", Font.PLAIN, Constants.TWENTY)); + container.add(mainMenuButton); + + // Layout constraints + extracted(layout, titleLabel, container, scoreLabel, descriptionArea, mainMenuButton); + + // Add action listener to "Main Menu" button + mainMenuButton.addActionListener(event -> { + restartGameController.resetGame(); + navigationManager.showMainView(); + dispose(); + }); + + // Window settings + setSize(Constants.SIX_HUNDRED, Constants.FOUR_HUNDRED); + setDefaultCloseOperation(EXIT_ON_CLOSE); + setResizable(false); + setVisible(false); + } + + public void setController(NevagateMainController ininevagateMainController) { + this.nevagateMainController = ininevagateMainController; + } + + public void setNavigationManager(NavigationManagerJson navigationManager) { + this.navigationManager = navigationManager; + } + + public void setRestartGameController(RestartGameController restartGameController) { + this.restartGameController = restartGameController; + } + + private static void extracted(SpringLayout layout, JLabel titleLabel, Container container, JLabel scoreLabel, + JTextArea descriptionArea, JButton mainMenuButton) { + layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, titleLabel, 0, SpringLayout.HORIZONTAL_CENTER, container); + layout.putConstraint(SpringLayout.NORTH, titleLabel, Constants.TWENTY, SpringLayout.NORTH, container); + + layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, scoreLabel, 0, SpringLayout.HORIZONTAL_CENTER, container); + layout.putConstraint(SpringLayout.NORTH, scoreLabel, Constants.TWENTY, SpringLayout.SOUTH, titleLabel); + + layout.putConstraint(SpringLayout.WEST, descriptionArea, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.EAST, descriptionArea, -Constants.TWENTY, SpringLayout.EAST, container); + layout.putConstraint(SpringLayout.NORTH, descriptionArea, Constants.TWENTY, SpringLayout.SOUTH, scoreLabel); + layout.putConstraint(SpringLayout.SOUTH, descriptionArea, -Constants.ONE_HUNDRED, SpringLayout.SOUTH, + container); + + layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, mainMenuButton, 0, SpringLayout.HORIZONTAL_CENTER, + container); + layout.putConstraint(SpringLayout.NORTH, mainMenuButton, Constants.TWENTY, SpringLayout.SOUTH, descriptionArea); + } + + /** + * Renders the component by initializing required events, setting its size, + * and making it visible. + * + *

This method triggers the execution of the eventInitializerController + * and adjusts the component's size to a predefined value. Finally, it makes + * the component visible to the user.

+ */ + public void render() { + setSize(Constants.FOUR_HUNDRED, Constants.SIX_HUNDRED); + setVisible(true); + } + + /** + * Disables the rendering of the component by maintaining its size but + * making it invisible. + * + *

This method adjusts the component's size to a predefined value but + * ensures that it is not visible to the user.

+ */ + public void disrender() { + setSize(Constants.FOUR_HUNDRED, Constants.FOUR_HUNDRED); + setVisible(false); + } + + public static void main(String[] args) { + new GameOverView(); + } + + @Override + public void prepareGameOverEarly(String message, int score) { + // Update the score label with the given score + scoreLabel.setText("Score: " + score); + + // Update the description area with the provided message + descriptionArea.setText(message); + + // Ensure the user can see the new content + descriptionArea.setCaretPosition(0); + + } + + @Override + public void updateUiHorde(String message, int score) { + scoreLabel.setText("Score: " + score); + + // Update the description area with the provided message + descriptionArea.setText(message); + + // Ensure the user can see the new content + descriptionArea.setCaretPosition(0); + + } + + @Override + public void failureHorde(String failmessage) { + + } +} diff --git a/src/main/java/view/GameView.java b/src/main/java/view/GameView.java new file mode 100644 index 000000000..daf965923 --- /dev/null +++ b/src/main/java/view/GameView.java @@ -0,0 +1,706 @@ +package view; + +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.ArrayList; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SpringLayout; + +import interface_adapters.NavigationManager; +import interface_adapters.broadcast.BroadcastController; +import interface_adapters.broadcast.BroadcastInterface; +import interface_adapters.dailygather.DailyGatherController; +import interface_adapters.dailygather.DailyGatherInterface; +import interface_adapters.dailymove.DailyMoveController; +import interface_adapters.dailymove.DailyMoveInterface; +import interface_adapters.endprocesshorde.HordeController; +import interface_adapters.endprocesshorde.HordeInterfaceNavigate; +import interface_adapters.eventdecide.EventDecideController; +import interface_adapters.eventdecide.EventDecideInterface; +import interface_adapters.fetchresource.FetchController; +import interface_adapters.fetchresource.FetchInterface; +import interface_adapters.gamelosedetecter.LoseController; +import interface_adapters.gamelosedetecter.LoseInterfaceNavigate; +import interface_adapters.gameminimap.MinimapController; +import interface_adapters.gameminimap.MinimapInterface; +import interface_adapters.gamenewday.NewdayController; +import interface_adapters.gamenewday.NewdayInterface; +import interface_adapters.gameplacedescription.PlaceDescriptionController; +import interface_adapters.gameplacedescription.PlaceDescriptionInterface; +import interface_adapters.nevagateevent.NevagateEventController; +import interface_adapters.nevagateevent.NevagateEventInterface; +import interface_adapters.nevagategameover.NevagateGameOverController; +import interface_adapters.nevagategameover.NevagateGameOverInterface; + +/** + * Represents the Game view in the application. + * Provides UI components for displaying the game result and returning to the main menu. + */ +public class GameView extends JFrame implements PropertyChangeListener, FetchInterface, BroadcastInterface, + PlaceDescriptionInterface, DailyGatherInterface, DailyMoveInterface, + EventDecideInterface, NevagateEventInterface, NewdayInterface, MinimapInterface, + LoseInterfaceNavigate, HordeInterfaceNavigate, + NevagateGameOverInterface { + private int day; + private int food; + private int water; + private int people; + private int weapon; + private int action; + + private final JLabel dayLabel; + private final JLabel foodLabel; + private final JLabel waterLabel; + private final JLabel peopleLabel; + private final JLabel weaponLabel; + private final JLabel actionAvailableLabel; + + private final JTextArea mapPanel; + private final JTextArea infoBox = new JTextArea(); + private boolean isMapVisible = true; + + private FetchController fetchController; + private BroadcastController broadcastController; + private PlaceDescriptionController placeDescriptionController; + private DailyGatherController dailyGatherController; + private DailyMoveController dailyMoveController; + private EventDecideController eventDecideController; + private NevagateEventController nevagateEventController; + private NewdayController newdayController; + private MinimapController minimapController; + private LoseController loseController; + private HordeController hordeController; + private NevagateGameOverController nevagateGameOverController; + + private final PropertyChangeSupport propertyChangeSupport; + private final String changeline = new String("\n\n"); + + public GameView() { + super("Game"); + + // Initialize PropertyChangeSupport + this.propertyChangeSupport = new PropertyChangeSupport(this); + + // Initialize UI components + final Container container = getContentPane(); + final SpringLayout layout = new SpringLayout(); + container.setLayout(layout); + + // Initialize labels for resources + dayLabel = new JLabel("Day: " + day); + dayLabel.setFont(new Font("Serif", Font.BOLD, Constants.TWENTY)); + foodLabel = new JLabel("Food: " + food); + waterLabel = new JLabel("Water: " + water); + peopleLabel = new JLabel("People: " + people); + weaponLabel = new JLabel("Weapon: " + weapon); + actionAvailableLabel = new JLabel("Action Available: " + action); + + containerContent(container); + + // MiniMap Panel + mapPanel = new JTextArea("Mini Map\nabcdefghijklm\nnuvwxyz"); + mapPanelSetteings(); + container.add(mapPanel); + + // Wrap infoBox in a JScrollPane (top-left position, smaller width) + final JScrollPane infoScrollPane = new JScrollPane(infoBox); + infoScrollPaneSettings(infoScrollPane, container, layout); + + // Buttons + final JButton broadcastButton = new JButton("Broadcast"); + final JButton gatherButton = new JButton("Gather"); + final JButton upButton = new JButton("Up"); + final JButton downButton = new JButton("Down"); + final JButton leftButton = new JButton("Left"); + final JButton rightButton = new JButton("Right"); + final JButton eventButton = new JButton("Event"); + final JButton nextDayButton = new JButton("Next Day"); + final JButton infoButton = new JButton("Log"); + + containerContent(container, broadcastButton, gatherButton, upButton, downButton, leftButton, + rightButton, eventButton, nextDayButton, infoButton); + + broadcastButtonListener(broadcastButton); + + gatherButtonListener(gatherButton); + + upButtonListener(upButton); + + downButtonListener(downButton); + + leftButtonListener(leftButton); + + rightButtonListener(rightButton); + + eventButtonListener(eventButton); + + nextdayButtonListener(nextDayButton); + + // Add ActionListeners + infoButtonListener(infoButton, nextDayButton); + + // Layout Constraints + applyLayoutConstraints(layout, container, dayLabel, foodLabel, waterLabel, peopleLabel, weaponLabel, + actionAvailableLabel, mapPanel, infoBox, broadcastButton, gatherButton, upButton, downButton, + leftButton, rightButton, eventButton, nextDayButton, infoButton); + + // Set frame properties + frameSettings(); + + // Register this as a listener for property changes + propertyChangeSupport.addPropertyChangeListener(this); + } + + private void frameSettings() { + setSize(Constants.SIX_HUNDRED, Constants.FOUR_HUNDRED); + setDefaultCloseOperation(EXIT_ON_CLOSE); + setResizable(false); + } + + private void infoButtonListener(JButton infoButton, JButton nextDayButton) { + infoButton.addActionListener(event -> toggleInfoBox()); + nextDayButton.addActionListener(event -> { + if (fetchController != null) { + fetchController.execute(); + } + }); + } + + private void nextdayButtonListener(JButton nextDayButton) { + nextDayButton.addActionListener(event -> { + newdayController.execute(); + fetchController.execute(); + }); + } + + private void eventButtonListener(JButton eventButton) { + eventButton.addActionListener(event -> { + nevagateEventController.execute(); + }); + } + + private void rightButtonListener(JButton rightButton) { + rightButton.addActionListener(event -> { + dailyMoveController.execute("right"); + fetchController.execute(); + minimapController.execute(); + }); + } + + private void leftButtonListener(JButton leftButton) { + leftButton.addActionListener(event -> { + dailyMoveController.execute("left"); + fetchController.execute(); + minimapController.execute(); + }); + } + + private void downButtonListener(JButton downButton) { + downButton.addActionListener(event -> { + dailyMoveController.execute("down"); + fetchController.execute(); + minimapController.execute(); + }); + } + + private void upButtonListener(JButton upButton) { + upButton.addActionListener(event -> { + dailyMoveController.execute("up"); + fetchController.execute(); + minimapController.execute(); + }); + } + + private void gatherButtonListener(JButton gatherButton) { + gatherButton.addActionListener(event -> { + dailyGatherController.execute(); + fetchController.execute(); + }); + } + + private void broadcastButtonListener(JButton broadcastButton) { + broadcastButton.addActionListener(event -> { + broadcastController.execute(); + fetchController.execute(); + }); + } + + private static void containerContent(Container container, JButton broadcastButton, JButton gatherButton, + JButton upButton, JButton downButton, JButton leftButton, JButton rightButton, + JButton eventButton, JButton nextDayButton, JButton infoButton) { + container.add(broadcastButton); + container.add(gatherButton); + container.add(upButton); + container.add(downButton); + container.add(leftButton); + container.add(rightButton); + container.add(eventButton); + container.add(nextDayButton); + container.add(infoButton); + } + + private void containerContent(Container container) { + container.add(dayLabel); + container.add(foodLabel); + container.add(waterLabel); + container.add(peopleLabel); + container.add(weaponLabel); + container.add(actionAvailableLabel); + } + + private void infoScrollPaneSettings(JScrollPane infoScrollPane, Container container, SpringLayout layout) { + infoScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + infoScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + // Adjusted smaller width and fixed height + infoScrollPane.setPreferredSize(new Dimension(Constants.TWO_HUNDRED, Constants.TWO_HUNDRED)); + container.add(infoScrollPane); + infoBox.setLineWrap(true); + infoBox.setWrapStyleWord(true); + infoScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + infoScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + + // Update Layout Constraints for infoScrollPane (top-left, same as minimap) + layout.putConstraint(SpringLayout.EAST, infoScrollPane, -Constants.TWENTY, SpringLayout.EAST, container); + layout.putConstraint(SpringLayout.NORTH, infoScrollPane, Constants.TWENTY, SpringLayout.NORTH, container); + } + + private void mapPanelSetteings() { + mapPanel.setEditable(false); + mapPanel.setLineWrap(true); + mapPanel.setWrapStyleWord(true); + mapPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK)); + mapPanel.setBackground(Color.LIGHT_GRAY); + mapPanel.setPreferredSize(new Dimension(Constants.TWO_HUNDRED, Constants.TWO_HUNDRED)); + } + + /** + * Sets the controllers for managing various aspects of the application. + * + *

This method initializes the required controllers by associating the provided + * controller instances with the corresponding fields in this class. Each controller + * is responsible for handling specific functionality within the application.

+ * + * @param inifetchController the controller responsible for fetching data + * @param inibroadcastController the controller responsible for broadcasting updates + * @param iniplaceDescriptionController the controller responsible for handling place descriptions + * @param inidailyGatherController the controller for managing daily gathering operations + * @param inidailyMoveController the controller for managing daily movement operations + * @param ininevagateEventController the controller for navigating events + * @param inieventDecideController the controller for handling event decision logic + * @param ininewdayController the controller responsible for handling new day transitions + * @param iniminimapController the controller for managing the minimap + * @param iniloseController the controller responsible for handling game loss conditions + * @param inihordeController the controller for managing hordes in the application + * @param ininevagateGameOverController the controller for managing the game-over navigation process + */ + public void setController(FetchController inifetchController, BroadcastController inibroadcastController, + PlaceDescriptionController iniplaceDescriptionController, + DailyGatherController inidailyGatherController, DailyMoveController inidailyMoveController, + NevagateEventController ininevagateEventController, + EventDecideController inieventDecideController, NewdayController ininewdayController, + MinimapController iniminimapController, + LoseController iniloseController, HordeController inihordeController, + NevagateGameOverController ininevagateGameOverController) { + this.fetchController = inifetchController; + this.broadcastController = inibroadcastController; + this.placeDescriptionController = iniplaceDescriptionController; + this.dailyGatherController = inidailyGatherController; + this.dailyMoveController = inidailyMoveController; + this.nevagateEventController = ininevagateEventController; + this.eventDecideController = inieventDecideController; + this.newdayController = ininewdayController; + this.minimapController = iniminimapController; + this.loseController = iniloseController; + this.hordeController = inihordeController; + this.nevagateGameOverController = ininevagateGameOverController; + } + + /** + * Renders the UI by executing controllers and making the panel visible. + */ + public void render() { + placeDescriptionController.execute(); + fetchController.execute(); + minimapController.execute(); + loseController.execute(); + setVisible(true); + } + + /** + * Hides the UI by making the panel invisible. + */ + public void disrender() { + setVisible(false); + } + + /** + * Toggles the visibility of the map and information box. + * If the map is currently visible, it hides the map and shows the info box, and vice versa. + */ + private void toggleInfoBox() { + isMapVisible = !isMapVisible; + mapPanel.setVisible(isMapVisible); + infoBox.setVisible(!isMapVisible); + } + + /** + * Sets the current day and notifies listeners of the property change. + * + * @param day the new day value + */ + public void setDay(int day) { + final int oldDay = this.day; + this.day = day; + propertyChangeSupport.firePropertyChange("day", oldDay, day); + } + + /** + * Sets the current food level and notifies listeners of the property change. + * + * @param food the new food value + */ + public void setFood(int food) { + final int oldFood = this.food; + this.food = food; + propertyChangeSupport.firePropertyChange("food", oldFood, food); + } + + /** + * Sets the current water level and notifies listeners of the property change. + * + * @param water the new water value + */ + public void setWater(int water) { + final int oldWater = this.water; + this.water = water; + propertyChangeSupport.firePropertyChange("water", oldWater, water); + } + + /** + * Sets the current population count and notifies listeners of the property change. + * + * @param people the new people count + */ + public void setPeople(int people) { + final int oldPeople = this.people; + this.people = people; + propertyChangeSupport.firePropertyChange("people", oldPeople, people); + } + + /** + * Sets the current weapon count and notifies listeners of the property change. + * + * @param weapon the new weapon value + */ + public void setWeapon(int weapon) { + final int oldWeapon = this.weapon; + this.weapon = weapon; + propertyChangeSupport.firePropertyChange("weapon", oldWeapon, weapon); + } + + /** + * Sets the current action count and notifies listeners of the property change. + * + * @param action the new action value + */ + public void setAction(int action) { + final int oldAction = this.action; + this.action = action; + propertyChangeSupport.firePropertyChange("action", oldAction, action); + } + + private void applyLayoutConstraints(SpringLayout layout, Container container, JLabel dayLabel, + JLabel foodLabel, JLabel waterLabel, JLabel peopleLabel, + JLabel weaponLabel, JLabel actionAvailableLabel, JTextArea mapPanel, + JTextArea infoBox, JButton broadcastButton, JButton gatherButton, + JButton upButton, JButton downButton, JButton leftButton, + JButton rightButton, JButton eventButton, JButton nextDayButton, + JButton infoButton) { + // Position resource labels + layout.putConstraint(SpringLayout.WEST, dayLabel, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.NORTH, dayLabel, Constants.TWENTY, SpringLayout.NORTH, container); + + layout.putConstraint(SpringLayout.WEST, foodLabel, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.NORTH, foodLabel, Constants.TWENTY, SpringLayout.SOUTH, dayLabel); + + layout.putConstraint(SpringLayout.WEST, waterLabel, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.NORTH, waterLabel, Constants.TWENTY, SpringLayout.SOUTH, foodLabel); + + layout.putConstraint(SpringLayout.WEST, peopleLabel, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.NORTH, peopleLabel, Constants.TWENTY, SpringLayout.SOUTH, waterLabel); + + layout.putConstraint(SpringLayout.WEST, weaponLabel, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.NORTH, weaponLabel, Constants.TWENTY, SpringLayout.SOUTH, peopleLabel); + + layout.putConstraint(SpringLayout.WEST, actionAvailableLabel, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.NORTH, actionAvailableLabel, Constants.TWENTY, SpringLayout.SOUTH, + weaponLabel); + + // Position minimap + layout.putConstraint(SpringLayout.EAST, mapPanel, -Constants.TWENTY, SpringLayout.EAST, container); + layout.putConstraint(SpringLayout.NORTH, mapPanel, Constants.TWENTY, SpringLayout.NORTH, container); + + // Position info box + layout.putConstraint(SpringLayout.EAST, infoBox, Constants.TWENTY, SpringLayout.EAST, container); + layout.putConstraint(SpringLayout.NORTH, infoBox, Constants.TWENTY, SpringLayout.NORTH, container); + + // Position buttons + layout.putConstraint(SpringLayout.WEST, broadcastButton, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.NORTH, broadcastButton, Constants.TWENTY, SpringLayout.SOUTH, + actionAvailableLabel); + + layout.putConstraint(SpringLayout.WEST, gatherButton, Constants.TWENTY, SpringLayout.EAST, broadcastButton); + layout.putConstraint(SpringLayout.NORTH, gatherButton, 0, SpringLayout.NORTH, broadcastButton); + + layout.putConstraint(SpringLayout.WEST, upButton, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.NORTH, upButton, Constants.TWENTY, SpringLayout.SOUTH, broadcastButton); + + layout.putConstraint(SpringLayout.WEST, downButton, Constants.TWENTY, SpringLayout.EAST, upButton); + layout.putConstraint(SpringLayout.NORTH, downButton, 0, SpringLayout.NORTH, upButton); + + layout.putConstraint(SpringLayout.WEST, leftButton, Constants.TWENTY, SpringLayout.EAST, downButton); + layout.putConstraint(SpringLayout.NORTH, leftButton, 0, SpringLayout.NORTH, upButton); + + layout.putConstraint(SpringLayout.WEST, rightButton, Constants.TWENTY, SpringLayout.EAST, leftButton); + layout.putConstraint(SpringLayout.NORTH, rightButton, 0, SpringLayout.NORTH, upButton); + + layout.putConstraint(SpringLayout.WEST, eventButton, Constants.TWENTY, SpringLayout.EAST, gatherButton); + layout.putConstraint(SpringLayout.NORTH, eventButton, 0, SpringLayout.NORTH, broadcastButton); + + layout.putConstraint(SpringLayout.WEST, nextDayButton, Constants.TWENTY, SpringLayout.EAST, eventButton); + layout.putConstraint(SpringLayout.NORTH, nextDayButton, 0, SpringLayout.NORTH, broadcastButton); + + layout.putConstraint(SpringLayout.WEST, infoButton, Constants.TWENTY, SpringLayout.EAST, rightButton); + layout.putConstraint(SpringLayout.NORTH, infoButton, 0, SpringLayout.NORTH, upButton); + } + + @Override + public void updateUiMinimap(ArrayList> grid) { + // Validate input + if (grid == null || grid.isEmpty() || grid.get(0).isEmpty()) { + mapPanel.setText("Invalid map data."); + return; + } + + final int rows = grid.size(); + final int cols = grid.get(0).size(); + + // Find the center and set a marker (e.g., @) for the player's position + final int centerRow = rows / 2; + final int centerCol = cols / 2; + + final StringBuilder mapBuilder = new StringBuilder(); + + for (int r = 0; r < rows; r++) { + for (int c = 0; c < cols; c++) { + if (r == centerRow && c == centerCol) { + mapBuilder.append("@ "); + } + else { + mapBuilder.append(grid.get(r).get(c)).append(" "); + } + } + mapBuilder.append("\n"); + } + + // Set text to mapPanel with fixed font and centered scroll + mapPanel.setFont(new Font("Monospaced", Font.PLAIN, Constants.MINIMAPSIZE)); + mapPanel.setText(mapBuilder.toString()); + mapPanel.setCaretPosition(0); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + final String propertyName = evt.getPropertyName(); + + switch (propertyName) { + case "day": + dayLabel.setText("Day: " + evt.getNewValue()); + break; + case "food": + foodLabel.setText("Food: " + evt.getNewValue()); + break; + case "water": + waterLabel.setText("Water: " + evt.getNewValue()); + break; + case "people": + peopleLabel.setText("People: " + evt.getNewValue()); + break; + case "weapon": + weaponLabel.setText("Weapon: " + evt.getNewValue()); + break; + case "action": + actionAvailableLabel.setText("Action Available: " + evt.getNewValue()); + break; + default: + // Handle unknown properties if needed + break; + } + } + + @Override + public void updateUiResource(int inifood, int iniwater, int inipeople, int iniweapon, int iniday, + int iniactionpoint) { + loseController.execute(); + // check if player lose on update. + setFood(inifood); + setWater(iniwater); + setPeople(inipeople); + setWeapon(iniweapon); + setDay(iniday); + setAction(iniactionpoint); + } + + @Override + public void updateUiBroadcast(String message) { + if (infoBox != null) { + infoBox.append(message + changeline); + infoBox.setCaretPosition(infoBox.getDocument().getLength()); + } + } + + @Override + public void failureBroadcast(String errorMessage) { + JOptionPane.showMessageDialog( + this, + errorMessage, + "Unable to Broadcast", + JOptionPane.ERROR_MESSAGE + ); + } + + @Override + public void updateUiGather(String message) { + if (infoBox != null) { + infoBox.append(message + changeline); + infoBox.setCaretPosition(infoBox.getDocument().getLength()); + } + } + + @Override + public void failureGather(String message) { + JOptionPane.showMessageDialog( + this, + message, + "Unable to Gather", + JOptionPane.ERROR_MESSAGE + ); + } + + @Override + public void updateUiMove(String message) { + if (infoBox != null) { + infoBox.append(message + changeline); + infoBox.setCaretPosition(infoBox.getDocument().getLength()); + } + } + + @Override + public void failureMove(String errormessage) { + JOptionPane.showMessageDialog( + this, + errormessage, + "Unable to Move", + JOptionPane.ERROR_MESSAGE + ); + } + + @Override + public void updateUiPlaceDescription(String placeDescription) { + if (infoBox != null) { + infoBox.append(placeDescription + changeline); + infoBox.setCaretPosition(infoBox.getDocument().getLength()); + } + } + + @Override + public void failurePlaceDescription(String failmessage) { + JOptionPane.showMessageDialog( + this, + failmessage, + "Unable to Get Place Description", + JOptionPane.ERROR_MESSAGE + ); + } + + @Override + public void updateUiEventDecide(ArrayList eventNames) { + if (infoBox != null) { + if (eventNames.isEmpty()) { + // No events + infoBox.append("No events happened today.\n\n"); + } + else { + // Display the events + infoBox.append("Today's events:\n"); + for (String event : eventNames) { + infoBox.append("- " + event + "\n"); + } + } + infoBox.setCaretPosition(infoBox.getDocument().getLength()); + } + } + + @Override + public void failureEventDecide(String errorMessage) { + JOptionPane.showMessageDialog( + this, + errorMessage, + "Unable to decide event.", + JOptionPane.ERROR_MESSAGE + ); + } + + @Override + public void failureNevagateEvent(String message) { + JOptionPane.showMessageDialog( + this, + message, + "Unable to go to event page!", + JOptionPane.ERROR_MESSAGE + ); + } + + @Override + public void updateUiNewday(String message) { + // only message is needed. + if (infoBox != null) { + infoBox.append(message + "\n\n"); + System.out.println("newday message prointed"); + infoBox.setCaretPosition(infoBox.getDocument().getLength()); + } + eventDecideController.execute(); + } + + @Override + public void failureNewday(String message) { + JOptionPane.showMessageDialog( + this, + message, + "Unable to go to next day!", + JOptionPane.ERROR_MESSAGE + ); + } + + @Override + public void navigateGameOver(NavigationManager navigationManager) { + navigationManager.showGameOverView(); + } + + @Override + public void NavigateHordeGameOver(NavigationManager manager) { + manager.showGameOverView(); + } +} diff --git a/src/main/java/view/InformationView.java b/src/main/java/view/InformationView.java new file mode 100644 index 000000000..f17b41b4c --- /dev/null +++ b/src/main/java/view/InformationView.java @@ -0,0 +1,99 @@ +package view; + +import java.awt.Color; +import java.awt.Container; +import java.awt.Font; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SpringLayout; + +/** + * Information view. + */ +public class InformationView extends JFrame { + @SuppressWarnings({"checkstyle:LambdaParameterName", "checkstyle:SuppressWarnings"}) + public InformationView(String information) { + super("Information"); + + // Set up the container + final Container container = getContentPane(); + final SpringLayout layout = new SpringLayout(); + container.setLayout(layout); + + // Create JTextArea to display information + final JTextArea infoArea = new JTextArea(information); + infoArea.setEditable(false); + infoArea.setLineWrap(true); + infoArea.setWrapStyleWord(true); + infoArea.setBackground(Color.LIGHT_GRAY); + infoArea.setFont(new Font("Serif", Font.PLAIN, Constants.TWENTY)); + infoArea.setBorder(BorderFactory.createLineBorder(Color.BLACK)); + + // Add a scroll pane for JTextArea + final JScrollPane scrollPane = new JScrollPane(infoArea); + container.add(scrollPane); + + // Create the back button + final JButton backButton = new JButton("Back"); + backButton.setFont(new Font("Arial", Font.PLAIN, Constants.TWENTY)); + container.add(backButton); + + // Layout constraints + layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, scrollPane, 0, SpringLayout.HORIZONTAL_CENTER, container); + layout.putConstraint(SpringLayout.NORTH, scrollPane, Constants.TWENTY, SpringLayout.NORTH, container); + layout.putConstraint(SpringLayout.WEST, scrollPane, Constants.TWENTY, SpringLayout.WEST, container); + layout.putConstraint(SpringLayout.EAST, scrollPane, -Constants.TWENTY, SpringLayout.EAST, container); + layout.putConstraint(SpringLayout.SOUTH, scrollPane, -Constants.SIXTY, SpringLayout.SOUTH, container); + + layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, backButton, 0, SpringLayout.HORIZONTAL_CENTER, container); + layout.putConstraint(SpringLayout.NORTH, backButton, Constants.TWENTY, SpringLayout.SOUTH, scrollPane); + + // Add action listener to the back button + backButton.addActionListener(e -> { + dispose(); + new GameView(); + }); + + // Set window properties + setSize(Constants.SIX_HUNDRED, Constants.FOUR_HUNDRED); + setDefaultCloseOperation(EXIT_ON_CLOSE); + setResizable(false); + setVisible(false); + } + + /** + * Renders the component by initializing required events, setting its size, + * and making it visible. + * + *

This method triggers the execution of the eventInitializerController + * and adjusts the component's size to a predefined value. Finally, it makes + * the component visible to the user.

+ */ + public void render() { + setSize(Constants.FOUR_HUNDRED, Constants.SIX_HUNDRED); + setVisible(true); + } + + /** + * Disables the rendering of the component by maintaining its size but + * making it invisible. + * + *

This method adjusts the component's size to a predefined value but + * ensures that it is not visible to the user.

+ */ + public void disrender() { + setSize(Constants.FOUR_HUNDRED, Constants.FOUR_HUNDRED); + setVisible(false); + } + + public static void main(String[] args) { + // Sample information to display + final String sampleInformation = "This is the system-generated information. " + + "It can include logs, updates, or any other details about the backend process."; + new InformationView(sampleInformation); + } +} diff --git a/src/main/java/view/LoginView.java b/src/main/java/view/LoginView.java new file mode 100644 index 000000000..76ab509bf --- /dev/null +++ b/src/main/java/view/LoginView.java @@ -0,0 +1,200 @@ +package view; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.io.IOException; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPasswordField; +import javax.swing.JTextField; +import javax.swing.Spring; +import javax.swing.SpringLayout; + +import app.JsonApplication; +import interface_adapters.NavigationManagerJson; +import interface_adapters.login.LoginController; +import interface_adapters.login.LoginInterface; + +/** + * LoginView handles the UI for user login and integrates with the LoginApplication. + */ +public class LoginView extends JFrame implements LoginInterface { + private final JLabel nameLabel = new JLabel("60 Days to Survive", JLabel.CENTER); + private final SpringLayout springLayout = new SpringLayout(); + private final JPanel centerPanel = new JPanel(springLayout); + private final JLabel userNameLabel = new JLabel("Username:"); + private final JTextField userText = new JTextField(); + private final JLabel passwordLabel = new JLabel("Password:"); + private final JPasswordField passwordText = new JPasswordField(); + private final JButton loginButton = new JButton("Log in"); + private final JButton registerButton = new JButton("Sign up"); + + private LoginController loginController; + private NavigationManagerJson navigationManager; + + /** + * Constructs the LoginView with the provided LoginController. + * + * @throws IOException If there is an error initializing the login application. + */ + public LoginView() throws IOException { + super("Login"); + + final Container contentPane = getContentPane(); + final String fontname = new String("Arial"); + nameLabel.setFont(new Font("Impact", Font.BOLD, Constants.FIFTY)); + userNameLabel.setFont(new Font(fontname, Font.BOLD, Constants.FIFTEEN)); + passwordLabel.setFont(new Font(fontname, Font.BOLD, Constants.FIFTEEN)); + loginButton.setFont(new Font(fontname, Font.PLAIN, Constants.TWENTY)); + loginButton.setBackground(Constants.THEME_COLOR); + loginButton.setForeground(Color.WHITE); + registerButton.setFont(new Font(fontname, Font.PLAIN, Constants.TWENTY)); + registerButton.setBackground(Color.WHITE); + registerButton.setForeground(Constants.THEME_COLOR); + + userText.setPreferredSize(new Dimension(Constants.TWO_HUNDRED, Constants.THIRTY)); + passwordText.setPreferredSize(new Dimension(Constants.TWO_HUNDRED, Constants.THIRTY)); + + containerContent(); + + contentPane.add(nameLabel, BorderLayout.NORTH); + contentPane.add(centerPanel, BorderLayout.CENTER); + + // spring layout + final Spring titleLabelWidth = Spring.width(userNameLabel); + final Spring titleTextWidth = Spring.width(userText); + final Spring spaceWidth = Spring.constant(20); + final Spring childWidth = Spring.sum(Spring.sum(titleLabelWidth, titleTextWidth), spaceWidth); + final int offsetX = (childWidth.getValue() + 40) / 2; + layout(offsetX); + + loginButton.addActionListener(event -> { + final String username = userText.getText(); + final String password = new String(passwordText.getPassword()); + userText.setText(""); + passwordText.setText(""); + loginController.handleLogin(username, password); + }); + + registerButton.addActionListener(event -> { + if (navigationManager != null) { + // Navigate to SignUpView + navigationManager.showSignUpView(); + } + }); + setSize(Constants.SIX_HUNDRED, Constants.FOUR_HUNDRED); + setDefaultCloseOperation(EXIT_ON_CLOSE); + setResizable(false); + setLocation(Constants.FIVE_HUNDRED, Constants.THREE_HUNDRED); + } + + private void containerContent() { + centerPanel.add(userNameLabel); + centerPanel.add(userText); + centerPanel.add(passwordLabel); + centerPanel.add(passwordText); + centerPanel.add(loginButton); + centerPanel.add(registerButton); + } + + private void layout(int offsetX) { + // set userLable location + springLayout.putConstraint(SpringLayout.WEST, userNameLabel, -offsetX, SpringLayout.HEIGHT, centerPanel); + springLayout.putConstraint(SpringLayout.NORTH, userNameLabel, Constants.SIXTY, SpringLayout.NORTH, + centerPanel); + // set userText location + springLayout.putConstraint(SpringLayout.WEST, userText, Constants.TEN, SpringLayout.EAST, userNameLabel); + springLayout.putConstraint(SpringLayout.NORTH, userText, -Constants.FIVE, SpringLayout.NORTH, userNameLabel); + // set passwordLabel location + springLayout.putConstraint(SpringLayout.EAST, passwordLabel, 0, SpringLayout.EAST, userNameLabel); + springLayout.putConstraint(SpringLayout.NORTH, passwordLabel, Constants.TWENTY, SpringLayout.SOUTH, + userNameLabel); + // set passwordText location + springLayout.putConstraint(SpringLayout.WEST, passwordText, Constants.TEN, SpringLayout.EAST, passwordLabel); + springLayout.putConstraint(SpringLayout.NORTH, passwordText, -Constants.FIVE, SpringLayout.NORTH, + passwordLabel); + // set loginButton location + springLayout.putConstraint(SpringLayout.WEST, loginButton, Constants.FIFTY, SpringLayout.WEST, passwordLabel); + springLayout.putConstraint(SpringLayout.NORTH, loginButton, Constants.FORTY, + SpringLayout.SOUTH, passwordLabel); + // set registerButton + springLayout.putConstraint(SpringLayout.WEST, registerButton, Constants.FIFTY, SpringLayout.EAST, loginButton); + springLayout.putConstraint(SpringLayout.NORTH, registerButton, 0, SpringLayout.NORTH, loginButton); + + } + + /** + * Sets the LoginController for this view. + * + * @param loginController The LoginController instance. + */ + public void setLoginController(LoginController loginController) { + this.loginController = loginController; + } + + /** + * Sets the NavigationManager for this view. + * + * @param navigationManager The NavigationManager instance. + */ + public void setNavigationManager(NavigationManagerJson navigationManager) { + this.navigationManager = navigationManager; + } + + /** + * Displays the result of a login attempt. + * + * @param message A message indicating the result of the login attempt. + */ + @Override + public void displayLoginResult(String message) { + JOptionPane.showMessageDialog(this, message, "Login Result", JOptionPane.INFORMATION_MESSAGE); + + if ("Login successful!".equals(message)) { + if (navigationManager != null) { + navigationManager.showMainView(); + } + else { + JOptionPane.showMessageDialog(this, + "Cannot navigate to Main View.", + "Error", JOptionPane.ERROR_MESSAGE); + } + } + } + + /** + * Renders the component by making it visible to the user. + * + *

This method sets the visibility of the component to {@code true}, + * ensuring it is displayed on the screen.

+ */ + public void render() { + setVisible(true); + } + + /** + * Hides the component by making it invisible to the user. + * + *

This method sets the visibility of the component to {@code false}, + * ensuring it is not displayed on the screen.

+ */ + public void disrender() { + setVisible(false); + } + + public static void main(String[] args) throws IOException { + try { + new JsonApplication("PlayerFile", "PlayerFile", "RankingFile"); + } + catch (IOException event) { + event.printStackTrace(); + } + } +} diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java new file mode 100644 index 000000000..854bb22ea --- /dev/null +++ b/src/main/java/view/MainView.java @@ -0,0 +1,209 @@ +package view; + +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.io.IOException; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.SpringLayout; + +import app.JsonApplication; +import app.RestartGameController; +import interface_adapters.NavigationManagerJson; +import interface_adapters.nevagateallowcatepage.NevagateAllowcateController; + +/** + * Main view. + */ + +public class MainView extends JFrame { + private JButton newGameButton = new JButton("New Game"); + private JButton rankingButton = new JButton("Ranking List"); + private JButton quitButton = new JButton("Quit"); + private JButton logoutButton = new JButton("Log Out"); + + private NevagateAllowcateController nevagateAllowcateController; + private NavigationManagerJson navigationManager; + private RestartGameController restartGameController; + + public MainView() { + // Set layout and container + final Container container = getContentPane(); + final SpringLayout layout = new SpringLayout(); + container.setLayout(layout); + + // Title + final JLabel titleLabel = new JLabel("Main Menu"); + final String fontname = new String("Arial"); + titleLabel.setFont(new Font(fontname, Font.BOLD, Constants.THIRTY)); + container.add(titleLabel); + + // Set button fonts + buttonSetting(fontname); + + // Add buttons to the container + container.add(newGameButton); + container.add(rankingButton); + container.add(quitButton); + container.add(logoutButton); + + // Layout constraints + layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, titleLabel, 0, SpringLayout.HORIZONTAL_CENTER, + container); + layout.putConstraint(SpringLayout.NORTH, titleLabel, Constants.THIRTY, SpringLayout.NORTH, container); + + layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, newGameButton, 0, SpringLayout.HORIZONTAL_CENTER, + container); + layout.putConstraint(SpringLayout.NORTH, newGameButton, Constants.FORTY, SpringLayout.SOUTH, titleLabel); + + layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, rankingButton, 0, SpringLayout.HORIZONTAL_CENTER, + container); + layout.putConstraint(SpringLayout.NORTH, rankingButton, Constants.TEN, SpringLayout.SOUTH, newGameButton); + + layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, logoutButton, 0, SpringLayout.HORIZONTAL_CENTER, + container); + layout.putConstraint(SpringLayout.NORTH, logoutButton, Constants.TEN, SpringLayout.SOUTH, rankingButton); + + layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, quitButton, 0, SpringLayout.HORIZONTAL_CENTER, + container); + layout.putConstraint(SpringLayout.NORTH, quitButton, Constants.TEN, SpringLayout.SOUTH, logoutButton); + + // Add listeners for buttons + addListeners(); + + // Set window properties (moved to render()) + setSize(Constants.SIX_HUNDRED, Constants.FOUR_HUNDRED); + setDefaultCloseOperation(EXIT_ON_CLOSE); + setResizable(false); + setLocation(Constants.FIVE_HUNDRED, Constants.THREE_HUNDRED); + } + + private void buttonSetting(String fontname) { + newGameButton.setFont(new Font(fontname, Font.BOLD, Constants.TWENTY)); + rankingButton.setFont(new Font(fontname, Font.PLAIN, Constants.TWENTY)); + quitButton.setFont(new Font(fontname, Font.PLAIN, Constants.TWENTY)); + logoutButton.setFont(new Font(fontname, Font.PLAIN, Constants.TWENTY)); + + newGameButton.setPreferredSize(new Dimension(Constants.TWO_HUNDRED, Constants.FIFTY)); + rankingButton.setPreferredSize(new Dimension(Constants.TWO_HUNDRED, Constants.FIFTY)); + quitButton.setPreferredSize(new Dimension(Constants.TWO_HUNDRED, Constants.FORTY)); + logoutButton.setPreferredSize(new Dimension(Constants.TWO_HUNDRED, Constants.FIFTY)); + + newGameButton.setBackground(Constants.THEME_COLOR); + rankingButton.setBackground(Color.WHITE); + quitButton.setBackground(Color.WHITE); + logoutButton.setBackground(Color.WHITE); + + newGameButton.setForeground(Color.WHITE); + rankingButton.setForeground(Constants.THEME_COLOR); + quitButton.setForeground(Constants.THEME_COLOR); + logoutButton.setForeground(Constants.THEME_COLOR); + } + + /** + * Sets the {@code NevigateAllowcateController} for this instance. + * + *

This method associates a {@code NevigateAllowcateController} with the current + * instance of the {@code MainView} and logs the instance's identity hash code for + * debugging purposes.

+ * + * @param nevagateAllowcateController the {@code NevigateAllowcateController} to be set + */ + public void setNevagateAllowcateController(NevagateAllowcateController nevagateAllowcateController) { + System.out.println("MainView instance in setNevagateAllowcateController: " + System.identityHashCode(this)); + this.nevagateAllowcateController = nevagateAllowcateController; + } + + public void setRestartGameController(RestartGameController restartGameController) { + this.restartGameController = restartGameController; + } + + // Add ActionListener to buttons + private void addListeners() { + // Switch to GameView when "New Game" is clicked + final String error = new String("Error"); + newGameButton.addActionListener(event -> { + restartGameController.resetGame(); + if (nevagateAllowcateController != null) { + nevagateAllowcateController.execute(); + } + else { + JOptionPane.showMessageDialog(this, "Navigation controller not initialized.", + error, JOptionPane.ERROR_MESSAGE); + } + }); + + // Switch to RankView when "Ranking" is clicked + rankingButton.addActionListener(event -> { + if (navigationManager != null) { + navigationManager.showRankingView(); + } + else { + JOptionPane.showMessageDialog(this, + "Navigation Manager is not initialized. Cannot navigate to Ranking View.", + error, JOptionPane.ERROR_MESSAGE); + } + }); + + // Exit the game when "Quit" is clicked + quitButton.addActionListener(event -> { + System.exit(0); + }); + + // Switch to LoginView when "Logout" is clicked + logoutButton.addActionListener(event -> { + if (navigationManager != null) { + navigationManager.showLoginView(); + } + else { + JOptionPane.showMessageDialog(this, + "Error navigating to LoginView.", + error, JOptionPane.ERROR_MESSAGE); + } + }); + } + + /** + * Sets the NavigationManager for this view. + * + * @param navigationManager The NavigationManager instance. + */ + public void setNavigationManager(NavigationManagerJson navigationManager) { + this.navigationManager = navigationManager; + } + + // Add render method + /** + * Renders the component by making it visible to the user. + * + *

This method sets the visibility of the component to {@code true}, + * ensuring it is displayed on the screen.

+ */ + public void render() { + setVisible(true); + } + + /** + * Hides the component by making it invisible to the user. + * + *

This method sets the visibility of the component to {@code false}, + * ensuring it is not displayed on the screen.

+ */ + public void disrender() { + setVisible(false); + } + + public static void main(String[] args) { + try { + new JsonApplication("PlayerFile", "PlayerFile", "RankingFile"); + } + catch (IOException event) { + event.printStackTrace(); + } + } +} diff --git a/src/main/java/view/NoteView.java b/src/main/java/view/NoteView.java deleted file mode 100644 index 331d76493..000000000 --- a/src/main/java/view/NoteView.java +++ /dev/null @@ -1,95 +0,0 @@ -package view; - -import java.awt.Component; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; - -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JTextArea; - -import interface_adapter.note.NoteController; -import interface_adapter.note.NoteState; -import interface_adapter.note.NoteViewModel; - -/** - * The View for when the user is viewing a note in the program. - */ -public class NoteView extends JPanel implements ActionListener, PropertyChangeListener { - - private final NoteViewModel noteViewModel; - - private final JLabel noteName = new JLabel("note for jonathan_calver2"); - private final JTextArea noteInputField = new JTextArea(); - - private final JButton saveButton = new JButton("Save"); - private final JButton refreshButton = new JButton("Refresh"); - private NoteController noteController; - - public NoteView(NoteViewModel noteViewModel) { - - noteName.setAlignmentX(Component.CENTER_ALIGNMENT); - this.noteViewModel = noteViewModel; - this.noteViewModel.addPropertyChangeListener(this); - - final JPanel buttons = new JPanel(); - buttons.add(saveButton); - buttons.add(refreshButton); - - saveButton.addActionListener( - evt -> { - if (evt.getSource().equals(saveButton)) { - noteController.execute(noteInputField.getText()); - - } - } - ); - - refreshButton.addActionListener( - evt -> { - if (evt.getSource().equals(refreshButton)) { - noteController.execute(null); - - } - } - ); - - this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - - this.add(noteName); - this.add(noteInputField); - this.add(buttons); - } - - /** - * React to a button click that results in evt. - * @param evt the ActionEvent to react to - */ - public void actionPerformed(ActionEvent evt) { - System.out.println("Click " + evt.getActionCommand()); - } - - @Override - public void propertyChange(PropertyChangeEvent evt) { - final NoteState state = (NoteState) evt.getNewValue(); - setFields(state); - if (state.getError() != null) { - JOptionPane.showMessageDialog(this, state.getError(), - "Error", JOptionPane.ERROR_MESSAGE); - } - } - - private void setFields(NoteState state) { - noteInputField.setText(state.getNote()); - } - - public void setNoteController(NoteController controller) { - this.noteController = controller; - } -} - diff --git a/src/main/java/view/RankingView.java b/src/main/java/view/RankingView.java new file mode 100644 index 000000000..250d7b504 --- /dev/null +++ b/src/main/java/view/RankingView.java @@ -0,0 +1,176 @@ +package view; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Container; +import java.awt.Font; +import java.io.IOException; +import java.util.List; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.DefaultTableModel; + +import app.JsonApplication; +import interface_adapters.NavigationManagerJson; +import interface_adapters.rankinglist.RankingController; +import interface_adapters.rankinglist.RankingInterface; + +/** + * Ranking view class that implements RankingInterface to display the leaderboard. + */ +public class RankingView extends JFrame implements RankingInterface { + private final JTable rankingTable; + private final DefaultTableModel tableModel; + private final JButton backButton; + + private RankingController rankingController; + private NavigationManagerJson navigationManager; + + /** + * Constructs the RankingView and sets up the UI components. + * @throws RuntimeException If there is an error initializing the signup application. + */ + public RankingView() { + super("Leaderboard"); + + // Main container layout + final Container container = getContentPane(); + container.setLayout(new BorderLayout()); + final String fontname = new String("Arial"); + + // Title + final JLabel titleLabel = new JLabel("Ranking List", JLabel.CENTER); + titleLabel.setFont(new Font(fontname, Font.BOLD, Constants.THIRTY)); + container.add(titleLabel, BorderLayout.NORTH); + + // Table to display rankings + final String[] columnNames = {"Rank", "Player Name", "Score", "Days Survived", "Status"}; + tableModel = new DefaultTableModel(columnNames, 0); + rankingTable = new JTable(tableModel); + // Make table non-editable + rankingTable.setEnabled(false); + rankingTable.setFont(new Font(fontname, Font.PLAIN, Constants.FIFTEEN)); + rankingTable.getTableHeader().setFont(new Font(fontname, Font.BOLD, Constants.FIFTEEN)); + rankingTable.setRowHeight(Constants.TWENTYFIVE); + container.add(new JScrollPane(rankingTable), BorderLayout.CENTER); + + // Error label + backButton = new JButton("Back to Main Memu"); + backButton.setBackground(Color.WHITE); + backButton.setForeground(Constants.THEME_COLOR); + backButton.setFont(new Font(fontname, Font.BOLD, Constants.TWENTY)); + container.add(backButton, BorderLayout.SOUTH); + + // Add ActionListener to navigate back to the main menu + backButton.addActionListener(event -> { + if (navigationManager != null) { + navigationManager.showMainView(); + } + else { + JOptionPane.showMessageDialog(this, "Navigation Manager not initialized.", + "Error", JOptionPane.ERROR_MESSAGE); + } + }); + + // Window settings + setSize(Constants.EIGHT_HUNDRED, Constants.SIX_HUNDRED); + setDefaultCloseOperation(EXIT_ON_CLOSE); + setResizable(false); + setLocation(Constants.FOUR_HUNDRED, Constants.TWO_HUNDRED); + } + + /** + * Sets the LoginController for this view. + * + * @param rankingController The LoginController instance. + */ + public void setRankingController(RankingController rankingController) { + this.rankingController = rankingController; + } + + /** + * Sets the NavigationManager for this view. + * + * @param navigationManager The NavigationManager instance. + */ + public void setNavigationManager(NavigationManagerJson navigationManager) { + this.navigationManager = navigationManager; + } + + /** + * Displays the leaderboard in the UI. + * + * @param playerNames A list of player names. + * @param scores A list of player scores. + * @param daysSurvived A list of days survived by each player. + * @param statuses A list of statuses indicating if each player won or lost. + */ + @Override + public void displayRankings(List playerNames, List scores, + List daysSurvived, List statuses) { + // Clear any existing rows in the table + tableModel.setRowCount(0); + + // Populate the table with new data + for (int i = 0; i < playerNames.size(); i++) { + tableModel.addRow(new Object[]{ + // Rank + i + 1, + // Player Name + playerNames.get(i), + // Score + scores.get(i), + // Days Survived + daysSurvived.get(i), + // Status (Won/Lost) + statuses.get(i), + }); + } + } + + /** + * Displays an error message in the UI. + * + * @param errorMessage The error message to display. + */ + @Override + public void displayError(String errorMessage) { + JOptionPane.showMessageDialog(this, errorMessage, + "Error", JOptionPane.ERROR_MESSAGE); + } + + /** + * Renders the ranking view window. + */ + public void render() { + setVisible(true); + if (rankingController != null) { + // Fetch rankings after the controller is set + rankingController.handleRanking(Constants.TEN); + } + } + + /** + * Hides the component by making it invisible to the user. + * + *

This method sets the visibility of the component to {@code false}, + * ensuring it is not displayed on the screen.

+ */ + public void disrender() { + setVisible(false); + } + + public static void main(String[] args) { + try { + new JsonApplication("PlayerFile", "PlayerFile", "RankingFile"); + } + catch (IOException event) { + event.printStackTrace(); + } + } +} diff --git a/src/main/java/view/RankingViewModel.java b/src/main/java/view/RankingViewModel.java new file mode 100644 index 000000000..c0769eaa7 --- /dev/null +++ b/src/main/java/view/RankingViewModel.java @@ -0,0 +1,43 @@ +package view; + +/** + * Represents a ViewModel for the ranking list. + * Used to pass ranking data from the application to the UI. + */ +public class RankingViewModel { + private final String name; + private final int score; + private final int daysSurvived; + private final boolean won; + + /** + * Constructs a new RankingViewModel with the specified attributes. + * + * @param name The player's name. + * @param score The player's score. + * @param daysSurvived The number of days the player survived. + * @param won Whether the player won. + */ + public RankingViewModel(String name, int score, int daysSurvived, boolean won) { + this.name = name; + this.score = score; + this.daysSurvived = daysSurvived; + this.won = won; + } + + public String getName() { + return name; + } + + public int getScore() { + return score; + } + + public int getDaysSurvived() { + return daysSurvived; + } + + public boolean isWon() { + return won; + } +} diff --git a/src/main/java/view/SignUpView.java b/src/main/java/view/SignUpView.java new file mode 100644 index 000000000..45cef7a8b --- /dev/null +++ b/src/main/java/view/SignUpView.java @@ -0,0 +1,240 @@ +package view; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.io.IOException; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPasswordField; +import javax.swing.JTextField; +import javax.swing.Spring; +import javax.swing.SpringLayout; + +import app.JsonApplication; +import interface_adapters.NavigationManagerJson; +import interface_adapters.signup.SignupController; +import interface_adapters.signup.SignupInterface; + +/** + * SignUpView handles the UI for user registration and integrates with the SignupApplication. + */ +public class SignUpView extends JFrame implements SignupInterface { + private final JLabel nameLabel = new JLabel("60 Days to Survive", JLabel.CENTER); + private final SpringLayout springLayout = new SpringLayout(); + private final JPanel centerPanel = new JPanel(springLayout); + private final JLabel userNameLabel = new JLabel("Username:"); + private final JTextField userText = new JTextField(); + private final JLabel passwordLabel = new JLabel("Password:"); + private final JPasswordField passwordText = new JPasswordField(); + private final JLabel againLabel = new JLabel("Confirm Password:"); + private final JPasswordField againText = new JPasswordField(); + private final JButton registerButton = new JButton("Sign up"); + private final JButton loginButton = new JButton("Back to login"); + + private SignupController signupController; + private NavigationManagerJson navigationManager; + + /** + * Constructs the SignUpView with the provided SignupController. + * + * @throws IOException If there is an error initializing the signup application. + */ + public SignUpView() throws IOException { + super("Sign Up"); + + final Container contentPane = getContentPane(); + final String fontname = new String("Arial"); + final String error = new String("error"); + setFont(fontname); + + userText.setPreferredSize(new Dimension(Constants.TWO_HUNDRED, Constants.THIRTY)); + passwordText.setPreferredSize(new Dimension(Constants.TWO_HUNDRED, Constants.THIRTY)); + againText.setPreferredSize(new Dimension(Constants.TWO_HUNDRED, Constants.THIRTY)); + + // add components + extracted(); + + contentPane.add(nameLabel, BorderLayout.NORTH); + contentPane.add(centerPanel, BorderLayout.CENTER); + + // springlayout + final Spring titleLabelWidth = Spring.width(userNameLabel); + final Spring titleTextWidth = Spring.width(userText); + final Spring spaceWidth = Spring.constant(20); + final Spring childWidth = Spring.sum(Spring.sum(titleLabelWidth, titleTextWidth), spaceWidth); + final int offsetX = (childWidth.getValue() + 40) / 2; + // set userNameLabel location + extracted(offsetX); + + registerButton.addActionListener(event -> handleSignup()); + + loginButton.addActionListener(event -> { + try { + navigationManager.showLoginView(); + } + catch (Exception ex) { + JOptionPane.showMessageDialog(this, "Error navigating to LoginView.", + error, JOptionPane.ERROR_MESSAGE); + ex.printStackTrace(); + } + }); + + setSize(Constants.SIX_HUNDRED, Constants.FOUR_HUNDRED); + // setLocation(null); + setDefaultCloseOperation(EXIT_ON_CLOSE); + setResizable(false); + setLocation(Constants.FIVE_HUNDRED, Constants.THREE_HUNDRED); + } + + private void setFont(String fontname) { + nameLabel.setFont(new Font("Impact", Font.BOLD, Constants.FIFTY)); + userNameLabel.setFont(new Font(fontname, Font.BOLD, Constants.FIFTEEN)); + passwordLabel.setFont(new Font(fontname, Font.BOLD, Constants.FIFTEEN)); + againLabel.setFont(new Font(fontname, Font.BOLD, Constants.FIFTEEN)); + registerButton.setFont(new Font(fontname, Font.PLAIN, Constants.TWENTY)); + registerButton.setBackground(Color.WHITE); + registerButton.setForeground(Constants.THEME_COLOR); + loginButton.setFont(new Font(fontname, Font.PLAIN, Constants.TWENTY)); + loginButton.setBackground(Constants.THEME_COLOR); + loginButton.setForeground(Color.WHITE); + } + + private void extracted() { + centerPanel.add(userNameLabel); + centerPanel.add(userText); + centerPanel.add(passwordLabel); + centerPanel.add(passwordText); + centerPanel.add(loginButton); + centerPanel.add(registerButton); + centerPanel.add(againLabel); + centerPanel.add(againText); + } + + private void extracted(int offsetX) { + springLayout.putConstraint(SpringLayout.WEST, userNameLabel, -offsetX, SpringLayout.HEIGHT, centerPanel); + springLayout.putConstraint(SpringLayout.NORTH, userNameLabel, Constants.FIFTY, SpringLayout.NORTH, + centerPanel); + // set userText location + springLayout.putConstraint(SpringLayout.WEST, userText, Constants.TEN, SpringLayout.EAST, userNameLabel); + springLayout.putConstraint(SpringLayout.NORTH, userText, -Constants.FIVE, SpringLayout.NORTH, userNameLabel); + // set passwordLabel location + springLayout.putConstraint(SpringLayout.EAST, passwordLabel, 0, SpringLayout.EAST, userNameLabel); + springLayout.putConstraint(SpringLayout.NORTH, passwordLabel, Constants.TWENTY, SpringLayout.SOUTH, + userNameLabel); + // set passwordText location + springLayout.putConstraint(SpringLayout.WEST, passwordText, Constants.TEN, SpringLayout.EAST, passwordLabel); + springLayout.putConstraint(SpringLayout.NORTH, passwordText, -Constants.FIVE, SpringLayout.NORTH, + passwordLabel); + // set loginButton location + springLayout.putConstraint(SpringLayout.WEST, loginButton, Constants.TEN, SpringLayout.WEST, passwordLabel); + springLayout.putConstraint(SpringLayout.NORTH, loginButton, Constants.EIGHTY, SpringLayout.SOUTH, + passwordLabel); + // set registerButton location + springLayout.putConstraint(SpringLayout.WEST, registerButton, Constants.FORTY, SpringLayout.EAST, loginButton); + springLayout.putConstraint(SpringLayout.NORTH, registerButton, -Constants.FIVE, SpringLayout.NORTH, + loginButton); + // set againLabel location + springLayout.putConstraint(SpringLayout.EAST, againLabel, 0, SpringLayout.EAST, passwordLabel); + springLayout.putConstraint(SpringLayout.NORTH, againLabel, Constants.TWENTY, SpringLayout.SOUTH, passwordLabel); + // set againText location + springLayout.putConstraint(SpringLayout.WEST, againText, Constants.TEN, SpringLayout.EAST, againLabel); + springLayout.putConstraint(SpringLayout.NORTH, againText, -Constants.FIVE, SpringLayout.NORTH, againLabel); + } + + private void handleSignup() { + final String username = userText.getText(); + final String password = new String(passwordText.getPassword()); + final String confirmPassword = new String(againText.getPassword()); + + if (!password.equals(confirmPassword)) { + JOptionPane.showMessageDialog(this, "Passwords do not match.", "Error", JOptionPane.ERROR_MESSAGE); + passwordText.setText(""); + againText.setText(""); + return; + } + + signupController.handleSignup(username, password); + } + + /** + * Sets the LoginController for this view. + * + * @param signupController The LoginController instance. + */ + public void setSignupController(SignupController signupController) { + this.signupController = signupController; + } + + /** + * Sets the NavigationManager for this view. + * + * @param navigationManager The NavigationManager instance. + */ + public void setNavigationManager(NavigationManagerJson navigationManager) { + this.navigationManager = navigationManager; + } + + /** + * Displays the result of the signup process. + * + * @param message A message indicating the result of the signup process. + */ + @Override + public void displaySignupResult(String message) { + JOptionPane.showMessageDialog(this, message, "Signup Result", JOptionPane.INFORMATION_MESSAGE); + + if ("Signup successful!".equals(message)) { + if (navigationManager != null) { + navigationManager.showLoginView(); + } + else { + userText.setText(""); + passwordText.setText(""); + againText.setText(""); + JOptionPane.showMessageDialog(this, + "Error navigating to LoginView.", + "Error", JOptionPane.ERROR_MESSAGE); + } + } + userText.setText(""); + passwordText.setText(""); + againText.setText(""); + } + + // Add render method + /** + * Renders the component by making it visible to the user. + * + *

This method sets the visibility of the component to {@code true}, + * ensuring it is displayed on the screen.

+ */ + public void render() { + setVisible(true); + } + + /** + * Hides the component by making it invisible to the user. + * + *

This method sets the visibility of the component to {@code false}, + * ensuring it is not displayed on the screen.

+ */ + public void disrender() { + setVisible(false); + } + + public static void main(String[] args) { + try { + new JsonApplication("PlayerFile", "PlayerFile", "RankingFile"); + } + catch (IOException event) { + event.printStackTrace(); + } + } +} diff --git a/src/test/java/app/MainNoteApplicationTest.java b/src/test/java/app/MainNoteApplicationTest.java deleted file mode 100644 index 025d970e2..000000000 --- a/src/test/java/app/MainNoteApplicationTest.java +++ /dev/null @@ -1,112 +0,0 @@ -package app; - -import entity.User; -import org.junit.Before; -import org.junit.Test; -import use_case.note.NoteDataAccessInterface; - -import javax.swing.*; -import java.awt.*; - -import static java.lang.Thread.sleep; -import static org.junit.Assert.*; - -public class MainNoteApplicationTest { - - private JFrame app; - - @Before - public void setUp() { - - // create the data access and inject it into our builder! - final NoteDataAccessInterface noteDataAccess = new NoteDataAccessInterface() { - - private String note = "test"; - - @Override - public String saveNote(User user, String note) { - this.note = note; - return note; - } - - @Override - public String loadNote(User user) { - return note; - } - }; - - final NoteAppBuilder builder = new NoteAppBuilder(); - app = builder.addNoteDAO(noteDataAccess) - .addNoteView() - .addNoteUseCase().build(); - - app.setVisible(true); - - } - - /** - * This is an example of an end-to-end test with a mocked database. - *

The code creates the application and directly tests to see that the GUI - * is updated as expected when the buttons and UI elements are interacted with. - *

- * You can run the test to visually see what happens. - */ - @Test - public void testEndToEnd() { - - Component[] components = ((JPanel)app.getRootPane().getContentPane().getComponents()[0]).getComponents(); - JTextArea textArea = null; - for (Component component : components) { - if (component instanceof JTextArea) { - textArea = (JTextArea) component; - assertEquals("test", textArea.getText()); - - } - } - - textArea.setText("test test"); - - - JButton save = null; - JButton load = null; - for (Component component : components) { - if (component instanceof JPanel) { - for (Component c : ((JPanel) component).getComponents()) { - if (c instanceof JButton) { - if (save != null) { - load = (JButton) c; - } - else { - save = (JButton) c; - } - } - } - } - } - - save.doClick(); - assertEquals("test test", textArea.getText()); - textArea.setText(""); - - System.out.println("cleared text; about to refresh..."); - // pause execution for a bit so we can visually see the changes on the screen - try { - sleep(1500); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - - load.doClick(); - assertEquals("test test", textArea.getText()); - - System.out.println("after refresh!"); - - // pause execution for a bit so we can visually see the changes on the screen - try { - sleep(1500); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - - } -} \ No newline at end of file diff --git a/src/test/java/use_case/note/NoteInteractorTest.java b/src/test/java/use_case/note/NoteInteractorTest.java deleted file mode 100644 index a3ed466b6..000000000 --- a/src/test/java/use_case/note/NoteInteractorTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package use_case.note; - -import entity.User; -import org.junit.Test; - -import static org.junit.Assert.*; - -public class NoteInteractorTest { - - @Test - public void testExecuteRefreshSuccess() { - - NoteDataAccessInterface noteDAO = new NoteDataAccessInterface() { - - - @Override - public String saveNote(User user, String note) { - return ""; - } - - - @Override - public String loadNote(User user) { - return "test"; - } - }; - - NoteOutputBoundary noteOB = new NoteOutputBoundary() { - @Override - public void prepareSuccessView(String message) { - assertEquals("test", message); - } - - @Override - public void prepareFailView(String errorMessage) { - fail(errorMessage); - } - }; - - NoteInteractor noteInteractor = new NoteInteractor(noteDAO, noteOB); - - noteInteractor.executeRefresh(); - - - } -} \ No newline at end of file diff --git a/src/test/java/usecases/MinimapInteractorTest.java b/src/test/java/usecases/MinimapInteractorTest.java new file mode 100644 index 000000000..020458b00 --- /dev/null +++ b/src/test/java/usecases/MinimapInteractorTest.java @@ -0,0 +1,60 @@ +package usecases; + +import entities.*; +import org.junit.Test; +import usecases.gameminimap.*; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; + +public class MinimapInteractorTest { + + @Test + public void testMinimapInteractorSuccess() { + ArrayList environments = new ArrayList<>(Arrays.asList("Iceland", "Desert", "Forest", "City", "Plain")); + MapFactory Mapfact =new MapFactory(); + ArrayList>>> cores = + Mapfact.getCores(100, 100, environments); + ArrayList> grids = Mapfact.getGrids(100, 100, cores); + Maps map = new Maps(grids); + MinimapDataAccessInterface MockDAO = new MinimapDataAccessInterface() { + @Override + public PlayerLocation getPlayerLocation() { + return new PlayerLocation(0,0); + } + + @Override + public Maps getMaps() { + return map; + } + }; + MinimapOutputBoundary mockPresenter = new MinimapOutputBoundary() { + @Override + public void preparesuccessview(MinimapOutputData outputdata) { + ArrayList> minimap = new ArrayList<>(); + for(int x = -4; x <= 4; x++) { + ArrayList row = new ArrayList<>(); + for(int y = -4; y <= 4; y++) { + if (EntityConstants.MAPWIDTH >= x + 1 && EntityConstants.MAPHEIGHT >= y + 1 && x >= 0 && y >= 0) { + row.add(grids.get(y).get(x).toString().substring(0, 1)); + // get the first letter as representative of map grid. + } + else { + row.add(" "); + // empty representing outside of Map + } + } + minimap.add(row); + } + System.out.println(minimap); + assertEquals(minimap, outputdata.getMinimap()); + } + + }; + MinimapInteractor MinimapInteractor = new MinimapInteractor(MockDAO, mockPresenter); + MinimapInteractor.execute(new MinimapInputData()); + } +}