இன்று நாம் சர்வ்லெட்டுகள் மற்றும் ஜேஎஸ்பியைப் பயன்படுத்தி டிக்-டாக்-டோ விளையாட்டை எழுதுவோம்.

இந்த திட்டம் முந்தைய திட்டங்களில் இருந்து சற்று வித்தியாசமாக இருக்கும். இது பணிகள் மட்டுமல்ல, அவற்றை எவ்வாறு செய்வது என்பது பற்றிய விளக்கங்களும் இருக்கும். அதாவது, இது "ஹவ் டு ..." தொடரிலிருந்து ஒரு திட்டமாக இருக்கும்.

அறிவுறுத்தல்:

  1. களஞ்சியத்திலிருந்து ஃபோர்க்: https://github.com/CodeGymCC/project-servlet.git
  2. திட்டத்தின் உங்கள் பதிப்பை உங்கள் கணினியில் பதிவிறக்கவும்.
  3. ஐடியாவில் பயன்பாட்டு துவக்கத்தை அமைக்கவும்:
    • Alt + Shift + F9 -> உள்ளமைவுகளைத் திருத்து... -> Alt + insert -> tom (தேடல் பட்டியில்) -> உள்ளூர்.
    • அதன் பிறகு, நீங்கள் "CONFIGURE" என்பதைக் கிளிக் செய்து, Tomcat உடனான காப்பகம் எங்கு பதிவிறக்கம் செய்யப்பட்டு திறக்கப்பட்டது என்பதைக் குறிப்பிட வேண்டும்.
    • “பணிநிறுத்தம்” தாவலில்: Alt + insert -> Artifact... -> tic-tac-toe:war exploded -> OK.
    • "பயன்பாட்டு சூழல்" புலத்தில்: "/" (ஸ்லாஷ்) மட்டும் விடுங்கள்.
    • "விண்ணப்பிக்கவும்" அழுத்தவும்.
    • அமைப்புகள் சாளரத்தை மூடு.
    • தனிப்பயனாக்கப்பட்ட கட்டமைப்பின் முதல் சோதனை ஓட்டத்தை உருவாக்கவும். எல்லாவற்றையும் சரியாகச் செய்தால், உங்கள் இயல்புநிலை உலாவி திறக்கும், அதில் இது இருக்கும்:
  4. "pom.xml" கோப்பைத் திறக்கவும் . "சார்புகள்" தொகுதியில் 2 சார்புகள் உள்ளன .
    • javax.servlet-apiservlets விவரக்குறிப்புக்கு பொறுப்பு. வளர்ச்சியின் போது ஸ்கோப் "வழங்கப்பட்டது" தேவை, ஆனால் இயக்க நேரத்தில் தேவையில்லை (டாம்கேட் ஏற்கனவே லிப் கோப்புறையில் இந்த சார்புநிலையை கொண்டுள்ளது).
    • jstl- ஒரு டெம்ப்ளேட் இயந்திரமாகக் கருதலாம்.
  5. "webapp" கோப்புறையில் 3 கோப்புகள் உள்ளன :
    • index.jsp- இது எங்கள் டெம்ப்ளேட் (HTML பக்கத்தைப் போன்றது). இது மார்க்அப் மற்றும் ஸ்கிரிப்ட்களைக் கொண்டிருக்கும். படி 3 இல் பார்த்த கட்டமைப்புகள் இல்லை என்றால், "இண்டெக்ஸ்" எனப்படும் கோப்பு ஆரம்பப் பக்கமாக வழங்கப்படுகிறது.
    • /static/main.css- பாணிகளுக்கான கோப்பு. முந்தைய திட்டத்தைப் போலவே, இங்கே எல்லாம் உங்களுடையது, நீங்கள் விரும்பியபடி வண்ணம் தீட்டவும்.
    • /static/jquery-3.6.0.min.js- எங்கள் சேவையகம் நிலையானதாக விநியோகிக்கும் முன்நிலை சார்பு.
  6. "com.tictactoe" தொகுப்பில் அனைத்து ஜாவா குறியீடும் இருக்கும். இப்போது 2 வகுப்புகள் உள்ளன:
    • Sign- enum, இது "குறுக்கு / பூஜ்யம் / வெற்றிடத்திற்கு" பொறுப்பாகும் .
    • Fieldநமது களமாகும். இந்த வகுப்பில் "புலம்" வரைபடம் உள்ளது . தரவு சேமிப்பகத்தின் கொள்கை பின்வருமாறு இருக்கும்: டிக்-டாக்-டோ புலத்தின் செல்கள் பூஜ்ஜியத்திலிருந்து எண்ணப்படுகின்றன. முதல் வரியில் 0, 1 மற்றும் 2. இரண்டாவது: 3, 4 மற்றும் 5. மற்றும் பல. மேலும் 3 முறைகள் உள்ளன. "getEmptyFieldIndex" முதல் காலியான கலத்தைத் தேடுகிறது (ஆம், எங்கள் எதிரி மிகவும் புத்திசாலியாக இருக்க மாட்டார்). விளையாட்டு முடிந்ததா என்பதை "checkWin" சரிபார்க்கிறது. மூன்று சிலுவைகளின் வரிசை இருந்தால், அது ஒரு சிலுவையைத் தரும்; மூன்று பூஜ்ஜியங்களின் வரிசை இருந்தால், அது பூஜ்ஜியத்தைத் தரும். இல்லையெனில், அது காலியாக உள்ளது. "getFieldData" - "புலம்" வரைபடத்தின் மதிப்புகளை ஏறுவரிசையில் வரிசைப்படுத்தப்பட்ட பட்டியலாக வழங்குகிறது.
  7. டெம்ப்ளேட் பற்றிய விளக்கங்கள் முடிந்தது, இப்போது நீங்கள் பணியைத் தொடங்கலாம். 3 க்கு 3 அட்டவணையை வரைவதன் மூலம் ஆரம்பிக்கலாம். இதைச் செய்ய, பின்வரும் குறியீட்டை “index.jsp” இல் சேர்க்கவும் :
    <table>
    	<tr>
    		<td>0</td>
    		<td>1</td>
    		<td>2</td>
    	</tr>
    	<tr>
    		<td>3</td>
    		<td>4</td>
    		<td>5</td>
    	</tr>
    	<tr>
    		<td>6</td>
    		<td>7</td>
    		<td>8</td>
    	</tr>
    </table>
    பின்னர் அட்டவணையில் உள்ள எண்களை அகற்றி, அவற்றை குறுக்கு, பூஜ்யம் அல்லது வெற்று புலத்துடன் மாற்றுவோம். மேலும், "தலை" குறிச்சொல்லின் உள்ளே, நடை கோப்பை சேர்க்கவும். இதைச் செய்ய, ஒரு வரியைச் சேர்க்கவும்:<link href="static/main.css" rel="stylesheet">

    பாணி கோப்பின் உள்ளடக்கம் உங்களுடையது. நான் இதைப் பயன்படுத்தினேன்:
    td {
        border: 3px solid black;
        padding: 10px;
        border-collapse: separate;
        margin: 10px;
        width: 100px;
        height: 100px;
        font-size: 50px;
        text-align: center;
        empty-cells: show;
    }
    இயங்கிய பிறகு, எனது முடிவு இப்படி இருக்கும்:
  8. இப்போது பின்வரும் செயல்பாட்டைச் சேர்ப்போம்: ஒரு செல் கிளிக் செய்தால், ஒரு கோரிக்கை சேவையகத்திற்கு அனுப்பப்படும், அதில் ஒரு அளவுருவாக கிளிக் செய்யப்பட்ட கலத்தின் குறியீட்டை அனுப்புவோம். இந்த பணியை இரண்டு பகுதிகளாகப் பிரிக்கலாம்: முன்பக்கத்திலிருந்து ஒரு கோரிக்கையை அனுப்பவும், சேவையகத்தில் கோரிக்கையை ஏற்கவும். ஒரு மாற்றத்திற்காக முன்பக்கத்தில் இருந்து ஆரம்பிக்கலாம்.

    ஒவ்வொரு "d" குறிச்சொல்லுக்கும் "onclick" அளவுருவைச் சேர்ப்போம் . மதிப்பில், குறிப்பிட்ட URLக்கு தற்போதைய பக்கத்தின் மாற்றத்தைக் குறிப்பிடுகிறோம். தர்க்கத்திற்குப் பொறுப்பாக இருக்கும் சர்வ்லெட் URL "/logic" ஐக் கொண்டிருக்கும் . மேலும் இது "கிளிக்" என்ற அளவுருவை எடுக்கும் . எனவே பயனர் கிளிக் செய்த கலத்தின் குறியீட்டை அனுப்புவோம்.
    <table>
        <tr>
            <td onclick="window.location='/logic?click=0'">0</td>
            <td onclick="window.location='/logic?click=1'">1</td>
            <td onclick="window.location='/logic?click=2'">2</td>
        </tr>
        <tr>
            <td onclick="window.location='/logic?click=3'">3</td>
            <td onclick="window.location='/logic?click=4'">4</td>
            <td onclick="window.location='/logic?click=5'">5</td>
        </tr>
        <tr>
            <td onclick="window.location='/logic?click=6'">6</td>
            <td onclick="window.location='/logic?click=7'">7</td>
            <td onclick="window.location='/logic?click=8'">8</td>
        </tr>
    </table>
    உலாவியில் உள்ள டெவலப்பர் பேனல் மூலம் அனைத்தும் சரியாகச் செய்யப்பட்டுள்ளதா என்பதைச் சரிபார்க்கலாம். எடுத்துக்காட்டாக, Chrome இல், இது F12 பொத்தானைக் கொண்டு திறக்கும் . குறியீட்டு 4 உடன் ஒரு கலத்தில் கிளிக் செய்வதன் விளைவாக, படம் பின்வருமாறு இருக்கும்: "லாஜிக்" என்ற முகவரிக்கு சேவையகத்தை அனுப்பக்கூடிய ஒரு சர்வ்லெட்டை நாங்கள் இன்னும் உருவாக்காததால் பிழை ஏற்படுகிறது .
  9. "com.tictactoe" தொகுப்பில் "LogicServlet" வகுப்பை உருவாக்கவும், இது "javax.servlet.http.HttpServlet" வகுப்பிலிருந்து பெறப்பட வேண்டும் . வகுப்பில், "doGet" முறையை மேலெழுதவும் .

    மேலும் கிளிக் செய்யப்பட்ட கலத்தின் குறியீட்டைப் பெறும் ஒரு முறையைச் சேர்ப்போம். நீங்கள் ஒரு மேப்பிங்கையும் சேர்க்க வேண்டும் (இந்த சேவையகம் கோரிக்கையை இடைமறிக்கும் முகவரி). சிறுகுறிப்பு மூலம் இதைச் செய்ய நான் பரிந்துரைக்கிறேன் (ஆனால் நீங்கள் சிரமங்களை விரும்பினால், நீங்கள் web.xml ஐயும் பயன்படுத்தலாம்). பொதுவான சர்வ்லெட் குறியீடு:
    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 = "LogicServlet", value = "/logic")
    public class LogicServlet extends HttpServlet {
        @Override
    	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            int index = getSelectedIndex(req);
            resp.sendRedirect("/index.jsp");
        }
    
    
        private int getSelectedIndex(HttpServletRequest request) {
            String click = request.getParameter("click");
            boolean isNumeric = click.chars().allMatch(Character::isDigit);
            return isNumeric ? Integer.parseInt(click) : 0;
        }
    
    }
    இப்போது, ​​​​எந்த செல் மீதும் கிளிக் செய்யும் போது, ​​சர்வரில் இந்த கலத்தின் குறியீட்டைப் பெறுவோம் (நீங்கள் பிழைத்திருத்தத்தில் சேவையகத்தை இயக்குவதன் மூலம் உறுதிப்படுத்திக் கொள்ளலாம்). மேலும் கிளிக் செய்யப்பட்ட அதே பக்கத்திற்கு ஒரு வழிமாற்றம் இருக்கும்.
  10. இப்போது நாம் கிளிக் செய்யலாம், ஆனால் இது இன்னும் ஒரு விளையாட்டு அல்ல. விளையாட்டு தர்க்கத்தைக் கொண்டிருக்க, நீங்கள் கோரிக்கைகளுக்கு இடையில் விளையாட்டின் நிலையை (சிலுவைகள் எங்கே, பூஜ்ஜியங்கள் எங்கே) சேமிக்க வேண்டும். இதைச் செய்வதற்கான எளிதான வழி, இந்தத் தரவை அமர்வில் சேமிப்பதாகும். இந்த அணுகுமுறையுடன், அமர்வு சேவையகத்தில் சேமிக்கப்படும், மேலும் கிளையன்ட் "JSESSIONID" என்ற குக்கீயில் அமர்வு ஐடியைப் பெறுவார் . ஆனால் அமர்வு ஒவ்வொரு முறையும் உருவாக்கப்பட வேண்டிய அவசியமில்லை, ஆனால் விளையாட்டின் தொடக்கத்தில் மட்டுமே. இதற்கு மற்றொரு சர்வ்லெட்டைத் தொடங்குவோம், அதை "InitServlet" என்று அழைப்போம் . அதில் உள்ள “doGet” முறையை மேலெழுதுவோம், அதில் புதிய அமர்வை உருவாக்கி, ஒரு விளையாட்டு மைதானத்தை உருவாக்கி, இந்த ஆடுகளம் மற்றும் வகை பட்டியலை வைத்து அமர்வு பண்புக்கூறுகளில் உள்நுழைந்து, index.jsp க்கு “முன்னோக்கி ” அனுப்புவோம். பக்கம். குறியீடு:
    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 {
            // Create a new session
            HttpSession currentSession = req.getSession(true);
    
            // Create a playing field
            Field field = new Field();
            Map<Integer, Sign> fieldData = field.getField();
    
            // Get a list of field values
            List<Sign> data = field.getFieldData();
    
            // Adding field parameters to the session (needed to store state between requests)
            currentSession.setAttribute("field", field);
            // and field values ​​sorted by index (required for drawing crosses and zeroes)
            currentSession.setAttribute("data", data);
    
            // Redirect request to index.jsp page via server
            getServletContext().getRequestDispatcher("/index.jsp").forward(req, resp);
        }
    }
    மறக்காமல், சேவையகத்தைத் தொடங்கிய பிறகு, உலாவியில் திறக்கும் தொடக்கப் பக்கத்தை “/தொடக்கம்” என மாற்றுவோம் : இப்போது சேவையகத்தை மறுதொடக்கம் செய்து, உலாவி டெவலப்பர் மெனுவில் உள்ள புலத்தின் எந்த கலத்தையும் “கோரிக்கை தலைப்புகள்” பிரிவில் கிளிக் செய்த பிறகு. , அமர்வு ஐடியுடன் குக்கீ இருக்கும்:
  11. கிளையண்டின் (உலாவி) கோரிக்கைகளுக்கு இடையில் மாநிலத்தை சேமிக்கக்கூடிய ஒரு களஞ்சியத்தை எங்களிடம் இருந்தால், நாங்கள் கேம் லாஜிக்கை எழுத ஆரம்பிக்கலாம். எங்களிடம் உள்ள தர்க்கம் “LogicServlet” இல் உள்ளது . நாம் "doGet" முறையுடன் வேலை செய்ய வேண்டும் . இந்த நடத்தையை முறையுடன் சேர்ப்போம்:
    • அமர்விலிருந்து புல வகையின் "புலம்" பொருளைப் பெறுவோம் (அதை "எக்ஸ்ட்ராக்ட்ஃபீல்ட்" முறைக்கு எடுத்துச் செல்வோம் ).
    • பயனர் கிளிக் செய்த இடத்தில் குறுக்கு ஒன்றை வைக்கவும் (இதுவரை எந்த சோதனையும் இல்லாமல்).
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // Get the current session
        HttpSession currentSession = req.getSession();
    
        // Get the playfield object from the session
        Field field = extractField(currentSession);
    
        // get the index of the cell that was clicked
        int index = getSelectedIndex(req);
    
        // put a cross in the cell that the user clicked on
        field.getField().put(index, Sign.CROSS);
    
        // Read the list of icons
        List<Sign> data = field.getFieldData();
    
        // Update field object and icon list in session
        currentSession.setAttribute("data", data);
        currentSession.setAttribute("field", field);
    
        resp.sendRedirect("/index.jsp");
    }
    
    
    
    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;
    }
    நடத்தை இன்னும் மாறவில்லை, ஆனால் நீங்கள் பிழைத்திருத்தத்தில் சேவையகத்தைத் தொடங்கி, திசைதிருப்பல் அனுப்பப்படும் வரியில் முறிவுப் புள்ளியை அமைத்தால், " தரவு" பொருளின் "உள்"களைக் காணலாம் . உண்மையில், கிளிக் செய்யப்பட்ட குறியீட்டின் கீழ் "கிராஸ்" தோன்றும் .
  12. இப்போது சிலுவையை முன்பக்கத்தில் காட்ட வேண்டிய நேரம் வந்துவிட்டது. இதைச் செய்ய, "index.jsp" கோப்பு மற்றும் "JSTL" தொழில்நுட்பத்துடன் வேலை செய்வோம் .
    • <head> பிரிவில் சேர்:<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    • ஒவ்வொரு <td> தொகுதிக்குள்ளும் உள்ள அட்டவணையில், குறியீட்டை ஒரு கட்டமைப்பிற்கு மாற்றவும், இது மதிப்புகளைக் கணக்கிட உங்களை அனுமதிக்கிறது. எடுத்துக்காட்டாக, குறியீட்டு பூஜ்ஜியத்திற்கு: <td onclick="window.location='/logic?click=0'">${data.get(0).getSign()}</td> இப்போது, ​​நீங்கள் ஒரு கலத்தில் கிளிக் செய்யும் போது, ​​அங்கு ஒரு குறுக்கு தோன்றும்:
  13. நாங்கள் எங்கள் நகர்வைச் செய்துவிட்டோம், இப்போது அது "பூஜ்ஜியத்திற்கான" முறை. ஏற்கனவே ஆக்கிரமிக்கப்பட்ட கலங்களில் அடையாளங்கள் வைக்கப்படாமல் இருக்க, இங்கே இரண்டு காசோலைகளைச் சேர்ப்போம்.
    • கிளிக் செய்த செல் காலியாக உள்ளதா என்பதைச் சரிபார்க்க வேண்டும். இல்லையெனில், நாங்கள் எதுவும் செய்யாமல், அமர்வு அளவுருக்களை மாற்றாமல் அதே பக்கத்திற்கு பயனரை அனுப்புவோம்.
    • புலத்தில் உள்ள கலங்களின் எண்ணிக்கை ஒற்றைப்படையாக இருப்பதால், சிலுவை வைக்கப்பட்டிருக்கலாம், ஆனால் பூஜ்ஜியத்திற்கு இடமில்லை. எனவே, நாம் ஒரு குறுக்கு போட்ட பிறகு, ஆக்கிரமிக்கப்படாத கலத்தின் குறியீட்டைப் பெற முயற்சிக்கிறோம் (புலம் வகுப்பின் getEmptyFieldIndex முறை). குறியீடு எதிர்மறையாக இல்லாவிட்டால், அங்கு பூஜ்ஜியத்தை வைக்கவும். குறியீடு:
      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 {
              // Get the current session
              HttpSession currentSession = req.getSession();
      
              // Get the playfield object from the session
              Field field = extractField(currentSession);
      
              // get the index of the cell that was clicked
              int index = getSelectedIndex(req);
              Sign currentSign = field.getField().get(index);
      
              // Check if the clicked cell is empty.
              // Otherwise, we do nothing and send the user to the same page without changes
              // parameters in the session
              if (Sign.EMPTY != currentSign) {
                  RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/index.jsp");
                  dispatcher.forward(req, resp);
                  return;
              }
      
              // put a cross in the cell that the user clicked on
              field.getField().put(index, Sign.CROSS);
      
              // Get an empty field cell
              int emptyFieldIndex = field.getEmptyFieldIndex();
      
              if (emptyFieldIndex >= 0) {
                  field.getField().put(emptyFieldIndex, Sign.NOUGHT);
              }
      
              // Read the list of icons
              List<Sign> data = field.getFieldData();
      
              // Update field object and icon list in session
              currentSession.setAttribute("data", data);
              currentSession.setAttribute("field", field);
      
              resp.sendRedirect("/index.jsp");
          }
      
          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;
          }
      }
  14. இந்த கட்டத்தில், நீங்கள் சிலுவைகள், AI பதில்களை பூஜ்ஜியங்களுடன் வைக்கலாம். ஆனால் விளையாட்டை எப்போது நிறுத்துவது என்பது தெரியவில்லை. இது மூன்று சந்தர்ப்பங்களில் இருக்கலாம்:
    • சிலுவையின் அடுத்த நகர்வுக்குப் பிறகு, மூன்று சிலுவைகளின் கோடு உருவாக்கப்பட்டது;
    • பூஜ்ஜியத்துடன் அடுத்த திரும்பும் நகர்வுக்குப் பிறகு, மூன்று பூஜ்ஜியங்களின் கோடு உருவாக்கப்பட்டது;
    • சிலுவையின் அடுத்த நகர்வுக்குப் பிறகு, வெற்று செல்கள் முடிந்தது.
    ஒரு வரிசையில் மூன்று குறுக்குகள் / பூஜ்ஜியங்கள் உள்ளதா என்பதைச் சரிபார்க்கும் முறையைச் சேர்ப்போம்:
    /**
     * The method checks if there are three X/O's in a row.
     * returns true/false
     */
    private boolean checkWin(HttpServletResponse response, HttpSession currentSession, Field field) throws IOException {
        Sign winner = field.checkWin();
        if (Sign.CROSS == winner || Sign.NOUGHT == winner) {
            // Add a flag to indicate that someone has won
            currentSession.setAttribute("winner", winner);
    
            // Read the list of icons
            List<Sign> data = field.getFieldData();
    
            // Update this list in session
            currentSession.setAttribute("data", data);
    
            // helmet redirect
            response.sendRedirect("/index.jsp");
            return true;
        }
        return false;
    }
    இந்த முறையின் தனித்தன்மை என்னவென்றால், வெற்றியாளர் கண்டுபிடிக்கப்பட்டால், அமர்வில் மற்றொரு அளவுருவைச் சேர்ப்போம், அதைப் பயன்படுத்தி பின்வரும் பத்திகளில் "index.jsp" இல் காட்சியை மாற்றுவோம் .
  15. "checkWin " முறைக்கு அழைப்பை இருமுறை "doGet" முறையில் சேர்ப்போம் . குறுக்கு அமைத்த பிறகு முதல் முறையாக, இரண்டாவது - பூஜ்ஜியத்தை அமைத்த பிறகு.
    // Check if the cross won after adding the user's last click
    if (checkWin(resp, currentSession, field)) {
        return;
    }
    if (emptyFieldIndex >= 0) {
        field.getField().put(emptyFieldIndex, Sign.NOUGHT);
        // Check if the zero won after adding the last zero
        if (checkWin(resp, currentSession, field)) {
            return;
        }
    }
  16. நடத்தையின் அடிப்படையில், ஏறக்குறைய எதுவும் மாறவில்லை (அடையாளங்களில் ஒன்று வெற்றி பெற்றால், பூஜ்ஜியங்கள் இனி வைக்கப்படாது. "index.jsp" இல் "வெற்றியாளர்" அளவுருவைப் பயன்படுத்தி வெற்றியாளரைக் காண்பிப்போம். அட்டவணைக்குப் c:setபிறகு வழிகாட்டுதல்களைப் பயன்படுத்துகிறோம்:c:if
    <hr>
    <c:set var="CROSSES" value="<%=Sign.CROSS%>"/>
    <c:set var="NOUGHTS" value="<%=Sign.NOUGHT%>"/>
    
    <c:if test="${winner == CROSSES}">
        <h1>CROSSES WIN!</h1>
    </c:if>
    <c:if test="${winner == NOUGHTS}">
        <h1>NOUGHTS WIN!</h1>
    </c:if>
    சிலுவைகள் வெற்றி பெற்றால், "CROSSES WIN!" , பூஜ்ஜியங்கள் "தேவைகள் வெற்றி!" . இதன் விளைவாக, நாம் இரண்டு கல்வெட்டுகளில் ஒன்றைப் பெறலாம்:
  17. ஒரு வெற்றியாளர் இருந்தால், நீங்கள் பழிவாங்க வேண்டும். இதைச் செய்ய, உங்களுக்கு ஒரு பொத்தான் தேவை, அது சேவையகத்திற்கு கோரிக்கையை அனுப்பும். சேவையகம் தற்போதைய அமர்வை செல்லாததாக்கி கோரிக்கையை "/தொடக்கம்" க்கு திருப்பிவிடும் .
    • "index.jsp" இல் "தலை" பிரிவில் , "jquery" ஸ்கிரிப்டை எழுதவும் . இந்த நூலகத்தைப் பயன்படுத்தி, சேவையகத்திற்கு கோரிக்கையை அனுப்புவோம்.
      <script src="<c:url value="/static/jquery-3.6.0.min.js"/>"></script>
    • "ஸ்கிரிப்ட்" பிரிவில் உள்ள "index.jsp" இல் , சேவையகத்திற்கு POST கோரிக்கையை அனுப்பக்கூடிய செயல்பாட்டைச் சேர்க்கவும். நாங்கள் செயல்பாட்டை ஒத்திசைக்கச் செய்வோம், மேலும் சேவையகத்திலிருந்து பதில் வரும்போது, ​​அது தற்போதைய பக்கத்தை மீண்டும் ஏற்றும்.
      <script>
          function restart() {
              $.ajax({
                  url: '/restart',
                  type: 'POST',
                  contentType: 'application/json;charset=UTF-8',
                  async: false,
                  success: function () {
                      location.reload();
                  }
              });
          }
      </script>
    • “c:if” தொகுதிகளுக்குள் , ஒரு பொத்தானைச் சேர்க்கவும், அதைக் கிளிக் செய்யும் போது, ​​நாம் இப்போது எழுதிய செயல்பாட்டை அழைக்கிறது:
      <c:if test="${winner == CROSSES}">
          <h1>CROSSES WIN!</h1>
          <button onclick="restart()">Start again</button>
      </c:if>
      <c:if test="${winner == NOUGHTS}">
          <h1>NOUGHTS WIN!</h1>
          <button onclick="restart()">Start again</button>
      </c:if>
    • "/மறுதொடக்கம்" URL ஐ வழங்கும் புதிய சர்வ்லெட்டை உருவாக்குவோம் .
      package com.tictactoe;
      
      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 IOException {
              req.getSession().invalidate();
              resp.sendRedirect("/start");
          }
      }
      வெற்றிக்குப் பிறகு, "மீண்டும் தொடங்கு" பொத்தான் தோன்றும் . அதைக் கிளிக் செய்த பிறகு, புலம் முற்றிலும் அழிக்கப்படும், மேலும் விளையாட்டு மீண்டும் தொடங்கும்.
  18. கடைசி சூழ்நிலையை கருத்தில் கொள்ள வேண்டும். பயனர் சிலுவை போட்டால், வெற்றி இல்லை, பூஜ்ஜியத்திற்கு இடமில்லை என்றால் என்ன செய்வது? பின்னர் இது ஒரு டிரா, அதை இப்போது செயலாக்குவோம்:
    • "LogicServlet" அமர்வில் , "டிரா" என்ற மற்றொரு அளவுருவைச் சேர்த்து , "தரவு" புலத்தைப் புதுப்பித்து, "index.jsp" க்கு திருப்பி அனுப்பவும் :
      // If such a cell exists
      if (emptyFieldIndex >= 0) {}
      // If there is no empty cell and no one wins, then it's a draw
      else {
          // Add a flag to the session that signals that a draw has occurred
          currentSession.setAttribute("draw", true);
      
          // Read the list of icons
          List<Sign> data = field.getFieldData();
      
          // Update this list in session
          currentSession.setAttribute("data", data);
      
          // helmet redirect
          response.sendRedirect("/index.jsp");
          return;
      }
    • "index.jsp" இல் இந்த அளவுருவை செயலாக்குவோம்:
      <c:if test="${draw}">
          <h1>IT'S A DRAW</h1>
          <br>
          <button onclick="restart()">Start again</button>
      </c:if>
      டிராவின் விளைவாக, தொடர்புடைய செய்தியையும் மீண்டும் தொடங்குவதற்கான சலுகையையும் பெறுவோம்:

இது விளையாட்டின் எழுத்தை நிறைவு செய்கிறது.

அவர்கள் பணிபுரிந்த வகுப்புகள் மற்றும் கோப்புகளின் குறியீடு

InitServlet

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 {
        // Create a new session
        HttpSession currentSession = req.getSession(true);

        // Create a playing field
        Field field = new Field();
        Map<Integer, Sign> fieldData = field.getField();

        // Get a list of field values
        List<Sign> data = field.getFieldData();

        // Adding field parameters to the session (needed to store state between requests)
        currentSession.setAttribute("field", field);
        // and field values ​​sorted by index (required for drawing crosses and zeroes)
        currentSession.setAttribute("data", data);

        // Redirect request to index.jsp page via server
        getServletContext().getRequestDispatcher("/index.jsp").forward(req, resp);
    }
}

லாஜிக் சர்வ்லெட்

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 {
        // Get the current session
        HttpSession currentSession = req.getSession();

        // Get the playfield object from the session
        Field field = extractField(currentSession);

        // get the index of the cell that was clicked
        int index = getSelectedIndex(req);
        Sign currentSign = field.getField().get(index);

        // Check if the clicked cell is empty.
        // Otherwise, we do nothing and send the user to the same page without changes
        // parameters in the session
        if (Sign.EMPTY != currentSign) {
            RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/index.jsp");
            dispatcher.forward(req, resp);
            return;
        }

        // put a cross in the cell that the user clicked on
        field.getField().put(index, Sign.CROSS);

        // Check if the cross has won after adding the user's last click
        if (checkWin(resp, currentSession, field)) {
            return;
        }

        // Get an empty field cell
        int emptyFieldIndex = field.getEmptyFieldIndex();

        if (emptyFieldIndex >= 0) {
            field.getField().put(emptyFieldIndex, Sign.NOUGHT);
            // Check if the zero won after adding the last zero
            if (checkWin(resp, currentSession, field)) {
                return;
            }
        }
        // If there is no empty cell and no one wins, then it's a draw
        else {
            // Add a flag to the session that signals that a draw has occurred
            currentSession.setAttribute("draw", true);

            // Read the list of icons
            List<Sign> data = field.getFieldData();

            // Update this list in session
            currentSession.setAttribute("data", data);

            // helmet redirect
            resp.sendRedirect("/index.jsp");
            return;
        }

        // Read the list of icons
        List<Sign> data = field.getFieldData();

        // Update field object and icon list in session
        currentSession.setAttribute("data", data);
        currentSession.setAttribute("field", field);

        resp.sendRedirect("/index.jsp");
    }

    /**
     * The method checks if there are three X/O's in a row.
     * returns true/false
     */
    private boolean checkWin(HttpServletResponse response, HttpSession currentSession, Field field) throws IOException {
        Sign winner = field.checkWin();
        if (Sign.CROSS == winner || Sign.NOUGHT == winner) {
            // Add a flag to indicate that someone has won
            currentSession.setAttribute("winner", winner);

            // Read the list of icons
            List<Sign> data = field.getFieldData();

            // Update this list in session
            currentSession.setAttribute("data", data);

            // helmet redirect
            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 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;
    }
}

RestartServlet

package com.tictactoe;

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 IOException {
        req.getSession().invalidate();
        resp.sendRedirect("/start");
    }
}

index.jsp_ _

<%@ page import="com.tictactoe.Sign" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<!DOCTYPE html>
<html>
<head>
    <link href="static/main.css" rel="stylesheet">
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <script src="<c:url value="/static/jquery-3.6.0.min.js"/>"></script>
    <title>Tic-Tac-Toe</title>
</head>
<body>
<h1>Tic-Tac-Toe</h1>

<table>
    <tr>
        <td onclick="window.location='/logic?click=0'">${data.get(0).getSign()}</td>
        <td onclick="window.location='/logic?click=1'">${data.get(1).getSign()}</td>
        <td onclick="window.location='/logic?click=2'">${data.get(2).getSign()}</td>
    </tr>
    <tr>
        <td onclick="window.location='/logic?click=3'">${data.get(3).getSign()}</td>
        <td onclick="window.location='/logic?click=4'">${data.get(4).getSign()}</td>
        <td onclick="window.location='/logic?click=5'">${data.get(5).getSign()}</td>
    </tr>
    <tr>
        <td onclick="window.location='/logic?click=6'">${data.get(6).getSign()}</td>
        <td onclick="window.location='/logic?click=7'">${data.get(7).getSign()}</td>
        <td onclick="window.location='/logic?click=8'">${data.get(8).getSign()}</td>
    </tr>
</table>

<hr>
<c:set var="CROSSES" value="<%=Sign.CROSS%>"/>
<c:set var="NOUGHTS" value="<%=Sign.NOUGHT%>"/>

<c:if test="${winner == CROSSES}">
    <h1>CROSSES WIN!</h1>
    <button onclick="restart()">Start again</button>
</c:if>
<c:if test="${winner == NOUGHTS}">
    <h1>NOUGHTS WIN!</h1>
    <button onclick="restart()">Start again</button>
</c:if>
<c:if test="${draw}">
    <h1>IT'S A DRAW</h1>
    <button onclick="restart()">Start again</button>
</c:if>

<script>
    function restart() {
        $.ajax({
            url: '/restart',
            type: 'POST',
            contentType: 'application/json;charset=UTF-8',
            async: false,
            success: function () {
                location.reload();
            }
        });
    }
</script>

</body>
</html>

main.css _

td {
    border: 3px solid black;
    padding: 10px;
    border-collapse: separate;
    margin: 10px;
    width: 100px;
    height: 100px;
    font-size: 50px;
    text-align: center;
    empty-cells: show;
   }