diff --git a/src/main/java/com/tictactoe/Field.java b/src/main/java/com/tictactoe/Field.java index c52d2a0d..fd7cfdc3 100644 --- a/src/main/java/com/tictactoe/Field.java +++ b/src/main/java/com/tictactoe/Field.java @@ -31,7 +31,6 @@ public int getEmptyFieldIndex() { .map(Map.Entry::getKey) .findFirst().orElse(-1); } - public List getFieldData() { return field.entrySet().stream() .sorted(Map.Entry.comparingByKey()) diff --git a/src/main/java/com/tictactoe/InitServlet.java b/src/main/java/com/tictactoe/InitServlet.java new file mode 100644 index 00000000..3ad0f079 --- /dev/null +++ b/src/main/java/com/tictactoe/InitServlet.java @@ -0,0 +1,29 @@ +package com.tictactoe; + +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; +import java.util.Map; + +@WebServlet(name="InitServlet", value = "/start") +public class InitServlet extends HttpServlet { + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + HttpSession session = req.getSession(true); + + Field field = new Field(); + Map fieldData = field.getField(); + List data = field.getFieldData(); + + session.setAttribute("field", field); + session.setAttribute("data", data); + session.setAttribute("queue", Sign.CROSS); + + getServletContext().getRequestDispatcher("/index.jsp").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..6dc00fa1 --- /dev/null +++ b/src/main/java/com/tictactoe/LogicServlet.java @@ -0,0 +1,92 @@ +package com.tictactoe; + +import javax.servlet.RequestDispatcher; +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(name = "LogicServlet", value = "/logic") +public class LogicServlet extends HttpServlet { + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + HttpSession session = req.getSession(); + Field field = extractField(session); + + int index = getSelectedIndex(req); + if(checkWin(resp, session, field)){ + return; + } + Sign currentSign = field.getField().get(index); + + if(Sign.EMPTY != currentSign) { + RequestDispatcher dispatcher = req.getServletContext().getRequestDispatcher("/index.jsp"); + dispatcher.forward(req, resp); + return; + } + if(session.getAttribute("queue") == Sign.CROSS) { + field.getField().put(index, Sign.CROSS); + if(checkWin(resp, session, field)){ + return; + } + else { + session.setAttribute("queue", Sign.NOUGHT); + } + } + else { + field.getField().put(index, Sign.NOUGHT); + if(checkWin(resp, session, field)){ + return; + } + else { + session.setAttribute("queue", Sign.CROSS); + } + } + if(field.getEmptyFieldIndex() == -1){ + session.setAttribute("draw", true); + List data = field.getFieldData(); + + session.setAttribute("data", data); + resp.sendRedirect("/index.jsp"); + return; + } + List data = field.getFieldData(); + + session.setAttribute("data", data); + session.setAttribute("field", field); + + resp.sendRedirect("/index.jsp"); + } + private boolean checkWin(HttpServletResponse response, HttpSession session, Field field) throws IOException { + Sign winner = field.checkWin(); + if(Sign.CROSS == winner || Sign.NOUGHT == winner) { + session.setAttribute("winner", winner); + + List data = field.getFieldData(); + + session.setAttribute("data", data); + response.sendRedirect("/index.jsp"); + return true; + } + return false; + } + + 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 session) { + Object fieldAttribute = session.getAttribute("field"); + if(Field.class != fieldAttribute.getClass()) { + session.invalidate(); + throw new RuntimeException("Session is broken, try one more time"); + } + return (Field) fieldAttribute; + } +} diff --git a/src/main/java/com/tictactoe/RestartServlet.java b/src/main/java/com/tictactoe/RestartServlet.java new file mode 100644 index 00000000..fdd03d00 --- /dev/null +++ b/src/main/java/com/tictactoe/RestartServlet.java @@ -0,0 +1,17 @@ +package com.tictactoe; + +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 java.io.IOException; + +@WebServlet(name = "RestartServlet", value = "/restart") +public class RestartServlet extends HttpServlet { + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + req.getSession().invalidate(); + resp.sendRedirect("/start"); + } +} diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp index 964cc071..5d375f2f 100644 --- a/src/main/webapp/index.jsp +++ b/src/main/webapp/index.jsp @@ -1,16 +1,73 @@ +<%@ page import="com.tictactoe.Sign" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> + + <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> Tic-Tac-Toe + - +

Tic-Tac-Toe

+ + + + + + + + + + + + + + + + +
${data.get(0).getSign()}${data.get(1).getSign()}${data.get(2).getSign()}
${data.get(3).getSign()}${data.get(4).getSign()}${data.get(5).getSign()}
${data.get(6).getSign()}${data.get(7).getSign()}${data.get(8).getSign()}
+
+ + - diff --git a/src/main/webapp/static/main.css b/src/main/webapp/static/main.css index e69de29b..82cd9842 100644 --- a/src/main/webapp/static/main.css +++ b/src/main/webapp/static/main.css @@ -0,0 +1,68 @@ +body { + font-family: Arial, sans-serif; + text-align: center; + background-color: #f0f0f0; + margin: 0; + padding: 20px; +} +h1 { + color: #333; +} + +table { + margin: 20px auto; + border-collapse: collapse; +} + +td { + width: 100px; + height: 100px; + border: 2px solid #333; + font-size: 2em; + font-weight: bold; + text-align: center; + vertical-align: middle; + cursor: pointer; + transition: background-color 0.3s ease; +} + +td:hover { + background-color: #e0e0e0; +} + +button { + background-color: #4CAF50; + color: white; + padding: 10px 20px; + margin-top: 20px; + border: none; + border-radius: 5px; + font-size: 1em; + cursor: pointer; + transition: background-color 0.3s ease; +} + +button:hover { + background-color: #45a049; +} + +hr { + margin: 20px 0; + border: none; + border-top: 2px solid #333; +} + +h1:first-of-type { + margin-top: 0; +} + +h1:last-of-type { + margin-bottom: 20px; +} +body.cross-turn { + background-color: #f0f8ff; /* Цвет фона для хода крестиков */ +} + +body.nought-turn { + background-color: #fffaf0; /* Цвет фона для хода ноликов */ +} \ No newline at end of file