diff --git a/pom.xml b/pom.xml index 78ee59d..9fadf8d 100644 --- a/pom.xml +++ b/pom.xml @@ -57,15 +57,19 @@ org.junit.jupiter - junit-jupiter-api + junit-jupiter-engine test org.junit.jupiter - junit-jupiter-engine + junit-jupiter-params + test + + + org.mockito + mockito-junit-jupiter test - diff --git a/src/main/java/com/javarush/buslovskii/command/Command.java b/src/main/java/com/javarush/buslovskii/command/Command.java new file mode 100644 index 0000000..d1c9159 --- /dev/null +++ b/src/main/java/com/javarush/buslovskii/command/Command.java @@ -0,0 +1,8 @@ +package com.javarush.buslovskii.command; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +public interface Command { + String execute(HttpServletRequest request, HttpServletResponse response) throws Exception; +} \ No newline at end of file diff --git a/src/main/java/com/javarush/buslovskii/command/CommandFactory.java b/src/main/java/com/javarush/buslovskii/command/CommandFactory.java new file mode 100644 index 0000000..aada413 --- /dev/null +++ b/src/main/java/com/javarush/buslovskii/command/CommandFactory.java @@ -0,0 +1,39 @@ +package com.javarush.buslovskii.command; + +import java.util.HashMap; +import java.util.Map; + +public class CommandFactory { + + private static CommandFactory instance; + private Map commands; + + private CommandFactory() { + commands = new HashMap<>(); + commands.put("start", new StartCommand()); + commands.put("game", new GameCommand()); + commands.put("restart", new RestartCommand()); + commands.put("selectquest", new SelectQuestCommand()); + commands.put("selectQuest", new SelectQuestCommand()); + } + + public static synchronized CommandFactory getInstance() { + if (instance == null) { + instance = new CommandFactory(); + } + return instance; + } + + public Command getCommand(String commandName) { + if (commandName == null || commandName.isEmpty()) { + return new StartCommand(); + } + + Command command = commands.get(commandName.toLowerCase()); + if (command == null) { + command = new UnknownCommand(); + } + + return command; + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/buslovskii/command/GameCommand.java b/src/main/java/com/javarush/buslovskii/command/GameCommand.java new file mode 100644 index 0000000..010b91e --- /dev/null +++ b/src/main/java/com/javarush/buslovskii/command/GameCommand.java @@ -0,0 +1,103 @@ +package com.javarush.buslovskii.command; + +import com.javarush.buslovskii.model.GameState; +import com.javarush.buslovskii.model.Quest; +import com.javarush.buslovskii.model.Question; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; + +public class GameCommand implements Command { + + @Override + public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception { + HttpSession session = request.getSession(); + GameState gameState = (GameState) session.getAttribute("gameState"); + Quest currentQuest = (Quest) session.getAttribute("currentQuest"); + + if (gameState == null) { + return "redirect:/start"; + } + + if (currentQuest == null) { + return "redirect:/selectQuest"; + } + + String method = request.getMethod(); + + if ("POST".equalsIgnoreCase(method)) { + String choiceParam = request.getParameter("choice"); + if (choiceParam != null) { + try { + int choice = Integer.parseInt(choiceParam); + int currentQuestionId = gameState.getCurrentQuestionId(); + + Question currentQuestion = currentQuest.getQuestions().get(currentQuestionId); + if (currentQuestion == null) { + return "redirect:/selectQuest"; + } + + int nextQuestionId; + if (choice == 1) { + nextQuestionId = currentQuestion.getNextIdOption1(); + } else { + nextQuestionId = currentQuestion.getNextIdOption2(); + } + + Question nextQuestion = currentQuest.getQuestions().get(nextQuestionId); + if (nextQuestion == null) { + return "redirect:/selectQuest"; + } + + gameState.setCurrentQuestionId(nextQuestionId); + + if (nextQuestion.isFinal()) { + gameState.setGameOver(true); + + boolean victory = currentQuest.isVictory(nextQuestionId); + gameState.setVictory(victory); + + if (victory) { + gameState.addWin(); + session.setAttribute("finalMessage", currentQuest.getVictoryMessage(nextQuestionId)); + } else { + gameState.addLoss(); + session.setAttribute("finalMessage", currentQuest.getDefeatMessage(nextQuestionId)); + } + + gameState.incrementGamesPlayed(); + return "redirect:/game?result=final"; + } + } catch (NumberFormatException e) { + return "redirect:/game"; + } + } + return "redirect:/game"; + } + + if (gameState.isGameOver()) { + Question currentQuestion = currentQuest.getQuestions().get(gameState.getCurrentQuestionId()); + if (currentQuestion == null) { + return "redirect:/selectQuest"; + } + request.setAttribute("question", currentQuestion); + + String finalMessage = (String) session.getAttribute("finalMessage"); + if (finalMessage != null) { + request.setAttribute("finalMessage", finalMessage); + session.removeAttribute("finalMessage"); + } + + return "/result.jsp"; + } + + Question currentQuestion = currentQuest.getQuestions().get(gameState.getCurrentQuestionId()); + if (currentQuestion == null) { + return "redirect:/selectQuest"; + } + + request.setAttribute("question", currentQuestion); + request.setAttribute("quest", currentQuest); + return "/game.jsp"; + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/buslovskii/command/RestartCommand.java b/src/main/java/com/javarush/buslovskii/command/RestartCommand.java new file mode 100644 index 0000000..0409799 --- /dev/null +++ b/src/main/java/com/javarush/buslovskii/command/RestartCommand.java @@ -0,0 +1,28 @@ +package com.javarush.buslovskii.command; + +import com.javarush.buslovskii.model.GameState; +import com.javarush.buslovskii.model.Quest; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; + +public class RestartCommand implements Command { + + @Override + public String execute(HttpServletRequest request, HttpServletResponse response) { + HttpSession session = request.getSession(); + GameState gameState = (GameState) session.getAttribute("gameState"); + Quest currentQuest = (Quest) session.getAttribute("currentQuest"); + + if (gameState != null && currentQuest != null) { + gameState.setCurrentQuestionId(1); + gameState.setGameOver(false); + gameState.setVictory(false); + session.removeAttribute("finalMessage"); + } else { + return "redirect:/start"; + } + + return "redirect:/game"; + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/buslovskii/command/SelectQuestCommand.java b/src/main/java/com/javarush/buslovskii/command/SelectQuestCommand.java new file mode 100644 index 0000000..8ca48f9 --- /dev/null +++ b/src/main/java/com/javarush/buslovskii/command/SelectQuestCommand.java @@ -0,0 +1,52 @@ +package com.javarush.buslovskii.command; + +import com.javarush.buslovskii.model.GameState; +import com.javarush.buslovskii.model.Quest; +import com.javarush.buslovskii.model.QuestManager; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; + +public class SelectQuestCommand implements Command { + + @Override + public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception { + HttpSession session = request.getSession(); + GameState gameState = (GameState) session.getAttribute("gameState"); + QuestManager questManager = QuestManager.getInstance(); + + if (gameState == null) { + return "redirect:/start"; + } + + String method = request.getMethod(); + + if ("POST".equalsIgnoreCase(method)) { + String questId = request.getParameter("questId"); + if (questId == null || questId.trim().isEmpty()) { + // Если ID не выбран, показываем список снова + request.setAttribute("quests", questManager.getAllQuests()); + request.setAttribute("questStats", questManager.getAllQuestStats()); + return "/quest-selection.jsp"; + } + + Quest selectedQuest = questManager.getQuest(questId); + + if (selectedQuest != null) { + session.setAttribute("currentQuest", selectedQuest); + gameState.setCurrentQuestId(questId); + gameState.setCurrentQuestionId(1); + gameState.setGameOver(false); + gameState.setVictory(false); + + questManager.incrementQuestPlays(questId); + + return "redirect:/game"; + } + } + + request.setAttribute("quests", questManager.getAllQuests()); + request.setAttribute("questStats", questManager.getAllQuestStats()); + return "/quest-selection.jsp"; + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/buslovskii/command/StartCommand.java b/src/main/java/com/javarush/buslovskii/command/StartCommand.java new file mode 100644 index 0000000..9ea6c35 --- /dev/null +++ b/src/main/java/com/javarush/buslovskii/command/StartCommand.java @@ -0,0 +1,33 @@ +package com.javarush.buslovskii.command; + +import com.javarush.buslovskii.model.GameState; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; + +public class StartCommand implements Command { + + @Override + public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception { + String method = request.getMethod(); + + if ("POST".equalsIgnoreCase(method)) { + String playerName = request.getParameter("playerName"); + + if (playerName == null || playerName.trim().isEmpty()) { + playerName = "Игрок"; + } + + HttpSession session = request.getSession(); + + GameState gameState = new GameState(); + gameState.setPlayerName(playerName.trim()); + + session.setAttribute("gameState", gameState); + + return "redirect:/selectQuest"; + } + + return "/index.jsp"; + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/buslovskii/command/UnknownCommand.java b/src/main/java/com/javarush/buslovskii/command/UnknownCommand.java new file mode 100644 index 0000000..bbf0c05 --- /dev/null +++ b/src/main/java/com/javarush/buslovskii/command/UnknownCommand.java @@ -0,0 +1,12 @@ +package com.javarush.buslovskii.command; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +public class UnknownCommand implements Command { + + @Override + public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception { + return "redirect:/start"; + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/buslovskii/controller/FrontControllerServlet.java b/src/main/java/com/javarush/buslovskii/controller/FrontControllerServlet.java new file mode 100644 index 0000000..8d123c3 --- /dev/null +++ b/src/main/java/com/javarush/buslovskii/controller/FrontControllerServlet.java @@ -0,0 +1,81 @@ +package com.javarush.buslovskii.controller; + +import com.javarush.buslovskii.command.Command; +import com.javarush.buslovskii.command.CommandFactory; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; + +@WebServlet("/") +public class FrontControllerServlet extends HttpServlet { + + private CommandFactory commandFactory; + + @Override + public void init() throws ServletException { + commandFactory = CommandFactory.getInstance(); + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + processRequest(request, response); + } + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + processRequest(request, response); + } + + private void processRequest(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + String path = getCommandPath(request); + Command command = commandFactory.getCommand(path); + + try { + String view = command.execute(request, response); + + if (view.startsWith("redirect:")) { + String redirectPath = view.substring("redirect:".length()); + response.sendRedirect(request.getContextPath() + redirectPath); + } else { + request.getRequestDispatcher(view).forward(request, response); + } + } catch (Exception e) { + throw new ServletException("Error executing command", e); + } + } + + private String getCommandPath(HttpServletRequest request) { + String uri = request.getRequestURI(); + String contextPath = request.getContextPath(); + + String path = uri.substring(contextPath.length()); + + if (path.startsWith("/")) { + path = path.substring(1); + } + + if (path.isEmpty() || path.equals("favicon.ico")) { + return "start"; + } + + if (path.contains("?")) { + path = path.substring(0, path.indexOf("?")); + } + if (path.contains("#")) { + path = path.substring(0, path.indexOf("#")); + } + + if (path.contains(".")) { + path = path.substring(0, path.indexOf(".")); + } + + return path; + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/buslovskii/filter/StaticResourceFilter.java b/src/main/java/com/javarush/buslovskii/filter/StaticResourceFilter.java new file mode 100644 index 0000000..d1e85b5 --- /dev/null +++ b/src/main/java/com/javarush/buslovskii/filter/StaticResourceFilter.java @@ -0,0 +1,40 @@ +package com.javarush.buslovskii.filter; + +import jakarta.servlet.*; +import jakarta.servlet.annotation.WebFilter; +import jakarta.servlet.http.HttpServletRequest; +import java.io.IOException; + +@WebFilter("/*") +public class StaticResourceFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + + HttpServletRequest httpRequest = (HttpServletRequest) request; + String path = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length()); + + if (path.startsWith("/css/") || + path.startsWith("/js/") || + path.startsWith("/images/") || + path.startsWith("/fonts/") || + path.endsWith(".css") || + path.endsWith(".js") || + path.endsWith(".jpg") || + path.endsWith(".png") || + path.endsWith(".gif") || + path.endsWith(".ico")) { + chain.doFilter(request, response); + return; + } + + chain.doFilter(request, response); + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException {} + + @Override + public void destroy() {} +} \ No newline at end of file diff --git a/src/main/java/com/javarush/buslovskii/listener/SessionListener.java b/src/main/java/com/javarush/buslovskii/listener/SessionListener.java new file mode 100644 index 0000000..1959fe3 --- /dev/null +++ b/src/main/java/com/javarush/buslovskii/listener/SessionListener.java @@ -0,0 +1,27 @@ +package com.javarush.buslovskii.listener; + +import jakarta.servlet.annotation.WebListener; +import jakarta.servlet.http.HttpSessionEvent; +import jakarta.servlet.http.HttpSessionListener; + +@WebListener +public class SessionListener implements HttpSessionListener { + + private static int activeSessions = 0; + + @Override + public void sessionCreated(HttpSessionEvent se) { + activeSessions++; + System.out.println("Session created. Active sessions: " + activeSessions); + } + + @Override + public void sessionDestroyed(HttpSessionEvent se) { + activeSessions--; + System.out.println("Session destroyed. Active sessions: " + activeSessions); + } + + public static int getActiveSessions() { + return activeSessions; + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/buslovskii/model/GameState.java b/src/main/java/com/javarush/buslovskii/model/GameState.java new file mode 100644 index 0000000..dbba880 --- /dev/null +++ b/src/main/java/com/javarush/buslovskii/model/GameState.java @@ -0,0 +1,101 @@ +package com.javarush.buslovskii.model; + +import java.io.Serializable; + +public class GameState implements Serializable { + private static final long serialVersionUID = 1L; + + private String playerName; + private String currentQuestId; + private int currentQuestionId; + private int gamesPlayed; + private int wins; + private int losses; + private boolean gameOver; + private boolean victory; + + public GameState() { + this.currentQuestionId = 1; + this.gamesPlayed = 0; + this.wins = 0; + this.losses = 0; + this.gameOver = false; + this.victory = false; + } + + public String getPlayerName() { + return playerName; + } + + public void setPlayerName(String playerName) { + this.playerName = playerName; + } + + public String getCurrentQuestId() { + return currentQuestId; + } + + public void setCurrentQuestId(String currentQuestId) { + this.currentQuestId = currentQuestId; + } + + public int getCurrentQuestionId() { + return currentQuestionId; + } + + public void setCurrentQuestionId(int currentQuestionId) { + this.currentQuestionId = currentQuestionId; + } + + public int getGamesPlayed() { + return gamesPlayed; + } + + public void setGamesPlayed(int gamesPlayed) { + this.gamesPlayed = gamesPlayed; + } + + public int getWins() { + return wins; + } + + public void setWins(int wins) { + this.wins = wins; + } + + public int getLosses() { + return losses; + } + + public void setLosses(int losses) { + this.losses = losses; + } + + public boolean isGameOver() { + return gameOver; + } + + public void setGameOver(boolean gameOver) { + this.gameOver = gameOver; + } + + public boolean isVictory() { + return victory; + } + + public void setVictory(boolean victory) { + this.victory = victory; + } + + public void incrementGamesPlayed() { + this.gamesPlayed++; + } + + public void addWin() { + this.wins++; + } + + public void addLoss() { + this.losses++; + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/buslovskii/model/Quest.java b/src/main/java/com/javarush/buslovskii/model/Quest.java new file mode 100644 index 0000000..bf85f90 --- /dev/null +++ b/src/main/java/com/javarush/buslovskii/model/Quest.java @@ -0,0 +1,18 @@ +package com.javarush.buslovskii.model; + +import java.io.Serializable; +import java.util.Map; + +public interface Quest extends Serializable { + String getId(); + String getTitle(); + String getDescription(); + String getGenre(); + int getDifficultyLevel(); // 1-5 + String getBackgroundImage(); + Map getQuestions(); + Question getStartQuestion(); + boolean isVictory(int questionId); + String getVictoryMessage(int questionId); + String getDefeatMessage(int questionId); +} \ No newline at end of file diff --git a/src/main/java/com/javarush/buslovskii/model/QuestManager.java b/src/main/java/com/javarush/buslovskii/model/QuestManager.java new file mode 100644 index 0000000..a812011 --- /dev/null +++ b/src/main/java/com/javarush/buslovskii/model/QuestManager.java @@ -0,0 +1,89 @@ +package com.javarush.buslovskii.model; + +import com.javarush.buslovskii.model.quests.DetectiveStoryQuest; +import com.javarush.buslovskii.model.quests.SpaceAdventureQuest; +import com.javarush.buslovskii.model.quests.TreasureHuntQuest; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public class QuestManager { + private static QuestManager instance; + private Map quests; + private Map questsById; + private Map questStats; + + private QuestManager() { + quests = new LinkedHashMap<>(); + questsById = new HashMap<>(); + questStats = new ConcurrentHashMap<>(); + initializeQuests(); + } + + public static synchronized QuestManager getInstance() { + if (instance == null) { + instance = new QuestManager(); + } + return instance; + } + + private void initializeQuests() { + addQuest(new TreasureHuntQuest()); + addQuest(new SpaceAdventureQuest()); + addQuest(new DetectiveStoryQuest()); + + } + + private void addQuest(Quest quest) { + quests.put(quest.getTitle(), quest); + questsById.put(quest.getId(), quest); + questStats.put(quest.getId(), 0); + } + + public List getAllQuests() { + return new ArrayList<>(quests.values()); + } + + public Quest getQuest(String id) { + return questsById.get(id); + } + + public Quest getQuestByTitle(String title) { + return quests.get(title); + } + + public void incrementQuestPlays(String questId) { + questStats.merge(questId, 1, Integer::sum); + } + + public int getQuestPlays(String questId) { + return questStats.getOrDefault(questId, 0); + } + + public Map getAllQuestStats() { + return new HashMap<>(questStats); + } + + public List getQuestsByGenre(String genre) { + List result = new ArrayList<>(); + for (Quest quest : quests.values()) { + if (quest.getGenre().equalsIgnoreCase(genre)) { + result.add(quest); + } + } + return result; + } + + public List getQuestsByDifficulty(int difficulty) { + List result = new ArrayList<>(); + for (Quest quest : quests.values()) { + if (quest.getDifficultyLevel() == difficulty) { + result.add(quest); + } + } + return result; + } + public void resetStats() { + questStats.clear(); + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/buslovskii/model/Question.java b/src/main/java/com/javarush/buslovskii/model/Question.java new file mode 100644 index 0000000..92c2683 --- /dev/null +++ b/src/main/java/com/javarush/buslovskii/model/Question.java @@ -0,0 +1,46 @@ +package com.javarush.buslovskii.model; + +import java.io.Serializable; + +public class Question implements Serializable { + private static final long serialVersionUID = 1L; + + private int id; + private String text; + private String option1; + private String option2; + private int nextIdOption1; + private int nextIdOption2; + private boolean isFinal; + private String victoryMessage; + private String defeatMessage; + + public Question(int id, String text, String option1, String option2, + int nextIdOption1, int nextIdOption2) { + this(id, text, option1, option2, nextIdOption1, nextIdOption2, false, null, null); + } + + public Question(int id, String text, String option1, String option2, + int nextIdOption1, int nextIdOption2, boolean isFinal, + String victoryMessage, String defeatMessage) { + this.id = id; + this.text = text; + this.option1 = option1; + this.option2 = option2; + this.nextIdOption1 = nextIdOption1; + this.nextIdOption2 = nextIdOption2; + this.isFinal = isFinal; + this.victoryMessage = victoryMessage; + this.defeatMessage = defeatMessage; + } + + public int getId() { return id; } + public String getText() { return text; } + public String getOption1() { return option1; } + public String getOption2() { return option2; } + public int getNextIdOption1() { return nextIdOption1; } + public int getNextIdOption2() { return nextIdOption2; } + public boolean isFinal() { return isFinal; } + public String getVictoryMessage() { return victoryMessage; } + public String getDefeatMessage() { return defeatMessage; } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/buslovskii/model/quests/DetectiveStoryQuest.java b/src/main/java/com/javarush/buslovskii/model/quests/DetectiveStoryQuest.java new file mode 100644 index 0000000..3c91353 --- /dev/null +++ b/src/main/java/com/javarush/buslovskii/model/quests/DetectiveStoryQuest.java @@ -0,0 +1,163 @@ +package com.javarush.buslovskii.model.quests; + +import com.javarush.buslovskii.model.Quest; +import com.javarush.buslovskii.model.Question; + +import java.util.HashMap; +import java.util.Map; + +public class DetectiveStoryQuest implements Quest { + private static final long serialVersionUID = 1L; + + private Map questions; + + public DetectiveStoryQuest() { + initializeQuestions(); + } + + private void initializeQuestions() { + questions = new HashMap<>(); + + questions.put(1, new Question(1, + "Вы - известный детектив. Вас вызывают на место убийства миллионера. С чего начнете?", + "Осмотреть тело", + "Поговорить с прислугой", + 2, 3)); + + questions.put(2, new Question(2, + "На теле найдены странные следы укуса. Похоже на вампира!", + "Искать вампира", + "Искать другие улики", + 4, 5)); + + questions.put(3, new Question(3, + "Прислуга говорит, что видели таинственного незнакомца в плаще.", + "Искать незнакомца", + "Проверить комнату убитого", + 6, 5)); + + questions.put(4, new Question(4, + "Вы находите логово вампира в подвале!", + "Войти с распятием", + "Войти с колом", + 7, 8)); + + questions.put(5, new Question(5, + "В комнате убитого найден дневник с зашифрованными записями.", + "Расшифровать записи", + "Показать эксперту", + 9, 10)); + + questions.put(6, new Question(6, + "Незнакомец оказывается братом убитого. Он предлагает взятку, чтобы вы закрыли дело.", + "Взять взятку", + "Арестовать его", + 11, 12)); + + questions.put(7, new Question(7, + "Вампир боится распятия. Вы заставляете его признаться в убийстве!", + "Начать заново", + "Выбрать другой квест", + 1, 1, true, + "Дело раскрыто! Убийца - вампир, и он обезврежен!", + null)); + + questions.put(8, new Question(8, + "Кол оказался недостаточно острым. Вампир атакует...", + "Начать заново", + "Выбрать другой квест", + 1, 1, true, + null, + "Вампир убивает вас. Дело остается нераскрытым.")); + + questions.put(9, new Question(9, + "В дневнике зашифровано имя убийцы - это дворецкий!", + "Начать заново", + "Выбрать другой квест", + 1, 1, true, + "Дворецкий арестован! Дело раскрыто!", + null)); + + questions.put(10, new Question(10, + "Эксперт теряет улики. Дело закрыто из-за отсутствия доказательств.", + "Начать заново", + "Выбрать другой квест", + 1, 1, true, + null, + "Убийца остается на свободе. Дело провалено.")); + + questions.put(11, new Question(11, + "Взятка оказывается фальшивой, и вас арестовывают за коррупцию.", + "Начать заново", + "Выбрать другой квест", + 1, 1, true, + null, + "Вы в тюрьме, а убийца на свободе.")); + + questions.put(12, new Question(12, + "Брат убийцы сознается в преступлении из ревности!", + "Начать заново", + "Выбрать другой квест", + 1, 1, true, + "Преступник сознался! Дело раскрыто!", + null)); + } + + @Override + public String getId() { + return "detective-story"; + } + + @Override + public String getTitle() { + return "Детективная история"; + } + + @Override + public String getDescription() { + return "Раскройте убийство миллионера в старом особняке. Под подозрением все: " + + "от прислуги до таинственного вампира!"; + } + + @Override + public String getGenre() { + return "Детектив/Мистика"; + } + + @Override + public int getDifficultyLevel() { + return 5; + } + + @Override + public String getBackgroundImage() { + return "/images/mansion.jpg"; + } + + @Override + public Map getQuestions() { + return questions; + } + + @Override + public Question getStartQuestion() { + return questions.get(1); + } + + @Override + public boolean isVictory(int questionId) { + return questionId == 7 || questionId == 9 || questionId == 12; + } + + @Override + public String getVictoryMessage(int questionId) { + Question q = questions.get(questionId); + return q != null ? q.getVictoryMessage() : "Дело раскрыто!"; + } + + @Override + public String getDefeatMessage(int questionId) { + Question q = questions.get(questionId); + return q != null ? q.getDefeatMessage() : "Дело провалено."; + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/buslovskii/model/quests/SpaceAdventureQuest.java b/src/main/java/com/javarush/buslovskii/model/quests/SpaceAdventureQuest.java new file mode 100644 index 0000000..d98f74f --- /dev/null +++ b/src/main/java/com/javarush/buslovskii/model/quests/SpaceAdventureQuest.java @@ -0,0 +1,149 @@ +package com.javarush.buslovskii.model.quests; + +import com.javarush.buslovskii.model.Quest; +import com.javarush.buslovskii.model.Question; + +import java.util.HashMap; +import java.util.Map; + +public class SpaceAdventureQuest implements Quest { + private static final long serialVersionUID = 1L; + + private Map questions; + + public SpaceAdventureQuest() { + initializeQuestions(); + } + + private void initializeQuestions() { + questions = new HashMap<>(); + + questions.put(1, new Question(1, + "Ваш космический корабль терпит крушение на неизвестной планете. Что делать?", + "Исследовать поверхность", + "Попытаться починить корабль", + 2, 3)); + + questions.put(2, new Question(2, + "Вы выходите на поверхность. Видите странные сооружения вдалеке.", + "Направиться к сооружениям", + "Вернуться к кораблю", + 4, 3)); + + questions.put(3, new Question(3, + "Ремонт корабля требует редких кристаллов. Они есть в пещере неподалеку.", + "Идти в пещеру", + "Продолжить ремонт без кристаллов", + 5, 6)); + + questions.put(4, new Question(4, + "Вы находите заброшенную базу пришельцев. Там есть топливо!", + "Взять топливо", + "Поискать что-то еще", + 7, 8)); + + questions.put(5, new Question(5, + "В пещере вы находите кристаллы, но просыпается огромный паук!", + "Сражаться с пауком", + "Убегать", + 9, 10)); + + questions.put(6, new Question(6, + "Без кристаллов двигатель взрывается...", + "Начать заново", + "Выбрать другой квест", + 1, 1, true, + null, + "Корабль уничтожен. Вы погибли.")); + + questions.put(7, new Question(7, + "С топливом вы взлетаете и возвращаетесь на Землю!", + "Начать заново", + "Выбрать другой квест", + 1, 1, true, + "Вы успешно вернулись на Землю и стали героем!", + null)); + + questions.put(8, new Question(8, + "Вы натыкаетесь на ловушку и попадаете в плен к пришельцам.", + "Начать заново", + "Выбрать другой квест", + 1, 1, true, + null, + "Вас взяли в плен. Игра окончена.")); + + questions.put(9, new Question(9, + "Вы победили паука и взяли кристаллы. Корабль починен!", + "Начать заново", + "Выбрать другой квест", + 1, 1, true, + "Вы починили корабль и улетели домой! Победа!", + null)); + + questions.put(10, new Question(10, + "Паук догоняет вас и...", + "Начать заново", + "Выбрать другой квест", + 1, 1, true, + null, + "Паук оказался быстрее. Вы погибли.")); + } + + @Override + public String getId() { + return "space-adventure"; + } + + @Override + public String getTitle() { + return "Космическое приключение"; + } + + @Override + public String getDescription() { + return "Вы - капитан космического корабля, потерпевшего крушение на неизвестной планете. " + + "Сможете ли вы выжить и вернуться домой?"; + } + + @Override + public String getGenre() { + return "Sci-Fi/Выживание"; + } + + @Override + public int getDifficultyLevel() { + return 4; + } + + @Override + public String getBackgroundImage() { + return "/images/space.jpg"; + } + + @Override + public Map getQuestions() { + return questions; + } + + @Override + public Question getStartQuestion() { + return questions.get(1); + } + + @Override + public boolean isVictory(int questionId) { + return questionId == 7 || questionId == 9; + } + + @Override + public String getVictoryMessage(int questionId) { + Question q = questions.get(questionId); + return q != null ? q.getVictoryMessage() : "Миссия выполнена!"; + } + + @Override + public String getDefeatMessage(int questionId) { + Question q = questions.get(questionId); + return q != null ? q.getDefeatMessage() : "Миссия провалена."; + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/buslovskii/model/quests/TreasureHuntQuest.java b/src/main/java/com/javarush/buslovskii/model/quests/TreasureHuntQuest.java new file mode 100644 index 0000000..45754fe --- /dev/null +++ b/src/main/java/com/javarush/buslovskii/model/quests/TreasureHuntQuest.java @@ -0,0 +1,163 @@ +package com.javarush.buslovskii.model.quests; + +import com.javarush.buslovskii.model.Quest; +import com.javarush.buslovskii.model.Question; + +import java.util.HashMap; +import java.util.Map; + +public class TreasureHuntQuest implements Quest { + private static final long serialVersionUID = 1L; + + private Map questions; + + public TreasureHuntQuest() { + initializeQuestions(); + } + + private void initializeQuestions() { + questions = new HashMap<>(); + + questions.put(1, new Question(1, + "Вы стоите перед входом в заброшенный замок. Ночь, луна освещает древние стены. Что вы сделаете?", + "Войти через главный вход", + "Найти тайный вход", + 2, 3)); + + questions.put(2, new Question(2, + "Вы входите в главный зал. Слышен странный шорох. На стене висит старый меч.", + "Взять меч и исследовать звук", + "Игнорировать меч и пойти дальше", + 4, 5)); + + questions.put(3, new Question(3, + "Вы нашли потайную дверь за кустами. Она ведет в подвал замка.", + "Спуститься в подвал", + "Вернуться к главному входу", + 6, 2)); + + questions.put(4, new Question(4, + "Вы взяли меч и пошли на звук. Это оказался призрак старого рыцаря!", + "Сразиться с призраком", + "Попытаться поговорить", + 7, 8)); + + questions.put(5, new Question(5, + "Вы пошли дальше без оружия. В темноте вы слышите шаги...", + "Спрятаться", + "Бежать", + 9, 10)); + + questions.put(6, new Question(6, + "В подвале вы нашли сундук с сокровищами! Но вход завалило камнями.", + "Попытаться разобрать завал", + "Искать другой выход", + 11, 12)); + + questions.put(7, new Question(7, + "Вы победили призрака! Он рассыпался в прах, оставив после себя древний амулет.", + "Начать заново", + "Выбрать другой квест", + 1, 1, true, + "Вы нашли древний амулет и выбрались из замка! Сокровища ваши!", + null)); + + questions.put(8, new Question(8, + "Призрак оказался дружелюбным! Он показал вам тайный ход к сокровищам.", + "Начать заново", + "Выбрать другой квест", + 1, 1, true, + "Вы нашли золото и подружились с призраком! Победа!", + null)); + + questions.put(9, new Question(9, + "Вы спрятались, но это был всего лишь кот. Вы нашли выход с мешком монет!", + "Начать заново", + "Выбрать другой квест", + 1, 1, true, + "Вы нашли сокровища и благополучно выбрались!", + null)); + + questions.put(10, new Question(10, + "Вы побежали и упали в яму с водой. Выбраться не удалось...", + "Начать заново", + "Выбрать другой квест", + 1, 1, true, + null, + "Вы утонули в подземной реке. Игра окончена.")); + + questions.put(11, new Question(11, + "Вы разобрали завал, но камни упали и придавили вас...", + "Начать заново", + "Выбрать другой квест", + 1, 1, true, + null, + "Вы погибли под завалом. Игра окончена.")); + + questions.put(12, new Question(12, + "Вы нашли старый туннель, ведущий прямо к выходу! Сокровища ваши!", + "Начать заново", + "Выбрать другой квест", + 1, 1, true, + "Вы нашли выход с сокровищами! Поздравляем!", + null)); + } + + @Override + public String getId() { + return "treasure-hunt"; + } + + @Override + public String getTitle() { + return "Поиск сокровищ в замке"; + } + + @Override + public String getDescription() { + return "Отправляйтесь в заброшенный замок на поиски легендарных сокровищ. " + + "Вас ждут встречи с призраками, ловушки и загадочные подземелья."; + } + + @Override + public String getGenre() { + return "Хоррор/Приключения"; + } + + @Override + public int getDifficultyLevel() { + return 3; + } + + @Override + public String getBackgroundImage() { + return "/images/castle.jpg"; + } + + @Override + public Map getQuestions() { + return questions; + } + + @Override + public Question getStartQuestion() { + return questions.get(1); + } + + @Override + public boolean isVictory(int questionId) { + return questionId == 7 || questionId == 8 || questionId == 9 || questionId == 12; + } + + @Override + public String getVictoryMessage(int questionId) { + Question q = questions.get(questionId); + return q != null ? q.getVictoryMessage() : "Поздравляем! Вы победили!"; + } + + @Override + public String getDefeatMessage(int questionId) { + Question q = questions.get(questionId); + return q != null ? q.getDefeatMessage() : "К сожалению, вы проиграли."; + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/khmelov/cmd/Command.java b/src/main/java/com/javarush/khmelov/cmd/Command.java deleted file mode 100644 index fd4035b..0000000 --- a/src/main/java/com/javarush/khmelov/cmd/Command.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.javarush.khmelov.cmd; - -import jakarta.servlet.http.HttpServletRequest; - -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public interface Command { - - default String doGet(HttpServletRequest request) { - return getView(); - } - - default String doPost(HttpServletRequest request) { - return getView(); - } - - default String getView() { - String simpleName = this.getClass().getSimpleName(); - return convertCamelCaseToKebabStyle(simpleName); - } - - private static String convertCamelCaseToKebabStyle(String string) { - String snakeName = string.chars() - .mapToObj(s -> String.valueOf((char) s)) - .flatMap(s -> s.matches("[A-Z]") - ? Stream.of("-", s) - : Stream.of(s)) - .collect(Collectors.joining()) - .toLowerCase(); - return snakeName.startsWith("-") - ? snakeName.substring(1) - : snakeName; - } - - -} diff --git a/src/main/java/com/javarush/khmelov/cmd/EditUser.java b/src/main/java/com/javarush/khmelov/cmd/EditUser.java deleted file mode 100644 index ae191b4..0000000 --- a/src/main/java/com/javarush/khmelov/cmd/EditUser.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.javarush.khmelov.cmd; - -import com.javarush.khmelov.entity.Role; -import com.javarush.khmelov.entity.User; -import com.javarush.khmelov.service.UserService; -import jakarta.servlet.http.HttpServletRequest; - -import java.util.Optional; - - -@SuppressWarnings("unused") -public class EditUser implements Command { - - private final UserService userService; - - public EditUser(UserService userService) { - this.userService = userService; - } - - - @Override - public String doGet(HttpServletRequest req) { - String stringId = req.getParameter("id"); - if (stringId != null) { - long id = Long.parseLong(stringId); - Optional optionalUser = userService.get(id); - if (optionalUser.isPresent()) { - User user = optionalUser.get(); - req.setAttribute("user", user); - } - } - return getView(); - } - - @Override - public String doPost(HttpServletRequest req) { - User user = User.builder() - .login(req.getParameter("login")) - .password(req.getParameter("password")) - .role(Role.valueOf(req.getParameter("role"))) - .build(); - if (req.getParameter("create") != null) { - userService.create(user); - } else if (req.getParameter("update") != null) { - user.setId(Long.parseLong(req.getParameter("id"))); - userService.update(user); - } - return getView() + "?id=" + user.getId(); - } - - -} \ No newline at end of file diff --git a/src/main/java/com/javarush/khmelov/cmd/ListUser.java b/src/main/java/com/javarush/khmelov/cmd/ListUser.java deleted file mode 100644 index 9257917..0000000 --- a/src/main/java/com/javarush/khmelov/cmd/ListUser.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.javarush.khmelov.cmd; - -import com.javarush.khmelov.entity.User; -import com.javarush.khmelov.service.UserService; -import jakarta.servlet.http.HttpServletRequest; - -import java.util.Collection; - -@SuppressWarnings("unused") -public class ListUser implements Command { - - private final UserService userService; - - public ListUser(UserService userService) { - this.userService = userService; - } - - @Override - public String doGet(HttpServletRequest request) { - Collection users = userService.getAll(); - request.setAttribute("users", users); - return getView(); - } - - -} \ No newline at end of file diff --git a/src/main/java/com/javarush/khmelov/cmd/StartPage.java b/src/main/java/com/javarush/khmelov/cmd/StartPage.java deleted file mode 100644 index d268f93..0000000 --- a/src/main/java/com/javarush/khmelov/cmd/StartPage.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.javarush.khmelov.cmd; - -@SuppressWarnings("unused") -public class StartPage implements Command { - -} diff --git a/src/main/java/com/javarush/khmelov/config/Winter.java b/src/main/java/com/javarush/khmelov/config/Winter.java deleted file mode 100644 index 48bd8a7..0000000 --- a/src/main/java/com/javarush/khmelov/config/Winter.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.javarush.khmelov.config; - -import lombok.SneakyThrows; - -import java.lang.reflect.Constructor; -import java.util.concurrent.ConcurrentHashMap; - -public class Winter { - - public static ConcurrentHashMap, Object> components = new ConcurrentHashMap<>(); - - - @SuppressWarnings("unchecked") - @SneakyThrows - public static T find(Class aClass) { - Object component = components.get(aClass); - if (component == null) { - Constructor constructor = aClass.getConstructors()[0]; - Class[] parameterTypes = constructor.getParameterTypes(); - Object[] parameters = new Object[parameterTypes.length]; - for (int i = 0; i < parameters.length; i++) { - parameters[i] = Winter.find(parameterTypes[i]); - } - Object newInstance = constructor.newInstance(parameters); - components.put(aClass, newInstance); - } - return (T) components.get(aClass); - } -} diff --git a/src/main/java/com/javarush/khmelov/controller/FrontController.java b/src/main/java/com/javarush/khmelov/controller/FrontController.java deleted file mode 100644 index 33242b2..0000000 --- a/src/main/java/com/javarush/khmelov/controller/FrontController.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.javarush.khmelov.controller; - -import com.javarush.khmelov.cmd.Command; -import com.javarush.khmelov.config.Winter; -import com.javarush.khmelov.entity.Role; -import jakarta.servlet.ServletConfig; -import jakarta.servlet.ServletException; -import jakarta.servlet.annotation.WebServlet; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -import java.io.IOException; - -@WebServlet({"", "/home", "/list-user", "/edit-user"}) -public class FrontController extends HttpServlet { - - private final HttpResolver httpResolver = Winter.find(HttpResolver.class); - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - Command command = httpResolver.resolve(req); - String view = command.doGet(req); - String jsp = getJsp(view); - req.getRequestDispatcher(jsp).forward(req, resp); - } - - @Override - public void init(ServletConfig config) { - config.getServletContext().setAttribute("roles", Role.values()); - } - - private static String getJsp(String view) { - return "/WEB-INF/" + view + ".jsp"; - } - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - Command command = httpResolver.resolve(req); - String redirect = command.doPost(req); - resp.sendRedirect(redirect); - } -} diff --git a/src/main/java/com/javarush/khmelov/controller/HttpResolver.java b/src/main/java/com/javarush/khmelov/controller/HttpResolver.java deleted file mode 100644 index 18bb761..0000000 --- a/src/main/java/com/javarush/khmelov/controller/HttpResolver.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.javarush.khmelov.controller; - -import com.javarush.khmelov.cmd.Command; -import com.javarush.khmelov.config.Winter; -import jakarta.servlet.http.HttpServletRequest; - -public class HttpResolver { - - public Command resolve(HttpServletRequest request) { - // /cmd-example - try { - String requestURI = request.getRequestURI(); - requestURI = requestURI.equals("/") ? "/start-page" : requestURI; - String kebabName = requestURI.split("[?#/]")[1]; - String simpleName = convertKebabStyleToCamelCase(kebabName); - String fullName = Command.class.getPackageName() + "." + simpleName; - Class aClass = Class.forName(fullName); - return (Command) Winter.find(aClass); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - } - - private String convertKebabStyleToCamelCase(String input) { - StringBuilder result = new StringBuilder(); - boolean capitalizeNext = true; - for (char c : input.toCharArray()) { - if (c == '-') { - capitalizeNext = true; - } else { - if (capitalizeNext) { - result.append(Character.toUpperCase(c)); - capitalizeNext = false; - } else { - result.append(Character.toLowerCase(c)); - } - } - } - return result.toString(); - } -} diff --git a/src/main/java/com/javarush/khmelov/entity/Role.java b/src/main/java/com/javarush/khmelov/entity/Role.java deleted file mode 100644 index 5ae365f..0000000 --- a/src/main/java/com/javarush/khmelov/entity/Role.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.javarush.khmelov.entity; - -public enum Role { - USER, ADMIN, GUEST -} diff --git a/src/main/java/com/javarush/khmelov/entity/User.java b/src/main/java/com/javarush/khmelov/entity/User.java deleted file mode 100644 index f7fa2d6..0000000 --- a/src/main/java/com/javarush/khmelov/entity/User.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.javarush.khmelov.entity; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class User { - - private Long id; - - private String login; - - private String password; - - private Role role; - - public String getImage() { //TODO move to DTO - return "image-" + id; - } - -} diff --git a/src/main/java/com/javarush/khmelov/repository/Repository.java b/src/main/java/com/javarush/khmelov/repository/Repository.java deleted file mode 100644 index f1abdac..0000000 --- a/src/main/java/com/javarush/khmelov/repository/Repository.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.javarush.khmelov.repository; - -import com.javarush.khmelov.entity.User; - -import java.util.Collection; -import java.util.Optional; - -public interface Repository { - - Collection getAll(); - - Optional get(long id); - - void create(T entity); - - void update(T entity); - - void delete(T entity); -} diff --git a/src/main/java/com/javarush/khmelov/repository/UserRepository.java b/src/main/java/com/javarush/khmelov/repository/UserRepository.java deleted file mode 100644 index 58b32ea..0000000 --- a/src/main/java/com/javarush/khmelov/repository/UserRepository.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.javarush.khmelov.repository; - -import com.javarush.khmelov.entity.Role; -import com.javarush.khmelov.entity.User; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicLong; - -public class UserRepository implements Repository { - - private final Map map = new HashMap<>(); - - public static final AtomicLong id = new AtomicLong(System.currentTimeMillis()); - - public UserRepository() { - map.put(1L, new User(1L, "Alisa", "qwerty", Role.USER)); - map.put(2L, new User(2L, "Bob", "", Role.GUEST)); - map.put(3L, new User(3L, "Carl", "admin", Role.ADMIN)); - map.put(4L, new User(4L, "Khmelov", "admin", Role.ADMIN)); - } - - @Override - public Collection getAll() { - return map.values(); - } - - @Override - public Optional get(long id) { - return Optional.ofNullable(map.get(id)); - } - - @Override - public void create(User entity) { - entity.setId(id.incrementAndGet()); - update(entity); - } - - @Override - public void update(User entity) { - map.put(entity.getId(), entity); - } - - @Override - public void delete(User entity) { - map.remove(entity.getId()); - } -} diff --git a/src/main/java/com/javarush/khmelov/service/UserService.java b/src/main/java/com/javarush/khmelov/service/UserService.java deleted file mode 100644 index b17527c..0000000 --- a/src/main/java/com/javarush/khmelov/service/UserService.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.javarush.khmelov.service; - -import com.javarush.khmelov.entity.User; -import com.javarush.khmelov.repository.UserRepository; - -import java.util.Collection; -import java.util.Optional; - -public class UserService { - - private final UserRepository userRepository; - - public UserService(UserRepository userRepository) { - this.userRepository = userRepository; - } - - public void create(User user) { - userRepository.create(user); - } - - public void update(User user) { - userRepository.update(user); - } - - public void delete(User user) { - userRepository.delete(user); - } - - public Collection getAll() { - return userRepository.getAll(); - } - - public Optional get(long id) { - return userRepository.get(id); - } -} diff --git a/src/main/webapp/WEB-INF/edit-user.jsp b/src/main/webapp/WEB-INF/edit-user.jsp deleted file mode 100644 index f274104..0000000 --- a/src/main/webapp/WEB-INF/edit-user.jsp +++ /dev/null @@ -1,73 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" language="java" %> -<%@include file="head.jsp" %> - -
-
-
- - - Edit user: - - -
- -
- - min 3 symbols -
-
- - -
- -
- - min 8 symb -
-
- - - -
- -
- -
-
- - -
- -
- - - - - - - -
-
- -
-
-
- - diff --git a/src/main/webapp/WEB-INF/head.jsp b/src/main/webapp/WEB-INF/head.jsp deleted file mode 100644 index 2f7b9f2..0000000 --- a/src/main/webapp/WEB-INF/head.jsp +++ /dev/null @@ -1,11 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" language="java" %> -<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> - - - Title - - - \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/list-user.jsp b/src/main/webapp/WEB-INF/list-user.jsp deleted file mode 100644 index dd52c55..0000000 --- a/src/main/webapp/WEB-INF/list-user.jsp +++ /dev/null @@ -1,9 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" language="java" %> -<%@include file="head.jsp"%> - - - ${user.login} - - - - diff --git a/src/main/webapp/WEB-INF/start-page.jsp b/src/main/webapp/WEB-INF/start-page.jsp deleted file mode 100644 index 0531c1c..0000000 --- a/src/main/webapp/WEB-INF/start-page.jsp +++ /dev/null @@ -1,8 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" language="java" %> -<%@include file="head.jsp"%> - -

<%= "Hello World!" %> -

-
-List Users - diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 0bf2fcb..76229a1 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -1,6 +1,21 @@ + + Text Quest + + + index.jsp + + + + 30 + + + default + /favicon.ico + \ No newline at end of file diff --git a/src/main/webapp/game.jsp b/src/main/webapp/game.jsp new file mode 100644 index 0000000..be671e7 --- /dev/null +++ b/src/main/webapp/game.jsp @@ -0,0 +1,163 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="c" uri="jakarta.tags.core" %> + + + + ${quest.title} - Игра + + + +
+
+
+ ${quest.genre} • Сложность: + + + + + + +
+
+ ${sessionScope.gameState.playerName} | + Побед: ${sessionScope.gameState.wins} | + Поражений: ${sessionScope.gameState.losses} +
+
+ +

${quest.title}

+ +
+ +
+ +
+
+ + +
+
+ +
+
+
${question.id}
+
Текущий шаг
+
+
+
${sessionScope.gameState.gamesPlayed}
+
Всего игр
+
+
+ + +
+ + \ No newline at end of file diff --git a/src/main/webapp/images/cat.png b/src/main/webapp/images/cat.png deleted file mode 100644 index 41771a1..0000000 Binary files a/src/main/webapp/images/cat.png and /dev/null differ diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp new file mode 100644 index 0000000..61d7fc2 --- /dev/null +++ b/src/main/webapp/index.jsp @@ -0,0 +1,100 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + + Поиск сокровищ в замке + + + +
+

Поиск сокровищ в заброшенном замке

+ +
+

Легенда

+

Глубоко в лесах Трансильвании стоит древний замок графа Дракулы. + Говорят, что в его подземельях спрятаны несметные сокровища, но + каждый, кто пытался их найти, исчезал бесследно...

+ +

Сегодня вы решили бросить вызов судьбе и отправиться на поиски + сокровищ. Сможете ли вы пережить эту ночь и найти золото, или + станете еще одной жертвой проклятого замка?

+ +

Приготовьтесь к приключениям! Каждое ваше решение + может стать решающим.

+
+ +
+
+ + +
+ +
+
+ + \ No newline at end of file diff --git a/src/main/webapp/quest-selection.jsp b/src/main/webapp/quest-selection.jsp new file mode 100644 index 0000000..ca9bc93 --- /dev/null +++ b/src/main/webapp/quest-selection.jsp @@ -0,0 +1,181 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="c" uri="jakarta.tags.core" %> +<%@ taglib prefix="fmt" uri="jakarta.tags.fmt" %> + + + + Выберите приключение + + + +
+
+

Добро пожаловать, ${sessionScope.gameState.playerName}!

+

Сыграно игр: ${sessionScope.gameState.gamesPlayed} | + Побед: ${sessionScope.gameState.wins} | + Поражений: ${sessionScope.gameState.losses}

+
+ +

Выберите свое приключение

+ +
+ +
+
+ +
+
+

${quest.title}

+
+ ${quest.genre} + + Сложность: + + + + + + + + + +
+

${quest.description}

+
+ 👥 Прохождений: ${questStats[quest.id]} + +
+
+
+
+
+
+ + + + + + \ No newline at end of file diff --git a/src/main/webapp/result.jsp b/src/main/webapp/result.jsp new file mode 100644 index 0000000..b3e662e --- /dev/null +++ b/src/main/webapp/result.jsp @@ -0,0 +1,184 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="c" uri="jakarta.tags.core" %> + + + + Результат игры + + + +
+ + +
🏆
+
ПОБЕДА!
+
+ +
💀
+
ПОРАЖЕНИЕ
+
+
+ +
+ +
+ +
+ +
+ +
+
+
Всего игр
+
${sessionScope.gameState.gamesPlayed}
+
+
+
Победы
+
${sessionScope.gameState.wins}
+
+
+
Поражения
+
${sessionScope.gameState.losses}
+
+
+ + +
+ + \ No newline at end of file diff --git a/src/test/java/com/javarush/buslovskii/model/QuestTest.java b/src/test/java/com/javarush/buslovskii/model/QuestTest.java new file mode 100644 index 0000000..002adb0 --- /dev/null +++ b/src/test/java/com/javarush/buslovskii/model/QuestTest.java @@ -0,0 +1,367 @@ +package com.javarush.buslovskii.model; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +class QuestTest { + + private QuestManager questManager; + + @BeforeEach + void setUp() { + questManager = QuestManager.getInstance(); + resetQuestStats(); + } + + @AfterEach + void tearDown() { + resetQuestStats(); + } + + private void resetQuestStats() { + try { + java.lang.reflect.Field statsField = QuestManager.class.getDeclaredField("questStats"); + statsField.setAccessible(true); + java.util.Map stats = (java.util.Map) statsField.get(questManager); + stats.clear(); + } catch (Exception ignored) { + } + } + + @Test + void testQuestManagerInitialization() { + List quests = questManager.getAllQuests(); + assertNotNull(quests, "Quests list should not be null"); + assertFalse(quests.isEmpty(), "Should have at least 1 quest"); + assertTrue(quests.size() >= 3, "Should have at least 3 quests"); + } + + @Test + void testGetQuestById() { + Quest treasureQuest = questManager.getQuest("treasure-hunt"); + assertNotNull(treasureQuest, "Treasure hunt quest should exist"); + assertEquals("Поиск сокровищ в замке", treasureQuest.getTitle(), "Treasure hunt quest title"); + + Quest spaceQuest = questManager.getQuest("space-adventure"); + assertNotNull(spaceQuest, "Space adventure quest should exist"); + assertEquals("Sci-Fi/Выживание", spaceQuest.getGenre(), "Space adventure quest genre"); + + Quest detectiveQuest = questManager.getQuest("detective-story"); + assertNotNull(detectiveQuest, "Detective story quest should exist"); + assertEquals(5, detectiveQuest.getDifficultyLevel(), "Detective story difficulty"); + } + + @Test + void testGetNonExistentQuest() { + Quest nonExistent = questManager.getQuest("non-existent"); + assertNull(nonExistent, "Non-existent quest should return null"); + } + + @Test + void testTreasureHuntQuestQuestions() { + Quest quest = questManager.getQuest("treasure-hunt"); + assertNotNull(quest, "Treasure hunt quest should exist"); + + Question startQuestion = quest.getStartQuestion(); + assertNotNull(startQuestion, "Start question should exist"); + assertEquals(1, startQuestion.getId(), "Start question ID should be 1"); + assertNotNull(startQuestion.getText(), "Start question text should not be null"); + assertNotNull(startQuestion.getOption1(), "Option 1 should not be null"); + assertNotNull(startQuestion.getOption2(), "Option 2 should not be null"); + + Map questions = quest.getQuestions(); + assertNotNull(questions, "Questions map should not be null"); + assertFalse(questions.isEmpty(), "Questions map should not be empty"); + assertTrue(questions.size() >= 10, "Should have multiple questions"); + } + + @Test + void testSpaceAdventureQuestQuestions() { + Quest quest = questManager.getQuest("space-adventure"); + assertNotNull(quest, "Space adventure quest should exist"); + + Question startQuestion = quest.getStartQuestion(); + assertNotNull(startQuestion, "Start question should exist"); + assertEquals("Ваш космический корабль терпит крушение на неизвестной планете. Что делать?", + startQuestion.getText(), + "Start question text should match"); + } + + @Test + void testDetectiveStoryQuestQuestions() { + Quest quest = questManager.getQuest("detective-story"); + assertNotNull(quest, "Detective story quest should exist"); + + Question startQuestion = quest.getStartQuestion(); + assertNotNull(startQuestion, "Start question should exist"); + assertTrue(startQuestion.getText().contains("детектив"), + "Start question text should contain detective theme" + ); + } + + @Test + void testTreasureHuntVictoryConditions() { + Quest quest = questManager.getQuest("treasure-hunt"); + + // Проверяем победные вопросы + assertTrue(quest.isVictory(7), "Question 7 should be victory"); + assertTrue(quest.isVictory(8), "Question 8 should be victory"); + assertTrue(quest.isVictory(9), "Question 9 should be victory"); + assertTrue(quest.isVictory(12), "Question 12 should be victory"); + + assertFalse(quest.isVictory(10), "Question 10 should not be victory"); + assertFalse(quest.isVictory(11), "Question 11 should not be victory"); + + assertNotNull("Victory message for question 7 should exist", + quest.getVictoryMessage(7)); + assertNotNull("Defeat message for question 10 should exist", + quest.getDefeatMessage(10)); + + assertFalse(quest.getVictoryMessage(7).isEmpty(), + "Victory message should not be empty"); + assertFalse(quest.getDefeatMessage(10).isEmpty(), + "Defeat message should not be empty"); + } + + @Test + void testSpaceAdventureVictoryConditions() { + Quest quest = questManager.getQuest("space-adventure"); + + assertTrue(quest.isVictory(7), "Question 7 should be victory"); + assertTrue(quest.isVictory(9), "Question 9 should be victory"); + + assertFalse(quest.isVictory(6), "Question 6 should not be victory"); + assertFalse(quest.isVictory(8), "Question 8 should not be victory"); + assertFalse(quest.isVictory(10), "Question 10 should not be victory"); + + assertEquals("Вы успешно вернулись на Землю и стали героем!", + quest.getVictoryMessage(7), "Victory message for question 7"); + assertEquals("Корабль уничтожен. Вы погибли.", + quest.getDefeatMessage(6), "Defeat message for question 6" + ); + } + + @Test + void testDetectiveStoryVictoryConditions() { + Quest quest = questManager.getQuest("detective-story"); + + assertTrue(quest.isVictory(7), "Question 7 should be victory"); + assertTrue(quest.isVictory(9), "Question 9 should be victory"); + assertTrue(quest.isVictory(12), "Question 12 should be victory"); + + assertFalse(quest.isVictory(8), "Question 8 should not be victory"); + assertFalse(quest.isVictory(10), "Question 10 should not be victory"); + assertFalse(quest.isVictory(11), "Question 11 should not be victory"); + } + + @Test + void testQuestStats() { + String questId = "detective-story"; + + int initialPlays = questManager.getQuestPlays(questId); + assertEquals(0, initialPlays, "Initial plays should be 0"); + + questManager.incrementQuestPlays(questId); + assertEquals(1, questManager.getQuestPlays(questId), "Quest plays should increment to 1"); + + questManager.incrementQuestPlays(questId); + assertEquals(2, questManager.getQuestPlays(questId), "Quest plays should increment to 2"); + + assertEquals(0, questManager.getQuestPlays("treasure-hunt"), "Other quest plays should be 0"); + } + + @Test + void testGetAllQuestStats() { + questManager.incrementQuestPlays("treasure-hunt"); + questManager.incrementQuestPlays("treasure-hunt"); + questManager.incrementQuestPlays("space-adventure"); + + Map allStats = questManager.getAllQuestStats(); + assertNotNull(allStats, "Stats map should not be null"); + + assertEquals(2, allStats.get("treasure-hunt").intValue(), "Treasure hunt plays"); + assertEquals(1, allStats.get("space-adventure").intValue(), "Space adventure plays"); + + // Детективный квест должен быть 0 или отсутствовать + Integer detectivePlays = allStats.get("detective-story"); + assertTrue(detectivePlays == null || detectivePlays == 0, + "Detective story plays should be 0 or null"); + } + + @Test + void testFilterQuestsByGenre() { + List horrorQuests = questManager.getQuestsByGenre("Хоррор/Приключения"); + assertNotNull(horrorQuests, "Horror quests list should not be null"); + assertFalse(horrorQuests.isEmpty(), "Should find horror quests"); + + boolean foundTreasureHunt = false; + for (Quest q : horrorQuests) { + if ("treasure-hunt".equals(q.getId())) { + foundTreasureHunt = true; + break; + } + } + assertTrue(foundTreasureHunt, "Treasure hunt should be in horror genre"); + + List sciFiQuests = questManager.getQuestsByGenre("Sci-Fi/Выживание"); + assertNotNull(sciFiQuests, "Sci-Fi quests list should not be null"); + assertFalse(sciFiQuests.isEmpty(), "Should find sci-fi quests"); + + List nonExistentGenre = questManager.getQuestsByGenre("Non-existent"); + assertNotNull(nonExistentGenre, "Non-existent genre should return empty list"); + assertTrue(nonExistentGenre.isEmpty(), "Non-existent genre should return empty list"); + } + + @Test + void testFilterQuestsByDifficulty() { + List difficulty3Quests = questManager.getQuestsByDifficulty(3); + assertNotNull(difficulty3Quests, "Difficulty 3 quests list should not be null"); + assertFalse(difficulty3Quests.isEmpty(), "Should find difficulty 3 quests"); + + boolean foundTreasureHunt = false; + for (Quest q : difficulty3Quests) { + if ("treasure-hunt".equals(q.getId())) { + foundTreasureHunt = true; + break; + } + } + assertTrue(foundTreasureHunt, "Treasure hunt should be difficulty 3"); + + List difficulty5Quests = questManager.getQuestsByDifficulty(5); + assertNotNull(difficulty5Quests, "Difficulty 5 quests list should not be null"); + assertFalse(difficulty5Quests.isEmpty(), "Should find difficulty 5 quests"); + + List nonExistentDifficulty = questManager.getQuestsByDifficulty(10); + assertNotNull(nonExistentDifficulty, "Non-existent difficulty should return empty list"); + assertTrue(nonExistentDifficulty.isEmpty(), "Non-existent difficulty should return empty list"); + } + + @Test + void testGameState() { + GameState gameState = new GameState(); + + assertEquals(1, gameState.getCurrentQuestionId(), "Initial question should be 1"); + assertFalse(gameState.isGameOver(), "Game should not be over initially"); + assertFalse(gameState.isVictory(), "Game should not be victory initially"); + assertEquals(0, gameState.getGamesPlayed(), "Games played should start at 0"); + assertEquals(0, gameState.getWins(), "Wins should start at 0"); + assertEquals(0, gameState.getLosses(), "Losses should start at 0"); + + gameState.setPlayerName("TestPlayer"); + assertEquals("TestPlayer", gameState.getPlayerName(),"Player name should be set correctly"); + + gameState.setCurrentQuestId("test-quest"); + assertEquals("test-quest", gameState.getCurrentQuestId(),"Quest ID should be set correctly"); + + gameState.addWin(); + gameState.addWin(); + assertEquals(2, gameState.getWins(), "Wins should be 2"); + + gameState.addLoss(); + assertEquals(1, gameState.getLosses(), "Losses should be 1"); + + gameState.incrementGamesPlayed(); + assertEquals(1, gameState.getGamesPlayed(), "Games played should be 1"); + + gameState.setGameOver(true); + assertTrue(gameState.isGameOver(), "Game should be over"); + + gameState.setVictory(true); + assertTrue(gameState.isVictory(), "Game should be victory"); + } + + @Test + void testQuestionModel() { + Question question = new Question(1, "Test question", "Option A", "Option B", 2, 3); + + assertEquals(1, question.getId(), "ID should be 1"); + assertEquals("Test question", question.getText(), "Text should match"); + assertEquals("Option A", question.getOption1(), "Option 1 should match"); + assertEquals("Option B", question.getOption2(), "Option 2 should match"); + assertEquals(2, question.getNextIdOption1(), "Next ID for option 1 should be 2"); + assertEquals(3, question.getNextIdOption2(), "Next ID for option 2 should be 3"); + assertFalse(question.isFinal(), "Should not be final by default"); + assertNull(question.getVictoryMessage(), "Victory message should be null"); + assertNull(question.getDefeatMessage(), "Defeat message should be null"); + + Question finalQuestion = new Question(2, "Final", "Restart", "Exit", 1, 1, true, "You win!", "You lose!"); + + assertTrue(finalQuestion.isFinal(), "Should be final"); + assertEquals("You win!", finalQuestion.getVictoryMessage(), "Victory message should match"); + assertEquals("You lose!", finalQuestion.getDefeatMessage(), "Defeat message should match"); + } + + + @Test + void testTreasureHuntGamePathToVictory() { + Quest quest = questManager.getQuest("treasure-hunt"); + Map questions = quest.getQuestions(); + + int currentId = 1; + + Question q1 = questions.get(currentId); + currentId = q1.getNextIdOption2(); + assertEquals(3, currentId, "Should be at question 3"); + + Question q3 = questions.get(currentId); + currentId = q3.getNextIdOption1(); + assertEquals(6, currentId, "Should be at question 6"); + + Question q6 = questions.get(currentId); + currentId = q6.getNextIdOption2(); + assertEquals(12, currentId, "Should be at question 12"); + + Question finalQuestion = questions.get(currentId); + assertTrue(finalQuestion.isFinal(), "Should be final question"); + assertTrue(quest.isVictory(currentId), "Should be victory"); + } + + @Test + void testTreasureHuntGamePathToDefeat() { + Quest quest = questManager.getQuest("treasure-hunt"); + Map questions = quest.getQuestions(); + + int currentId = 1; + + Question q1 = questions.get(currentId); + currentId = q1.getNextIdOption1(); + assertEquals(2, currentId, "Should be at question 2"); + + Question q2 = questions.get(currentId); + currentId = q2.getNextIdOption2(); + assertEquals(5, currentId, "Should be at question 5"); + + Question q5 = questions.get(currentId); + currentId = q5.getNextIdOption2(); + assertEquals(10, currentId, "Should be at question 10"); + + Question finalQuestion = questions.get(currentId); + assertTrue(finalQuestion.isFinal(), "Should be final question"); + assertFalse(quest.isVictory(currentId), "Should not be victory"); + } + + @Test + void testSpaceAdventureGamePaths() { + Quest quest = questManager.getQuest("space-adventure"); + Map questions = quest.getQuestions(); + + int victoryId = 1; + victoryId = questions.get(victoryId).getNextIdOption1(); + victoryId = questions.get(victoryId).getNextIdOption1(); + victoryId = questions.get(victoryId).getNextIdOption1(); + + assertTrue(quest.isVictory(victoryId), "Should be victory"); + + int defeatId = 1; + defeatId = questions.get(defeatId).getNextIdOption2(); + defeatId = questions.get(defeatId).getNextIdOption2(); + + assertFalse(quest.isVictory(defeatId), "Should not be victory"); + } +} \ No newline at end of file