diff --git a/Eugene-JR/Dockerfile b/Eugene-JR/Dockerfile new file mode 100644 index 0000000..881b1a2 --- /dev/null +++ b/Eugene-JR/Dockerfile @@ -0,0 +1,13 @@ +FROM maven:3.8.5-openjdk-17 AS build +WORKDIR /app +COPY pom.xml . +COPY src ./src +RUN mvn clean package -DskipTests + + +FROM tomcat:9.0-jdk17 + +# @TODO Replace Oleksandr-JR-Example.war with your app name +COPY --from=build /app/target/Eugene-JR-M3.war /usr/local/tomcat/webapps/ROOT.war +EXPOSE 8080 +CMD ["catalina.sh", "run"] \ No newline at end of file diff --git a/Eugene-JR/README.md b/Eugene-JR/README.md new file mode 100644 index 0000000..7bde3c5 --- /dev/null +++ b/Eugene-JR/README.md @@ -0,0 +1,7 @@ + +Quest Description: "Shadow of the Past" +You and your team receive a mysterious letter inviting you to an abandoned mansion on the outskirts of the city. The letter is signed by the famous historian Artem Lysenko, who mysteriously disappeared 20 years ago. In the letter, he claims to have uncovered evidence of an ancient conspiracy that could change history forever. +As you step inside the eerie mansion, the doors creak shut behind you. The air is thick with the scent of old books, and the dim candlelight barely illuminates the grand hallway. The walls whisper secrets of the past, and every room holds hidden clues, puzzles, and dangers. + +Your choices will determine the outcome of the story. Will you uncover the truth, or will you fall victim to the mysteries lurking in the shadows? +Access quest-game via the link - https://m3-quest-eugene.onrender.com/ \ No newline at end of file diff --git a/Eugene-JR/pom.xml b/Eugene-JR/pom.xml new file mode 100644 index 0000000..a5fdb24 --- /dev/null +++ b/Eugene-JR/pom.xml @@ -0,0 +1,112 @@ + + 4.0.0 + org.taco + Eugene-JR + war + 1.0-SNAPSHOT + Eugene-JR Maven Webapp + http://maven.apache.org + + + 17 + + 1.18.36 + 3.12.0 + + 5.12.0 + + 4.0.1 + 3.0.1 + 1.2 + + ${java.version} + ${java.version} + 3.3.2 + + + + + + + + junit + junit + 3.8.1 + test + + + + javax.servlet + javax.servlet-api + ${javax.servlet-api.version} + provided + + + + javax.servlet + jstl + ${jstl.version} + + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter-engine.version} + test + + + + org.projectlombok + lombok + ${lombok.version} + + + + org.glassfish.web + jakarta.servlet.jsp.jstl + ${jakarta.servlet.jsp.jstl.version} + + + + jakarta.servlet.jsp.jstl + jakarta.servlet.jsp.jstl-api + ${jakarta.servlet.jsp.jstl.version} + + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + + Eugene-JR-M3 + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.9.0 + + ${java.version} + ${java.version} + + + org.projectlombok + lombok + ${lombok.version} + + + + + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + + + + diff --git a/Eugene-JR/src/main/java/controller/QuizServlet.java b/Eugene-JR/src/main/java/controller/QuizServlet.java new file mode 100644 index 0000000..e46045e --- /dev/null +++ b/Eugene-JR/src/main/java/controller/QuizServlet.java @@ -0,0 +1,46 @@ +package controller; + +import model.Scene; +import service.QuizService; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +@WebServlet("/quiz") +public class QuizServlet extends HttpServlet { + + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + HttpSession session = request.getSession(); + QuizService quizService = (QuizService) session.getAttribute("quizService"); + + if (quizService == null || request.getParameter("restart") != null) { + quizService = new QuizService(); + session.setAttribute("quizService", quizService); + } + + Scene currentScene = quizService.getCurrentScene(); + request.setAttribute("scene", currentScene); + request.getRequestDispatcher("quiz.jsp").forward(request, response); + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + HttpSession session = request.getSession(); + QuizService quizService = (QuizService) session.getAttribute("quizService"); + + int answer = Integer.parseInt(request.getParameter("answer")); + Scene currentScene = quizService.makeStep(answer); + session.setAttribute("currentScene", currentScene); + + request.setAttribute("scene", currentScene); + request.setAttribute("questions", currentScene.getQuestions()); + request.getRequestDispatcher("quiz.jsp").forward(request, response); + } +} diff --git a/Eugene-JR/src/main/java/controller/RestartServlet.java b/Eugene-JR/src/main/java/controller/RestartServlet.java new file mode 100644 index 0000000..ad89f51 --- /dev/null +++ b/Eugene-JR/src/main/java/controller/RestartServlet.java @@ -0,0 +1,19 @@ +package controller; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +@WebServlet("/restart") +public class RestartServlet extends HttpServlet { + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + HttpSession session = req.getSession(); + session.invalidate(); + resp.sendRedirect("quiz"); + } +} diff --git a/Eugene-JR/src/main/java/model/Question.java b/Eugene-JR/src/main/java/model/Question.java new file mode 100644 index 0000000..cea4638 --- /dev/null +++ b/Eugene-JR/src/main/java/model/Question.java @@ -0,0 +1,18 @@ +package model; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.List; + +@Data +@AllArgsConstructor +public class Question { + + private String name; + private Scene nextScene; + + public Question(String name) { + this.name = name; + } +} diff --git a/Eugene-JR/src/main/java/model/Scene.java b/Eugene-JR/src/main/java/model/Scene.java new file mode 100644 index 0000000..6546ec9 --- /dev/null +++ b/Eugene-JR/src/main/java/model/Scene.java @@ -0,0 +1,26 @@ +package model; + +import lombok.*; + +import java.util.List; +@Data +public class Scene { + + private String name; + private List questions; + private boolean isFinal = false; + + public Scene(String name) { + this.name = name; + } + + public Scene setFinal(){ + isFinal = true; + return this; + } + + @Override + public String toString() { + return "Question{text='" + name+" }"; + } +} diff --git a/Eugene-JR/src/main/java/repository/QuizRepository.java b/Eugene-JR/src/main/java/repository/QuizRepository.java new file mode 100644 index 0000000..8e2b5e9 --- /dev/null +++ b/Eugene-JR/src/main/java/repository/QuizRepository.java @@ -0,0 +1,109 @@ +package repository; + +import lombok.Data; +import model.Question; +import model.Scene; + +import java.util.Arrays; + +@Data +public class QuizRepository { + private static QuizRepository INSTANCE; + + // Локації квесту + private Scene scene1 = new Scene("Біля входу до маєтку"); + private Scene scene2 = new Scene("Велика зала"); + private Scene scene3 = new Scene("Стара бібліотека"); + private Scene scene4 = new Scene("Темний підвал"); + private Scene scene5 = new Scene("Залізні сходи"); + private Scene scene6 = new Scene("Музична кімната"); + private Scene scene7 = new Scene("Секретний прохід"); + private Scene scene8 = new Scene("Горище"); + private Scene scene9 = new Scene("Старий сад"); + private Scene scene10 = new Scene("Покинута каплиця"); + + // Фінальні сцени + private Scene sceneEnd1 = new Scene("Перемога! Ви розкрили таємницю маєтку Лисенка і знайшли скарб.").setFinal(); + private Scene sceneEnd2 = new Scene("Поразка... Ви зачепили старий механізм, і стеля обвалилася.").setFinal(); + private Scene sceneEnd3 = new Scene("Нейтральна кінцівка. Ви залишилися в маєтку, зачаровані його музикою.").setFinal(); + + private QuizRepository() { + scene1.setQuestions( + Arrays.asList( + new Question("Зайти в маєток", scene2), + new Question("Обійти будівлю навколо", scene9) + ) + ); + + scene2.setQuestions( + Arrays.asList( + new Question("Піти до бібліотеки", scene3), + new Question("Спуститися в підвал", scene4), + new Question("Дослідити сходи нагору", scene5) + ) + ); + + scene3.setQuestions( + Arrays.asList( + new Question("Відкрити стару книгу", scene7), + new Question("Оглянути нотні записи", scene6) + ) + ); + + scene4.setQuestions( + Arrays.asList( + new Question("Шукати вихід", sceneEnd2), // Поразка + new Question("Піднятися назад", scene2) + ) + ); + + scene5.setQuestions( + Arrays.asList( + new Question("Продовжити підніматися нагору", scene8), + new Question("Спуститися назад у залу", scene2) + ) + ); + + scene6.setQuestions( + Arrays.asList( + new Question("Грати на піаніно", sceneEnd3), // Нейтральний фінал + new Question("Шукати прихований механізм", scene7) + ) + ); + + scene7.setQuestions( + Arrays.asList( + new Question("Відкрити потайний хід", scene10), + new Question("Повернутися в бібліотеку", scene3) + ) + ); + + scene8.setQuestions( + Arrays.asList( + new Question("Відчинити стару скриню", sceneEnd1), // Перемога + new Question("Спуститися вниз", scene5) + ) + ); + + scene9.setQuestions( + Arrays.asList( + new Question("Дослідити старий фонтан", sceneEnd3), // Нейтральний фінал + new Question("Повернутися до входу в маєток", scene1) + ) + ); + + scene10.setQuestions( + Arrays.asList( + new Question("Оглянути вівтар", sceneEnd1), // Перемога + new Question("Залишити каплицю і повернутися", scene7) + ) + ); + } + + public static QuizRepository getInstance() { + if (INSTANCE == null) { + INSTANCE = new QuizRepository(); + } + return INSTANCE; + } +} diff --git a/Eugene-JR/src/main/java/service/QuizService.java b/Eugene-JR/src/main/java/service/QuizService.java new file mode 100644 index 0000000..52ce68f --- /dev/null +++ b/Eugene-JR/src/main/java/service/QuizService.java @@ -0,0 +1,29 @@ +package service; + +import lombok.Data; +import model.Question; +import model.Scene; +import repository.QuizRepository; + +import java.util.List; + +@Data +public class QuizService { + + private Scene currentScene; + private List scenes; + private QuizRepository quizRepository = QuizRepository.getInstance();; + + + public QuizService() { + currentScene = quizRepository.getScene1(); + } + + public Scene makeStep(int answer){ + List questions = currentScene.getQuestions(); + Question question = questions.get(answer); + currentScene = question.getNextScene(); + return currentScene; + } + +} diff --git a/Eugene-JR/src/main/webapp/WEB-INF/web.xml b/Eugene-JR/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..9f88c1f --- /dev/null +++ b/Eugene-JR/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,7 @@ + + + + Archetype Created Web Application + diff --git a/Eugene-JR/src/main/webapp/index.jsp b/Eugene-JR/src/main/webapp/index.jsp new file mode 100644 index 0000000..5020994 --- /dev/null +++ b/Eugene-JR/src/main/webapp/index.jsp @@ -0,0 +1,48 @@ +<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> + + + + + Квестова гра + + + +

Ласкаво просимо у квестову гру "Тінь минулого"

+

Група учасників отримує загадковий лист із запрошенням до старовинного маєтку на околиці міста. + Лист написаний від імені відомого історика Артема Лисенка, який зник безвісти 20 років тому. + Він стверджує, що залишив у маєтку докази давньої змови, яка може змінити історію...

+ +
+ +
+ + diff --git a/Eugene-JR/src/main/webapp/quiz.jsp b/Eugene-JR/src/main/webapp/quiz.jsp new file mode 100644 index 0000000..6db5d61 --- /dev/null +++ b/Eugene-JR/src/main/webapp/quiz.jsp @@ -0,0 +1,59 @@ +<%@ page import="model.Scene" %> +<%@ page import="model.Question" %> +<%@ page import="java.util.List" %> +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + + Квест + + + + + +

Квестова гра

+ <% + Scene scene = (Scene) request.getAttribute("scene"); + %> + +

Локація: <%= scene.getName() %>

+ + <% if (scene.isFinal()) { %> +

<%= scene.getName() %>

+
+ +
+ <% } else { %> +
+ <% + List questions = scene.getQuestions(); + if (questions != null) { + for (int i = 0; i < questions.size(); i++) { + Question question = questions.get(i); + %> + +
+ <% + } + } + %> + + + + <% } %> + + + diff --git a/Eugene-JR/src/test/java/service/QuizServiceTest.java b/Eugene-JR/src/test/java/service/QuizServiceTest.java new file mode 100644 index 0000000..01c4016 --- /dev/null +++ b/Eugene-JR/src/test/java/service/QuizServiceTest.java @@ -0,0 +1,64 @@ +package service; + +import model.Question; +import model.Scene; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import repository.QuizRepository; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; +class QuizServiceTest { + + private QuizService quizService; + private QuizRepository quizRepository; + + @BeforeEach + void setUp() { + quizRepository = QuizRepository.getInstance(); + quizService = new QuizService(); + } + + @Test + void testInitialSceneIsCorrect() { + assertEquals(quizRepository.getScene1(), quizService.getCurrentScene(), "Initial scene should be Start"); + } + + @Test + void testSceneTransition() { + Scene initialScene = quizService.getCurrentScene(); + Scene expectedScene = initialScene.getQuestions().get(0).getNextScene(); + + Scene newScene = quizService.makeStep(0); + + assertEquals(expectedScene, newScene, "After choosing the first option, the scene should change correctly"); + } + + @Test + void testInvalidStepThrowsException() { + Scene initialScene = quizService.getCurrentScene(); + int invalidIndex = initialScene.getQuestions().size(); + + Exception exception = assertThrows(IndexOutOfBoundsException.class, () -> quizService.makeStep(invalidIndex)); + + assertTrue(exception.getMessage().contains("Index"), "Exception should be thrown for an invalid choice"); + } + + @Test + void testFinalSceneDetection() { + // Перехід до фінальної сцени (наприклад, через кілька кроків) + Scene finalScene = new Scene("Перемога").setFinal(); + Scene testScene = new Scene("Test"); + testScene.setQuestions(Arrays.asList(new Question("Go to final", finalScene))); + + quizService.setCurrentScene(testScene); + + Scene newScene = quizService.makeStep(0); + + assertTrue(newScene.isFinal(), "Final scene should be detected properly"); + assertEquals(finalScene, newScene, "Final scene should be reached correctly"); + } + + +} \ No newline at end of file