diff --git a/pom.xml b/pom.xml index 4a15063..2879d14 100644 --- a/pom.xml +++ b/pom.xml @@ -8,12 +8,40 @@ Module3Quest Maven Webapp http://maven.apache.org + + javax.servlet + servlet-api + 2.5 + provided + + + javax.servlet + jsp-api + 2.0 + provided + + + jstl + jstl + 1.2 + + + org.apache.tomcat.embed + tomcat-embed-core + 9.0.85 + junit junit - 3.8.1 + 4.13.2 test + + jakarta.servlet + jakarta.servlet-api + 6.1.0-M2 + provided + Module3Quest diff --git a/src/main/java/quest/Question.java b/src/main/java/quest/Question.java new file mode 100644 index 0000000..0fff356 --- /dev/null +++ b/src/main/java/quest/Question.java @@ -0,0 +1,58 @@ +package quest; + +import java.util.Objects; + +public class Question { + private String question; + private final String answerOption1; + private final String answerOption2; + private final String answerOption3; + private final String answerOption4; + private final int rightAnswer; + + public Question(String question, String answerOption1, String answerOption2, String answerOption3, String answerOption4, int rightAnswer) { + this.question = question; + this.answerOption1 = answerOption1; + this.answerOption2 = answerOption2; + this.answerOption3 = answerOption3; + this.answerOption4 = answerOption4; + this.rightAnswer = rightAnswer; + } + + public String getQuestion() { + return question; + } + + public String getAnswerOption1() { + return answerOption1; + } + + public String getAnswerOption2() { + return answerOption2; + } + + public String getAnswerOption3() { + return answerOption3; + } + + public String getAnswerOption4() { + return answerOption4; + } + + public int getRightAnswer() { + return rightAnswer; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Question question1 = (Question) o; + return rightAnswer == question1.rightAnswer && Objects.equals(question, question1.question) && Objects.equals(answerOption1, question1.answerOption1) && Objects.equals(answerOption2, question1.answerOption2) && Objects.equals(answerOption3, question1.answerOption3) && Objects.equals(answerOption4, question1.answerOption4); + } + + @Override + public int hashCode() { + return Objects.hash(question, answerOption1, answerOption2, answerOption3, answerOption4, rightAnswer); + } +} \ No newline at end of file diff --git a/src/main/java/quest/QuestionBase.java b/src/main/java/quest/QuestionBase.java new file mode 100644 index 0000000..15c13b2 --- /dev/null +++ b/src/main/java/quest/QuestionBase.java @@ -0,0 +1,101 @@ +package quest; + +import java.util.ArrayList; +import java.util.List; + +public class QuestionBase { + private static QuestionBase instance; + private List questions; + private int currentQuestionIndex = 0; + + private QuestionBase() { + questions = new ArrayList<>(); + questions.add(new Question("img/1.png", + "BMW", + "Bentley", + "Lexus", + "Audi", 2)); + questions.add(new Question("img/2.png", + "Brilliance", + "Skoda", + "Lexus", + "Dodge", 1)); + questions.add(new Question("img/3.png", + "Skoda", + "Alfa Romeo", + "Acura", + "Dodge", 4)); + questions.add(new Question("img/4.png", + "Mazda", + "Audi", + "Brilliance", + "Dodge", 2)); + questions.add(new Question("img/5.png", + "Daihatsu", + "Bentley", + "BMW", + "Jaguar", 1)); + questions.add(new Question("img/6.png", + "Alfa Romeo", + "Acura", + "Citroen", + "Lexus", 2)); + questions.add(new Question("img/7.png", + "Alfa Romeo", + "Porsche", + "Mercedes", + "Volkswagen", 1)); + questions.add(new Question("img/8.png", + "Volkswagen", + "Citroen", + "Jaguar", + "BMW", 4)); + questions.add(new Question("img/9.png", + "Chevrolet", + "Porsche", + "Lexus", + "BMW", 1)); + questions.add(new Question("img/10.png", + "Alfa Romeo", + "Porsche", + "Daewoo", + "Acura", 3)); + questions.add(new Question("img/11.png", + "BMW", + "Mercedes", + "Ford", + "Aston Martin", 2)); + questions.add(new Question("img/12.png", + "Ford", + "Citroen", + "Jaguar", + "Cadillac", 4)); + questions.add(new Question("img/13.png", + "Ferrari", + "Acura", + "Porsche", + "Mercedes", 1)); + questions.add(new Question("img/14.png", + "Ferrari", + "BMW", + "Chevrolet", + "Aston Martin", 4)); + questions.add(new Question("img/15.png", + "Daewoo", + "Volkswagen", + "Citroen", + "BMW", 3)); + + currentQuestionIndex = 0; + } + public static synchronized QuestionBase getInstance(){ + if (instance == null){ + instance = new QuestionBase(); + } + return instance; + } + + public List getQuestions() { + return questions; + } +} \ No newline at end of file diff --git a/src/main/java/quest/QuizControllerServlet.java b/src/main/java/quest/QuizControllerServlet.java new file mode 100644 index 0000000..0d80da0 --- /dev/null +++ b/src/main/java/quest/QuizControllerServlet.java @@ -0,0 +1,92 @@ +package 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.List; + +@WebServlet("/quiz") +public class QuizControllerServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + HttpSession session = request.getSession(true); + String level = request.getParameter("level"); + String startNewGame = request.getParameter("newGame"); + + if ("true".equals(startNewGame)) { + session.removeAttribute("currentQuestion"); + session.removeAttribute("currentQuestionIndex"); + session.removeAttribute("message"); + } + + List questions = QuestionBase.getInstance().getQuestions(); + + if (!questions.isEmpty()) { + session.setAttribute("currentQuestion", questions.get(0)); + session.setAttribute("currentQuestionIndex", 0); + session.setAttribute("level", level); + session.setAttribute("totalQuestions", questions.size()); + getServletContext().getRequestDispatcher("/quiz.jsp").forward(request, response); + } else { + response.getWriter().println("Помилка: Немає доступних питань."); + } + } + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + HttpSession session = request.getSession(true); + Question currentQuestion = (Question) session.getAttribute("currentQuestion"); + String userAnswerStr = request.getParameter("userAnswer"); + + if (userAnswerStr != null && !userAnswerStr.isEmpty()) { + try { + int userAnswer = Integer.parseInt(userAnswerStr); + + if (userAnswer == currentQuestion.getRightAnswer()) { + session.setAttribute("message", "Correct!"); + } else { + session.setAttribute("message", "Incorrect!"); + } + } catch (NumberFormatException e) { + session.setAttribute("message", "Error"); + } + } + + List questions = QuestionBase.getInstance().getQuestions(); + int currentQuestionIndex = (Integer) session.getAttribute("currentQuestionIndex"); + + if ("true".equals(request.getParameter("restartButton"))) { + restartGame(session); + response.sendRedirect("quiz.jsp"); + return; + } + + session.setAttribute("currentQuestionIndex", currentQuestionIndex); + session.setAttribute("totalQuestions", questions.size()); + + if (currentQuestionIndex < questions.size() - 1) { + Question nextQuestion = questions.get(currentQuestionIndex + 1); + session.setAttribute("currentQuestion", nextQuestion); + session.setAttribute("currentQuestionIndex", currentQuestionIndex + 1); + response.sendRedirect("quiz.jsp"); + } else { + response.sendRedirect("quizResult.jsp"); + } + } + + private void restartGame(HttpSession session) { + session.removeAttribute("currentQuestion"); + session.removeAttribute("currentQuestionIndex"); + session.removeAttribute("message"); + + List questions = QuestionBase.getInstance().getQuestions(); + Question firstQuestion = questions.get(0); + session.setAttribute("currentQuestion", firstQuestion); + session.setAttribute("currentQuestionIndex", 0); + } +} diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index 9f88c1f..0000000 --- a/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - Archetype Created Web Application - diff --git a/src/main/webapp/img/1.png b/src/main/webapp/img/1.png new file mode 100644 index 0000000..73b234d Binary files /dev/null and b/src/main/webapp/img/1.png differ diff --git a/src/main/webapp/img/10.png b/src/main/webapp/img/10.png new file mode 100644 index 0000000..38f89e7 Binary files /dev/null and b/src/main/webapp/img/10.png differ diff --git a/src/main/webapp/img/11.png b/src/main/webapp/img/11.png new file mode 100644 index 0000000..52e1f34 Binary files /dev/null and b/src/main/webapp/img/11.png differ diff --git a/src/main/webapp/img/12.png b/src/main/webapp/img/12.png new file mode 100644 index 0000000..72f63b6 Binary files /dev/null and b/src/main/webapp/img/12.png differ diff --git a/src/main/webapp/img/13.png b/src/main/webapp/img/13.png new file mode 100644 index 0000000..437c673 Binary files /dev/null and b/src/main/webapp/img/13.png differ diff --git a/src/main/webapp/img/14.png b/src/main/webapp/img/14.png new file mode 100644 index 0000000..8430949 Binary files /dev/null and b/src/main/webapp/img/14.png differ diff --git a/src/main/webapp/img/15.png b/src/main/webapp/img/15.png new file mode 100644 index 0000000..92b9fe0 Binary files /dev/null and b/src/main/webapp/img/15.png differ diff --git a/src/main/webapp/img/2.png b/src/main/webapp/img/2.png new file mode 100644 index 0000000..16f49c7 Binary files /dev/null and b/src/main/webapp/img/2.png differ diff --git a/src/main/webapp/img/3.png b/src/main/webapp/img/3.png new file mode 100644 index 0000000..428f3b8 Binary files /dev/null and b/src/main/webapp/img/3.png differ diff --git a/src/main/webapp/img/4.png b/src/main/webapp/img/4.png new file mode 100644 index 0000000..a9bbf2e Binary files /dev/null and b/src/main/webapp/img/4.png differ diff --git a/src/main/webapp/img/5.png b/src/main/webapp/img/5.png new file mode 100644 index 0000000..ba012d5 Binary files /dev/null and b/src/main/webapp/img/5.png differ diff --git a/src/main/webapp/img/6.png b/src/main/webapp/img/6.png new file mode 100644 index 0000000..73b9d7f Binary files /dev/null and b/src/main/webapp/img/6.png differ diff --git a/src/main/webapp/img/7.png b/src/main/webapp/img/7.png new file mode 100644 index 0000000..4505296 Binary files /dev/null and b/src/main/webapp/img/7.png differ diff --git a/src/main/webapp/img/8.png b/src/main/webapp/img/8.png new file mode 100644 index 0000000..c0cb5ca Binary files /dev/null and b/src/main/webapp/img/8.png differ diff --git a/src/main/webapp/img/9.png b/src/main/webapp/img/9.png new file mode 100644 index 0000000..110084f Binary files /dev/null and b/src/main/webapp/img/9.png differ diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp index c38169b..dbf03f9 100644 --- a/src/main/webapp/index.jsp +++ b/src/main/webapp/index.jsp @@ -1,5 +1,20 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + CAR LOGO QUIZ + + + -Hello World! + + + Виберіть рівень гри: + Ласкаво просимо до CAR LOGO QUIZ! Ця гра допоможе вам перевірити ваші знання логотипів. Оберіть рівень складності: + Легко + Середньо + Складно + + + diff --git a/src/main/webapp/quiz.jsp b/src/main/webapp/quiz.jsp new file mode 100644 index 0000000..ea74588 --- /dev/null +++ b/src/main/webapp/quiz.jsp @@ -0,0 +1,73 @@ +<%@ page import="quest.Question" %> +<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%> + + + + CAR LOGO QUIZ + + + + + + + CAR LOGO QUIZ + + + + + <% + Question currentQuestion = (Question) session.getAttribute("currentQuestion"); + String questionImage = currentQuestion.getQuestion(); + %> + + + + + + Питання ${sessionScope.currentQuestionIndex + 1} з ${sessionScope.totalQuestions} + + + + + ${currentQuestion.getAnswerOption1()} + + + + ${currentQuestion.getAnswerOption2()} + + + + ${currentQuestion.getAnswerOption3()} + + + + ${currentQuestion.getAnswerOption4()} + + + + + + + + Час до завершення відповіді: + + + ${message} + + + ${sessionScope.level} + + + + + + + + Почати заново + + + На головну + + + + diff --git a/src/main/webapp/quizResult.jsp b/src/main/webapp/quizResult.jsp new file mode 100644 index 0000000..405701e --- /dev/null +++ b/src/main/webapp/quizResult.jsp @@ -0,0 +1,14 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> + + + + CAR LOGO QUIZ + + + + + Вітаю! Ти пройшов всю гру + На головну стрінку + + + diff --git a/src/main/webapp/script.js b/src/main/webapp/script.js new file mode 100644 index 0000000..e885037 --- /dev/null +++ b/src/main/webapp/script.js @@ -0,0 +1,108 @@ +let timerSeconds; +function setTimerDuration(){ + let levelElement = document.getElementById('level'); + let levelText = levelElement.textContent.trim().toLowerCase(); + + if (levelText === 'easy') { + timerSeconds = 60; + }else if (levelText === 'hard') { + timerSeconds = 20; + }else { + timerSeconds = 30; + } +} + +function updateTimer() { + document.getElementById('timer').innerHTML = timerSeconds + " сек"; + timerSeconds--; + + if (timerSeconds < 0) { + document.getElementById('quiz-form').style.display = 'none'; + document.getElementById('timer-message').innerHTML = 'Час вичерпано'; + document.getElementById('answer-alert').style.display = 'block'; + document.getElementById('restart-button').style.display = 'block'; + makeScreenRed() + }else { + setTimeout(updateTimer, 1000); + } +} + +function validateSelection(){ + let selectedOption = document.querySelector('input[name="userAnswer"]:checked'); + let answerAlert = document.getElementById('answer-alert'); + + if (!selectedOption) { + answerAlert.style.display = 'block'; + return false; + }else { + answerAlert.style.display = 'none'; + return true; + } +} + +function validateForm() { + let answerAlert = document.getElementById('answer-alert'); + + if (answerAlert.innerText.trim() === "Incorrect!") { + makeScreenRed(); + document.getElementById('quiz-form').style.display = 'none'; + document.getElementById('timer-message').innerHTML = "Неправельна відповідь. Гра закінчена!"; + answerAlert.style.display = 'block'; + document.getElementById('restart-button').style.display = 'block'; + } else if (answerAlert.innerText.trim() === "Correct!") { + makeScreenGreen(); + } +} + +function makeScreenGreen() { + let opacity = 1; + const interval = 20; + const duration = 1000; + const steps = duration / interval; + + const intervalId = setInterval(function () { + document.body.style.backgroundColor = `rgba(144, 238, 144, ${opacity}`; + opacity -= 1 / steps; + + if (opacity <= 0) { + clearInterval(intervalId); + document.body.style.backgroundColor = ''; + } + }, interval); +} + +function makeScreenRed() { + let opacity = 1; + const interval = 20; + const duration = 1500; + const steps = duration / interval; + + const intervalId = setInterval(function () { + document.body.style.backgroundColor = `rgba(220, 20, 60, ${opacity}`; + opacity -= 1 / steps; + + if (opacity <= 0) { + clearInterval(intervalId); + document.body.style.backgroundColor = ''; + } + }, interval); +} + +window.onload = function () { + setTimerDuration() + updateTimer(); + validateForm(); +}; + +function restartGame() { + let restartInput = document.createElement('input'); + restartInput.type = 'hidden'; + restartInput.name = 'restartButton'; + restartInput.value = 'true'; + document.getElementById('quiz-form').appendChild(restartInput); + document.getElementById('quiz-form').submit(); +} + +function goHome() { + window.location.href = "index.jsp"; +} \ No newline at end of file diff --git a/src/main/webapp/static/style.css b/src/main/webapp/static/style.css new file mode 100644 index 0000000..85bae2e --- /dev/null +++ b/src/main/webapp/static/style.css @@ -0,0 +1,144 @@ +body { + font-family: 'Poppins', sans-serif; + background-color: #f8f8f8; + margin: 0; + padding: 0; +} + +.container { + max-width: 800px; + margin: 50px auto; + padding: 30px; + background-color: #fff; + border-radius: 10px; + box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1); + text-align: center; +} + +h2 { + color: #2c3e50; + font-size: 32px; + margin-bottom: 20px; +} + +.quiz-timer p { + font-size: 22px; + color: #555; + margin: 20px 0; +} + +.quiz-info { + font-size: 18px; + color: #777; + margin-bottom: 20px; +} + +.quiz-options { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); + gap: 15px; + justify-content: center; +} + +.form-check { + text-align: center; + margin-bottom: 20px; +} + +.quiz-options input[type="radio"] { + margin-right: 8px; +} + +.quiz-submit input[type="submit"], +.quiz-restart #restart-button { + display: inline-block; + padding: 12px 24px; + font-size: 18px; + text-align: center; + text-decoration: none; + cursor: pointer; + border-radius: 8px; + margin-top: 20px; + border: none; +} + +.quiz-submit input[type="submit"] { + color: #fff; + background-color: #3498db; +} + +.quiz-submit input[type="submit"]:hover, +.quiz-restart #restart-button:hover { + background-color: #2980b9; +} + +.quiz-restart #restart-button { + color: #fff; + background-color: #e74c3c; + margin: 20px auto; +} + +.hidden-element { + display: none; +} + +.go-home { + text-align: center; + margin-top: 20px; +} + +.go-home .btn { + display: inline-block; + padding: 12px 24px; + font-size: 18px; + text-align: center; + text-decoration: none; + cursor: pointer; + border-radius: 8px; + background-color: #9b59b6; + color: #fff; + transition: background-color 0.3s; +} + +.card { + max-width: 800px; + margin: 50px auto; + padding: 30px; + background-color: #fff; + border-radius: 10px; + box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1); + text-align: center; +} + +.btn-easy, +.btn-medium, +.btn-hard { + display: inline-block; + padding: 12px 24px; + font-size: 18px; + text-align: center; + text-decoration: none; + cursor: pointer; + border-radius: 8px; + transition: background-color 0.3s; + margin: 10px; +} + +.btn-easy { + background-color: #2ecc71; + color: white; +} + +.btn-medium { + background-color: #f39c12; + color: #333; +} + +.btn-hard { + background-color: #e74c3c; + color: white; +} + +.btn-hard:hover, .btn-medium:hover, .btn-easy:hover { + filter: brightness(90%); +} diff --git a/src/test/java/quest/QuestionBaseTest.java b/src/test/java/quest/QuestionBaseTest.java new file mode 100644 index 0000000..77788fd --- /dev/null +++ b/src/test/java/quest/QuestionBaseTest.java @@ -0,0 +1,31 @@ +package quest; + +import org.junit.Test; + + +import static org.junit.Assert.*; + +public class QuestionBaseTest { + @Test + public void testSingletonInstance() { + QuestionBase instance1 = QuestionBase.getInstance(); + QuestionBase instance2 = QuestionBase.getInstance(); + assertEquals(instance1, instance2); + } + @Test + public void testQuestionsListNotNull() { + QuestionBase questionBase = QuestionBase.getInstance(); + assertNotNull(questionBase.getQuestions()); + } + @Test + public void testQuestionsListPopulated() { + QuestionBase questionBase = QuestionBase.getInstance(); + assertFalse(questionBase.getQuestions().isEmpty()); + } + @Test + public void testMultipleGetInstanceCalls() { + QuestionBase instance1 = QuestionBase.getInstance(); + QuestionBase instance2 = QuestionBase.getInstance(); + assertEquals(instance1, instance2); + } +} \ No newline at end of file
Ласкаво просимо до CAR LOGO QUIZ! Ця гра допоможе вам перевірити ваші знання логотипів. Оберіть рівень складності:
Час до завершення відповіді: