From d058aad368e1dfee9b1797c56b8ba9861567479f Mon Sep 17 00:00:00 2001 From: mxchbot Date: Mon, 22 Dec 2025 14:02:05 +0300 Subject: [PATCH 1/4] The project is completed --- pom.xml | 17 ++- src/main/java/com/tictactoe/Field.java | 6 +- src/main/java/com/tictactoe/IndexServlet.java | 19 ++++ src/main/java/com/tictactoe/LogicServlet.java | 90 +++++++++++++++ .../java/com/tictactoe/RestartServlet.java | 20 ++++ src/main/java/com/tictactoe/StartServlet.java | 26 +++++ src/main/webapp/WEB-INF/index.jsp | 80 +++++++++++++ src/main/webapp/index.jsp | 17 --- src/main/webapp/static/main.css | 105 ++++++++++++++++++ 9 files changed, 355 insertions(+), 25 deletions(-) create mode 100644 src/main/java/com/tictactoe/IndexServlet.java create mode 100644 src/main/java/com/tictactoe/LogicServlet.java create mode 100644 src/main/java/com/tictactoe/RestartServlet.java create mode 100644 src/main/java/com/tictactoe/StartServlet.java create mode 100644 src/main/webapp/WEB-INF/index.jsp delete mode 100644 src/main/webapp/index.jsp diff --git a/pom.xml b/pom.xml index cb226e88..de4cab3b 100644 --- a/pom.xml +++ b/pom.xml @@ -18,15 +18,20 @@ - javax.servlet - javax.servlet-api - 4.0.1 + jakarta.servlet + jakarta.servlet-api + 6.2.0-M1 provided - javax.servlet - jstl - 1.2 + jakarta.servlet.jsp.jstl + jakarta.servlet.jsp.jstl-api + 3.1.0-M1 + + + org.glassfish.web + jakarta.servlet.jsp.jstl + 3.0.1 diff --git a/src/main/java/com/tictactoe/Field.java b/src/main/java/com/tictactoe/Field.java index c52d2a0d..7e4faad1 100644 --- a/src/main/java/com/tictactoe/Field.java +++ b/src/main/java/com/tictactoe/Field.java @@ -52,8 +52,10 @@ public Sign checkWin() { ); for (List winPossibility : winPossibilities) { - if (field.get(winPossibility.get(0)) == field.get(winPossibility.get(1)) - && field.get(winPossibility.get(0)) == field.get(winPossibility.get(2))) { + Sign sign0 = field.get(winPossibility.get(0)); + if ((sign0 == field.get(winPossibility.get(1))) + && (sign0 == field.get(winPossibility.get(2))) + && (sign0 != Sign.EMPTY)) { return field.get(winPossibility.get(0)); } } diff --git a/src/main/java/com/tictactoe/IndexServlet.java b/src/main/java/com/tictactoe/IndexServlet.java new file mode 100644 index 00000000..8792dd90 --- /dev/null +++ b/src/main/java/com/tictactoe/IndexServlet.java @@ -0,0 +1,19 @@ +package com.tictactoe; + +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 IndexServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + req.getRequestDispatcher("/start") + .forward(req, resp); + } +} diff --git a/src/main/java/com/tictactoe/LogicServlet.java b/src/main/java/com/tictactoe/LogicServlet.java new file mode 100644 index 00000000..1d817556 --- /dev/null +++ b/src/main/java/com/tictactoe/LogicServlet.java @@ -0,0 +1,90 @@ +package com.tictactoe; + +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 jakarta.servlet.http.HttpSession; + +import java.io.IOException; +import java.util.List; + +@WebServlet(name = "LogicServlet", value = "/logic") +public class LogicServlet extends HttpServlet { + + private static final String PATH_INDEX = "WEB-INF/index.jsp"; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + HttpSession currentSession = req.getSession(); + Field field = extractField(currentSession); + + if (checkWin(req, resp, currentSession, field)) { + return; + } + + int index = getSelectedIndex(req); + Sign currentSign = field.getField().get(index); + if (Sign.EMPTY != currentSign) { + req.getRequestDispatcher(PATH_INDEX) + .forward(req, resp); + return; + } + field.getField().put(index, Sign.CROSS); + if (checkWin(req, resp, currentSession, field)) { + return; + } + + int emptyFieldIndex = field.getEmptyFieldIndex(); + if (emptyFieldIndex >= 0) { + field.getField().put(emptyFieldIndex, Sign.NOUGHT); + if (checkWin(req, resp, currentSession, field)) { + return; + } + } else { + currentSession.setAttribute("draw", true); + List data = field.getFieldData(); + currentSession.setAttribute("data", data); + req.getRequestDispatcher(PATH_INDEX) + .forward(req, resp); + return; + } + + List data = field.getFieldData(); + currentSession.setAttribute("data", data); + req.getRequestDispatcher(PATH_INDEX) + .forward(req, resp); + } + + private int getSelectedIndex(HttpServletRequest request) { + String click = request.getParameter("click"); + boolean isNumeric = click.chars().allMatch(Character::isDigit); + return isNumeric ? Integer.parseInt(click) : 0; + } + + private Field extractField(HttpSession currentSession) { + Object fieldAttribute = currentSession.getAttribute("field"); + if (Field.class != fieldAttribute.getClass()) { + currentSession.invalidate(); + throw new RuntimeException("Session is broken, try one more time"); + } + return (Field) fieldAttribute; + } + + private boolean checkWin(HttpServletRequest req, + HttpServletResponse resp, + HttpSession currentSession, + Field field) throws IOException, ServletException { + Sign winner = field.checkWin(); + if (Sign.CROSS == winner || Sign.NOUGHT == winner) { + currentSession.setAttribute("winner", winner); + List data = field.getFieldData(); + currentSession.setAttribute("data", data); + req.getRequestDispatcher(PATH_INDEX) + .forward(req, resp); + return true; + } + return false; + } +} diff --git a/src/main/java/com/tictactoe/RestartServlet.java b/src/main/java/com/tictactoe/RestartServlet.java new file mode 100644 index 00000000..6607c339 --- /dev/null +++ b/src/main/java/com/tictactoe/RestartServlet.java @@ -0,0 +1,20 @@ +package com.tictactoe; + +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(name = "RestartServlet", value = "/restart") +public class RestartServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + req.getSession().invalidate(); + req.getRequestDispatcher("/start") + .forward(req, resp); + } +} diff --git a/src/main/java/com/tictactoe/StartServlet.java b/src/main/java/com/tictactoe/StartServlet.java new file mode 100644 index 00000000..17fffce5 --- /dev/null +++ b/src/main/java/com/tictactoe/StartServlet.java @@ -0,0 +1,26 @@ +package com.tictactoe; + +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 jakarta.servlet.http.HttpSession; + +import java.io.IOException; +import java.util.List; + +@WebServlet(name = "InitServlet", value = "/start") +public class StartServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + HttpSession currentSession = req.getSession(true); + Field field = new Field(); + List data = field.getFieldData(); + currentSession.setAttribute("field", field); + currentSession.setAttribute("data", data); + req.getRequestDispatcher("WEB-INF/index.jsp") + .forward(req, resp); + } +} diff --git a/src/main/webapp/WEB-INF/index.jsp b/src/main/webapp/WEB-INF/index.jsp new file mode 100644 index 00000000..17bd523b --- /dev/null +++ b/src/main/webapp/WEB-INF/index.jsp @@ -0,0 +1,80 @@ +<%@ page import="com.tictactoe.Sign" %> +<%@ page contentType="text/html;charset=UTF-8"%> + + + + Tic-Tac-Toe + + <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + +
+

Tic-Tac-Toe

+
+ + + +
X
+
+ +
O
+
+ +
+
+
+
+
+ + +
+
+ IT'S A DRAW +
+ +
+
+ +
+
+ CROSSES WIN! +
+ +
+
+ +
+
+ NOUGHTS WIN! +
+ +
+
+ +
+
+ MESSAGE +
+ +
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp deleted file mode 100644 index 964cc071..00000000 --- a/src/main/webapp/index.jsp +++ /dev/null @@ -1,17 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" language="java" %> - - - - - Tic-Tac-Toe - - -

Tic-Tac-Toe

- - - - - - \ No newline at end of file diff --git a/src/main/webapp/static/main.css b/src/main/webapp/static/main.css index e69de29b..919dcaf1 100644 --- a/src/main/webapp/static/main.css +++ b/src/main/webapp/static/main.css @@ -0,0 +1,105 @@ +body { + margin: 0; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); + font-family: 'Segoe UI', sans-serif; + color: white; +} + +.game-container { + display: flex; + flex-direction: column; + align-items: center; +} + +h1 { + font-weight: 300; + letter-spacing: 3px; + margin-bottom: 20px; + text-transform: uppercase; + opacity: 0.8; +} + +.board { + display: grid; + grid-template-columns: repeat(3, 100px); + grid-template-rows: repeat(3, 100px); + gap: 15px; + padding: 20px; + background: rgba(255, 255, 255, 0.05); + backdrop-filter: blur(15px); + border-radius: 20px; + border: 1px solid rgba(255, 255, 255, 0.1); + box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5); +} + +.cell { + width: 100px; + height: 100px; + background: rgba(255, 255, 255, 0.03); + border-radius: 12px; + display: flex; + justify-content: center; + align-items: center; + font-size: 3rem; + font-weight: bold; + cursor: pointer; + user-select: none; + -webkit-user-select: none; + transition: all 0.2s ease; + border: 1px solid rgba(255, 255, 255, 0.05); +} + +.cell:hover { + background: rgba(255, 255, 255, 0.1); + transform: scale(1.02); +} + +.cell.x { color: #ff4d6d; text-shadow: 0 0 10px #ff4d6d; } +.cell.o { color: #00d4ff; text-shadow: 0 0 10px #00d4ff; } + +.controls { + height: 120px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + margin-top: 10px; + width: 100%; + visibility: hidden; + opacity: 0; + transition: opacity 0.4s ease; +} + +.controls.show { + visibility: visible; + opacity: 1; +} + +#status { + font-size: 1.2rem; + margin-bottom: 15px; + height: 1.5rem; +} + +.restart-btn { + padding: 10px 25px; + font-size: 1rem; + border: none; + border-radius: 50px; + background: #4ecca3; + color: #1a1a2e; + font-weight: bold; + cursor: pointer; + transition: 0.3s; + box-shadow: 0 4px 15px rgba(78, 204, 163, 0.3); +} + +.restart-btn:hover { + background: #45b691; + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(78, 204, 163, 0.4); +} From d55b7e86790c33b320194859dd99b79004b1f41c Mon Sep 17 00:00:00 2001 From: mxchbot Date: Mon, 22 Dec 2025 14:15:53 +0300 Subject: [PATCH 2/4] Fixes --- src/main/java/com/tictactoe/Field.java | 8 ++++---- src/main/java/com/tictactoe/IndexServlet.java | 2 +- src/main/java/com/tictactoe/LogicServlet.java | 2 +- src/main/webapp/WEB-INF/index.jsp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/tictactoe/Field.java b/src/main/java/com/tictactoe/Field.java index 7e4faad1..10551169 100644 --- a/src/main/java/com/tictactoe/Field.java +++ b/src/main/java/com/tictactoe/Field.java @@ -53,10 +53,10 @@ public Sign checkWin() { for (List winPossibility : winPossibilities) { Sign sign0 = field.get(winPossibility.get(0)); - if ((sign0 == field.get(winPossibility.get(1))) - && (sign0 == field.get(winPossibility.get(2))) - && (sign0 != Sign.EMPTY)) { - return field.get(winPossibility.get(0)); + if ((sign0 != Sign.EMPTY) + && (sign0 == field.get(winPossibility.get(1))) + && (sign0 == field.get(winPossibility.get(2)))) { + return sign0; } } return Sign.EMPTY; diff --git a/src/main/java/com/tictactoe/IndexServlet.java b/src/main/java/com/tictactoe/IndexServlet.java index 8792dd90..3b4f2cbe 100644 --- a/src/main/java/com/tictactoe/IndexServlet.java +++ b/src/main/java/com/tictactoe/IndexServlet.java @@ -8,7 +8,7 @@ import java.io.IOException; -@WebServlet({""}) +@WebServlet("") public class IndexServlet extends HttpServlet { @Override diff --git a/src/main/java/com/tictactoe/LogicServlet.java b/src/main/java/com/tictactoe/LogicServlet.java index 1d817556..6217bec5 100644 --- a/src/main/java/com/tictactoe/LogicServlet.java +++ b/src/main/java/com/tictactoe/LogicServlet.java @@ -77,7 +77,7 @@ private boolean checkWin(HttpServletRequest req, HttpSession currentSession, Field field) throws IOException, ServletException { Sign winner = field.checkWin(); - if (Sign.CROSS == winner || Sign.NOUGHT == winner) { + if (winner != Sign.EMPTY) { currentSession.setAttribute("winner", winner); List data = field.getFieldData(); currentSession.setAttribute("data", data); diff --git a/src/main/webapp/WEB-INF/index.jsp b/src/main/webapp/WEB-INF/index.jsp index 17bd523b..614b1831 100644 --- a/src/main/webapp/WEB-INF/index.jsp +++ b/src/main/webapp/WEB-INF/index.jsp @@ -72,7 +72,7 @@ }); } - + document.getElementById('endGameUI').classList.add('show'); From 6423e5642ec0b81045e9836d01b2fc8d4d42859c Mon Sep 17 00:00:00 2001 From: mxchbot Date: Mon, 22 Dec 2025 14:20:45 +0300 Subject: [PATCH 3/4] Fix --- src/main/webapp/static/main.css | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/webapp/static/main.css b/src/main/webapp/static/main.css index 919dcaf1..8c7a0baa 100644 --- a/src/main/webapp/static/main.css +++ b/src/main/webapp/static/main.css @@ -58,8 +58,15 @@ h1 { transform: scale(1.02); } -.cell.x { color: #ff4d6d; text-shadow: 0 0 10px #ff4d6d; } -.cell.o { color: #00d4ff; text-shadow: 0 0 10px #00d4ff; } +.cell.x { + color: #ff4d6d; + text-shadow: 0 0 10px #ff4d6d; +} + +.cell.o { + color: #00d4ff; + text-shadow: 0 0 10px #00d4ff; +} .controls { height: 120px; From b63e35b4723cd2a90fa48a0afbd43eb99b955b9d Mon Sep 17 00:00:00 2001 From: mxchbot Date: Wed, 7 Jan 2026 14:18:53 +0300 Subject: [PATCH 4/4] Fix dependencies stable version --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index de4cab3b..06fa0c5c 100644 --- a/pom.xml +++ b/pom.xml @@ -20,13 +20,13 @@ jakarta.servlet jakarta.servlet-api - 6.2.0-M1 + 6.0.0 provided jakarta.servlet.jsp.jstl jakarta.servlet.jsp.jstl-api - 3.1.0-M1 + 3.0.0 org.glassfish.web