From 3818c99124fab5982a2c517b3a29ce89e32304bc Mon Sep 17 00:00:00 2001 From: BevzyukIvan Date: Mon, 3 Mar 2025 00:17:28 +0200 Subject: [PATCH 1/2] Finished project v1.0 --- Bevzyuk/pom.xml | 47 ++++++ .../src/main/java/com/quest/GameServlet.java | 83 +++++++++++ Bevzyuk/src/main/java/com/quest/Question.java | 27 ++++ .../main/java/com/quest/RestartServlet.java | 15 ++ Bevzyuk/src/main/webapp/WEB-INF/web.xml | 7 + Bevzyuk/src/main/webapp/game.jsp | 48 +++++++ Bevzyuk/src/main/webapp/index.jsp | 18 +++ Bevzyuk/src/main/webapp/style.css | 134 ++++++++++++++++++ .../test/java/com/quest/GameServletTest.java | 80 +++++++++++ 9 files changed, 459 insertions(+) create mode 100644 Bevzyuk/pom.xml create mode 100644 Bevzyuk/src/main/java/com/quest/GameServlet.java create mode 100644 Bevzyuk/src/main/java/com/quest/Question.java create mode 100644 Bevzyuk/src/main/java/com/quest/RestartServlet.java create mode 100644 Bevzyuk/src/main/webapp/WEB-INF/web.xml create mode 100644 Bevzyuk/src/main/webapp/game.jsp create mode 100644 Bevzyuk/src/main/webapp/index.jsp create mode 100644 Bevzyuk/src/main/webapp/style.css create mode 100644 Bevzyuk/src/test/java/com/quest/GameServletTest.java diff --git a/Bevzyuk/pom.xml b/Bevzyuk/pom.xml new file mode 100644 index 0000000..62ef4a4 --- /dev/null +++ b/Bevzyuk/pom.xml @@ -0,0 +1,47 @@ + + 4.0.0 + org.example + Bevzyuk + war + 1.0-SNAPSHOT + Bevzyuk Maven Webapp + http://maven.apache.org + + + javax.servlet + javax.servlet-api + 3.1.0 + + + + + org.junit.jupiter + junit-jupiter-engine + 5.12.0 + test + + + + + org.mockito + mockito-core + 5.15.2 + test + + + + + Bevzyuk + + + org.apache.maven.plugins + maven-compiler-plugin + + 9 + 9 + + + + + diff --git a/Bevzyuk/src/main/java/com/quest/GameServlet.java b/Bevzyuk/src/main/java/com/quest/GameServlet.java new file mode 100644 index 0000000..1240941 --- /dev/null +++ b/Bevzyuk/src/main/java/com/quest/GameServlet.java @@ -0,0 +1,83 @@ +package com.quest; + +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; +import java.util.HashMap; +import java.util.Map; + +@WebServlet("/game") +public class GameServlet extends HttpServlet { + Map questions; + + @Override + public void init() { + questions = new HashMap<>(); + + questions.put(1, new Question("Ти стоїш перед дверима. Що робити?", Map.of( + "Відкрити двері", 2, + "Йти геть", 9 + ), false)); + + questions.put(2, new Question("Ти потрапив у темний коридор. Йти ліворуч чи праворуч?", Map.of( + "Ліворуч", 3, + "Праворуч", 4 + ), false)); + + questions.put(3, new Question("Ти знайшов стару скриню. Взяти ключ?", Map.of( + "Так", 6, + "Ні", 7 + ), false)); + + questions.put(4, new Question("Ти потрапив у пастку з шипами! Гра закінчена. 😵", Map.of(), true)); + + questions.put(6, new Question("Ти підійшов до великих воріт. Відкрити їх ключем?", Map.of( + "Відкрити", 8, + "Повернутися", 2 + ), false)); + + questions.put(7, new Question("Ти бачиш великі ворота, але вони зачинені. Що робити?", Map.of( + "Повернутися", 2, + "Сісти і чекати", 10 + ), false)); + + questions.put(8, new Question("Вітаю! Ти відкрив ворота і знайшов величезний скарб! 🏆", Map.of(), true)); + + questions.put(9, new Question("Ти вирішив покинути квест. Може, спробуєш ще раз? 🚪", Map.of(), true)); + + questions.put(10, new Question("Ти сів чекати, але ніхто не прийшов... Гра закінчена. ⏳", Map.of(), true)); + } + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { + request.setCharacterEncoding("UTF-8"); + HttpSession session = request.getSession(); + + Integer step = (Integer) session.getAttribute("step"); + + String choice = request.getParameter("choice"); + + Question currentQuestion = questions.get(step); + Integer nextStep = currentQuestion.getOptions().get(choice); + + session.setAttribute("step", nextStep); + + response.sendRedirect("game.jsp"); + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + HttpSession session = request.getSession(); + + session.setAttribute("questions", questions); + String playerName = request.getParameter("playerName"); + session.setAttribute("playerName", playerName); + session.setAttribute("step", 1); + + request.getRequestDispatcher("game.jsp").forward(request, response); + } +} diff --git a/Bevzyuk/src/main/java/com/quest/Question.java b/Bevzyuk/src/main/java/com/quest/Question.java new file mode 100644 index 0000000..7aa98b3 --- /dev/null +++ b/Bevzyuk/src/main/java/com/quest/Question.java @@ -0,0 +1,27 @@ +package com.quest; + +import java.util.Map; + +public class Question { + private String text; + private Map options; + private boolean isEnding; + + public Question(String text, Map options, boolean isEnding) { + this.text = text; + this.options = options; + this.isEnding = isEnding; + } + + public String getText() { + return text; + } + + public Map getOptions() { + return options; + } + + public boolean isEnding() { + return isEnding; + } +} \ No newline at end of file diff --git a/Bevzyuk/src/main/java/com/quest/RestartServlet.java b/Bevzyuk/src/main/java/com/quest/RestartServlet.java new file mode 100644 index 0000000..75e9d9e --- /dev/null +++ b/Bevzyuk/src/main/java/com/quest/RestartServlet.java @@ -0,0 +1,15 @@ +package com.quest; + +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@WebServlet("/restart") +public class RestartServlet extends HttpServlet { + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { + request.getSession().invalidate(); + response.sendRedirect("index.jsp"); + } +} diff --git a/Bevzyuk/src/main/webapp/WEB-INF/web.xml b/Bevzyuk/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..9f88c1f --- /dev/null +++ b/Bevzyuk/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,7 @@ + + + + Archetype Created Web Application + diff --git a/Bevzyuk/src/main/webapp/game.jsp b/Bevzyuk/src/main/webapp/game.jsp new file mode 100644 index 0000000..4611cdc --- /dev/null +++ b/Bevzyuk/src/main/webapp/game.jsp @@ -0,0 +1,48 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ page import="java.util.Map" %> +<%@ page import="com.quest.Question" %> +<%@ page import="javax.servlet.http.HttpSession" %> + + + Квест + + + +<% + session = request.getSession(); + String playerName = (String) session.getAttribute("playerName"); + Integer step = (Integer) session.getAttribute("step"); + Map questions = (Map) session.getAttribute("questions"); + + Question question = (questions != null) ? questions.get(step) : null; + + String headerText; + if (question != null && !question.isEnding()) { + headerText = "Удачі, " + (playerName != null ? playerName : "Гравцю") + "! Обери свій шлях:"; + } else if (question != null && question.isEnding()) { + headerText = "Кінець гри, " + (playerName != null ? playerName : "Гравцю") + "!"; + } else { + headerText = "Щось пішло не так, спробуй ще раз!"; + } +%> + +

<%= headerText %>

+ +<% if (question != null) { %> +

<%= question.getText() %>

+ +<% if (!question.isEnding()) { %> +
+ <% for (String option : question.getOptions().keySet()) { %> + + <% } %> +
+<% } else { %> +

Гра закінчена!

+Почати знову +<% } %> +<% } else { %> +

Щось пішло не так. Спробуйте знову

+<% } %> + + \ No newline at end of file diff --git a/Bevzyuk/src/main/webapp/index.jsp b/Bevzyuk/src/main/webapp/index.jsp new file mode 100644 index 0000000..0f1eeec --- /dev/null +++ b/Bevzyuk/src/main/webapp/index.jsp @@ -0,0 +1,18 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + Квест: Початок + + + +
+

🔮 Ласкаво просимо до квесту! 🔮

+

Відчуй себе справжнім шукачем пригод! Введи своє ім’я та вирушай у подорож повну таємниць і небезпек.

+
+ + + +
+
+ + diff --git a/Bevzyuk/src/main/webapp/style.css b/Bevzyuk/src/main/webapp/style.css new file mode 100644 index 0000000..216163f --- /dev/null +++ b/Bevzyuk/src/main/webapp/style.css @@ -0,0 +1,134 @@ +/* Загальні стилі сторінки */ +body { + font-family: 'Arial', sans-serif; + background: linear-gradient(135deg, #1b2838, #3b5363); + color: #ecf0f1; + padding: 20px; + text-align: center; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: center; + min-height: 100vh; +} + +/* Контейнер для квестових питань */ +.quest-container { + margin-top: 10vh; + max-width: 800px; + background: rgba(27, 40, 56, 0.9); + padding: 30px; + border-radius: 10px; + box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); +} + +/* Заголовок */ +h2 { + font-size: 28px; + margin-bottom: 20px; + text-transform: uppercase; + letter-spacing: 1.5px; + color: #dcdde1; +} + +/* Стилі для кнопок */ +form button { + background: linear-gradient(135deg, #6a11cb, #2575fc); + color: #fff; + padding: 12px 24px; + margin: 10px; + border: none; + border-radius: 5px; + cursor: pointer; + font-size: 18px; + font-weight: bold; + transition: background 0.3s, transform 0.2s; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3); +} + +form button:hover { + background: linear-gradient(135deg, #2575fc, #6a11cb); + transform: scale(1.05); +} + +/* Стилі для повідомлень */ +p { + font-size: 20px; + margin: 20px 0; + color: #b2bec3; +} + +/* Лінки */ +a { + color: #f39c12; + text-decoration: none; + font-weight: bold; + transition: color 0.3s; +} + +a:hover { + color: #e74c3c; +} + +/* Фон для стартової сторінки */ +body.start-page { + background: url('https://www.kapitoliy.net.ua/wp-content/uploads/2018/11/istoriya-pro-pryvyda-pidgoretskogo-zamku.jpg') no-repeat center center fixed; + background-size: cover; + display: flex; + justify-content: flex-start; + align-items: center; + height: 100vh; + padding-top: 10vh; + margin: 0; + color: #ecf0f1; +} + +/* Контейнер для контенту */ +.container { + background: rgba(27, 40, 56, 0.9); + padding: 30px; + border-radius: 10px; + box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); + text-align: center; + max-width: 600px; + width: 90%; +} + +/* Заголовок */ +h1 { + font-size: 32px; + margin-bottom: 20px; + text-transform: uppercase; + letter-spacing: 2px; + color: #f1c40f; +} + +/* Поле введення */ +input[type="text"] { + padding: 10px; + border: 2px solid #3498db; + border-radius: 5px; + font-size: 16px; + width: calc(100% - 22px); + margin-bottom: 20px; + background: #1b2838; + color: #ecf0f1; +} + +/* Кнопка старту */ +button { + background: #e74c3c; + color: #fff; + padding: 12px 24px; + border: none; + border-radius: 5px; + font-size: 18px; + cursor: pointer; + transition: background 0.3s, transform 0.2s; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3); +} + +button:hover { + background: #c0392b; + transform: scale(1.05); +} diff --git a/Bevzyuk/src/test/java/com/quest/GameServletTest.java b/Bevzyuk/src/test/java/com/quest/GameServletTest.java new file mode 100644 index 0000000..b39c300 --- /dev/null +++ b/Bevzyuk/src/test/java/com/quest/GameServletTest.java @@ -0,0 +1,80 @@ +package com.quest; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import java.io.IOException; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class GameServletTest { + + @InjectMocks + private GameServlet servlet; + + @Mock + private HttpServletRequest request; + + @Mock + private HttpServletResponse response; + + @Mock + private HttpSession session; + + @Mock + private RequestDispatcher dispatcher; + + @BeforeEach + void setUp() { + MockitoAnnotations.initMocks(this); + servlet.init(); + + when(request.getSession()).thenReturn(session); + when(request.getRequestDispatcher("game.jsp")).thenReturn(dispatcher); + } + + @Test + void testInitQuestions() { + assertNotNull(servlet.questions, "questions не має бути null"); + assertEquals("Ти стоїш перед дверима. Що робити?", servlet.questions.get(1).getText()); + } + + @Test + void testDoGet_SetsSessionAttributesAndForwards() throws ServletException, IOException { + when(request.getParameter("playerName")).thenReturn("Тарас"); + + servlet.doGet(request, response); + + verify(session).setAttribute("questions", servlet.questions); + verify(session).setAttribute("playerName", "Тарас"); + verify(session).setAttribute("step", 1); + verify(dispatcher).forward(request, response); + } + + @Test + void testDoPost_UpdatesStepAndRedirects() throws IOException { + when(session.getAttribute("step")).thenReturn(1); + when(request.getParameter("choice")).thenReturn("Відкрити двері"); + + Map questions = servlet.questions; + Question currentQuestion = questions.get(1); + Integer expectedNextStep = currentQuestion.getOptions().get("Відкрити двері"); + + servlet.doPost(request, response); + + verify(session).setAttribute("step", expectedNextStep); + verify(response).sendRedirect("game.jsp"); + } +} + From 9fab1224c73ea4419b7712c6322c41cef457ab92 Mon Sep 17 00:00:00 2001 From: BevzyukIvan Date: Mon, 3 Mar 2025 00:39:02 +0200 Subject: [PATCH 2/2] Added README.md --- Bevzyuk/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Bevzyuk/README.md diff --git a/Bevzyuk/README.md b/Bevzyuk/README.md new file mode 100644 index 0000000..7728620 --- /dev/null +++ b/Bevzyuk/README.md @@ -0,0 +1,17 @@ +# M3-Quest-NEW + +## Опис +**M3-Quest-NEW** — це текстова гра-квест, реалізована за допомогою сервлетів. Гравець приймає рішення, які впливають на подальший розвиток сюжету. + +## Функціонал +- Початковий екран з можливістю введення імені гравця. +- Взаємодія з грою через вибір відповідей. +- Перехід між етапами квесту на основі вибору користувача. +- Збереження поточного стану гри через `HttpSession`. + +## Використані технології +- Java 21 (JDK 21) +- Java Servlet API +- JSP (JavaServer Pages) +- JUnit 5 (Jupiter API) +- Mockito \ No newline at end of file