Why does Javascript Tic-Tac-Toe delay notifying the user until the entire board is full?

There have been a lot of questions about Tic-Tac-Toe javascript, but my issue is unique. My code works fine, but it doesn't declare a winner or a tie game until the entire board is filled. I suspect that my if statements are causing problems and can't read a "nodeValue of null" unless the whole board is fully populated. How can I solve this? I tried adding a "blank" text node to the board, but then all blank squares become equal. Is there a way to compare empty squares with filled ones to determine a win? (Specifically looking at the Array defined in the start_game() function and the if statements inside the beat_game() function for comparing 2-D arrays). Besides addressing this, any suggestions on improving my js code are welcome. Here's the code snippet:

<html>

<head>
    <script type="text/javascript">
        window.onload = function page_load() {
       // alert('in here');
            start_game();
        }

        function start_game() {
           if (document.getElementById('board')) {
                document.getElementById('board').parentNode.removeChild(document.getElementById('board'));
            }
            win_Array = [
                [
                    'TL',
                    'TM',
                    'TR'
                ],
                [
                    'ML',
                    'MM',
                    'MR'
                ],
                [
                    'BL',
                    'BM',
                    'BR'
                ]
            ];
            body = document.getElementsByTagName('body')[0];
            table = document.createElement('table');
            table.id = 'board';
            table.setAttribute('border', '1');
            body.appendChild(table);
            tbody = document.createElement('tbody');
            table.appendChild(tbody);
            run = 0;
            win = 0;
            var count;
            td_Array = [{
                t: 'TL',
                m: 'ML',
                b: 'BL'
            }, {
                t: 'TM',
                m: 'MM',
                b: 'BM'
            }, {
                t: 'TR',
                m: 'MR',
                b: 'BR'
            }];
            tr = document.createElement('tr');
            tr.id = "tr1";
            tbody.appendChild(tr);
            for (count = 0; count <= 2; count++) {
                td = document.createElement('td');
                td.id = td_Array[count].t;
                td.setAttribute('onClick', 'value("' + td_Array[count].t + '")');
                tr.appendChild(td);
            }
            tr = document.createElement('tr');
            tr.id = "tr2";
            tbody.appendChild(tr);
            for (count = 0; count <= 2; count++) {
                td = document.createElement('td');
                td.id = td_Array[count].m;
                td.setAttribute('onClick', 'value("' + td_Array[count].m + '")');
                tr.appendChild(td);
            }
            tr = document.createElement('tr');
            tr.id = "tr3";
            tbody.appendChild(tr);
            for (count = 0; count <= 2; count++) {
                td = document.createElement('td');
                td.id = td_Array[count].b;
                td.setAttribute('onClick', 'value("' + td_Array[count].b + '")');
                tr.appendChild(td);
            }
        }

        function value(data) {
            console.log(data);
            console.log(document.getElementById(data));
            if (run % 2 !== 0) {
                td = document.getElementById(data);
                text = document.createTextNode('O');
                td.appendChild(text);
                document.getElementById(data).removeAttribute('onClick');
            } else {
                td = document.getElementById(data);
                text = document.createTextNode('X');
                td.appendChild(text);
                document.getElementById(data).removeAttribute('onClick');
            } //document.getElementById('').childNodes[0].nodeValue //node value prevents error.
            run++;
                beat_game();
        }

        function beat_game() {
           // alert('test sucessful');
            var x, y;

                for (x = 0; x < 3; x++) 
                { //for checking across td's
                   if (document.getElementById(win_Array[x][0]).childNodes[0].nodeValue == document.getElementById(win_Array[x][1]).childNodes[0].nodeValue 
                   && document.getElementById(win_Array[x][1]).childNodes[0].nodeValue == document.getElementById(win_Array[x][2]).childNodes[0].nodeValue) 
                    {
                        win = true;
                        win_value = document.getElementById(win_Array[x][0]).childNodes[0].nodeValue;
                    } 
                }
                for (y = 0; y < 3; y++) 
                { //for checking down td's
                    if (document.getElementById(win_Array[0][y]).childNodes[0].nodeValue == document.getElementById(win_Array[1][y]).childNodes[0].nodeValue
                    && document.getElementById(win_Array[1][y]).childNodes[0].nodeValue == document.getElementById(win_Array[2][y]).childNodes[0].nodeValue)
                    {
                        win = true;
                        win_value = document.getElementById(win_Array[0][y]).childNodes[0].nodeValue;
                    }
                } // checking across values here...
                    if ( document.getElementById(win_Array[0][0]).childNodes[0].nodeValue == document.getElementById(win_Array[1][1]).childNodes[0].nodeValue
                    && document.getElementById(win_Array[1][1]).childNodes[0].nodeValue == document.getElementById(win_Array[2][2]).childNodes[0].nodeValue
                    || document.getElementById(win_Array[0][2]).childNodes[0].nodeValue == document.getElementById(win_Array[1][1]).childNodes[0].nodeValue
                    && document.getElementById(win_Array[1][1]).childNodes[0].nodeValue == document.getElementById(win_Array[2][0]).childNodes[0].nodeValue)
                    {
                        win = true;
                        win_value = document.getElementById(win_Array[0][0]).childNodes[0].nodeValue;
                    }
                    if(win == true)
                    {
                        if(win_value == 'X')
                        {
                            alert('Player 1 Wins!');
                        }else{
                            alert('Player 2 Wins!');
                        }
                    }else {
                        alert("Cat's Game!");
                    }
        } 
    </script>
    <style>
        td {
            width: 50px;
            height: 50px;
            text-align: center;
        }
        body {
            font-size: 6;
        }
    </style>
</head>

<body>
</body>

</html>

Thank you!

Answer №1

It appears that the issue lies within your beat_game() function.

A problem arises when trying to access the nodeValue attribute from a td cell's child node (e.g.,

document.getElementById(win_Array[x][0]).childNodes[0]
) as there may not be a child node present, resulting in an exception.

To rectify this, consider using a more reliable method of retrieving the cell's value by utilizing innerHTML instead:

document.getElementById(win_Array[x][0]).innerHTML

To address the uniformity of all blank squares being considered equal and triggering a win condition, incorporate an additional validation check to confirm the presence of a value in the cell before determining win = true. By implementing these suggestions, one of the loops could resemble the following:

for (x = 0; x < 3; x++) 
    { //for checking across td's
    if (document.getElementById(win_Array[x][0]).innerHTML == document.getElementById(win_Array[x][1]).innerHTML 
    && document.getElementById(win_Array[x][1]).innerHTML == document.getElementById(win_Array[x][2]).innerHTML) 
     {
          win_value = document.getElementById(win_Array[x][0]).innerHTML;
          win = win_value ? true : false;
     } 
}

Upon making these adjustments, you may encounter a new issue where the game repeatedly displays "Cat's game!". This is due to always defaulting to the else case if win is false after winning checks. To resolve this, consider utilizing the run variable to track the maximum number of moves reached.

Furthermore, there seems to be an error in your final diagonal check condition. The win_value is consistently assigned as the top-left element on the board, despite potential variations given the consolidation of both diagonal cases into a single statement.

I hope these insights prove helpful!

Answer №2

Upon investigating the script, an issue caught my attention with the following line (as well as similar variations):

 document.getElementById(win_Array[x][0]).childNodes[0].nodeValue == document.getElementById(win_Array[x][1]).childNodes[0].nodeValue

It is important to note that childNodes[0] may not always be defined - during the initial run, the table may not contain any table cells with child nodes. Only when you input an X or an O does it create a child node within the table cell. When there are no Xs or Os, there will be no child node present, resulting in an error upon each move. This highlights the necessity for completing the game to determine a winner.

My recommendation would be to implement a separate 3x3 array (an array of arrays in JS) consisting of strings or numbers, which can then be used to verify winning conditions.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

My code seems to be malfunctioning

I'm attempting to conceal the chatname div. Once hidden, I want to position the chatid at the bottom, which is why the value 64px is utilized. However, I encountered an error stating The function toggle3(); has not been defined. <div id="chat ...

What is the best way to loop through <div> elements that have various class names using Python 3.7 and the Selenium webdriver?

I am currently in the process of creating a Reddit bot that provides me with a detailed report about my profile. One task I need to accomplish is identifying which of my comments has received the most likes. Each comment on Reddit is wrapped in elements w ...

What is the trick to incorporating nested tabs within tabs?

My tabs are functional and working smoothly. To view the jsfiddle, click here - http://jsfiddle.net/K3WVG/ I am looking for a way to add nested tabs within the existing tabs. I would prefer a CSS/HTML solution, but a JavaScript/jQuery method is also acce ...

Intermittent issue with Webdriver executeScript failing to detect dynamically created elements

It has taken me quite a while to come to terms with this, and I am still facing difficulties. My goal is to access dynamically generated elements on a web page using JavaScript injection through Selenium WebDriver. For instance: String hasclass = js.exec ...

What is the best way to create a miniaturized image of a webpage for sharing on Facebook?

I'm looking for a way to post a link to users' Facebook walls with a thumbnail image of their created page. The page is in HTML format and stored as a series of 'elements' in the database, each with its size, position, and content. Is i ...

Is it possible to connect ng-model with a style tag?

Is it feasible to create a basic template editor using angularjs where an input field with an ng-model can be connected to a style tag to control the css on an entire page rather than applying it to a specific element with inline styling? Could something ...

Using jQuery and PHP to send a dynamic form through AJAX

I'm currently working on a pet registration form where users can add new pets. When a user clicks the "add pet" button, I use jQuery to clone the pet section of the form and give each cloned section an id like #pet-2, #pet-3, and so on. Although my ...

Merging the outcomes of a JSON call

Presently, I have an async function that returns a JSON response in the form of an array containing two objects. Please refer to the screenshot. https://i.sstatic.net/gCP8p.png How can I merge these objects to obtain: [{resultCount: 100, results: Array(1 ...

Tips for eliminating double quotes from an input string

I am currently developing an input for a website that will generate a div tag along with its necessary child elements to ensure the website functions correctly. I have a couple of key questions regarding this setup: <!DOCTYPE html> <html> < ...

issue with displaying content in bootstrap tabs

Every time I attempt to load a tab, it redirects me to the homepage. Just for reference, I am using AngularJS as my JavaScript framework. <div class="container"> <h1> Tab Panel </h1> </div> <div id="exTab1" class="container"&g ...

The coloring feature in Excel Add-in's React component fails to populate cells after the "await" statement

Currently, I am developing a Microsoft Excel Add-in using React. My goal is to assign colors to specific cells based on the value in each cell, indicated by a color code (refer to the Board Color column in the image below). To achieve this, I retrieve the ...

Generate a single-page PDF document mirroring the content of a website

I'm facing a dilemma. I need to generate a one-page PDF file without any gaps between the pages. Despite trying numerous plugins, add-ons, scripts, and software, all of them produce multiple pages. What I really require is to have all the pages in a s ...

"Maintaining Consistency: Ensuring The First Row is Repeated on Every

When trying to save a PDF using jspdf, I encountered an issue with tables in my HTML. The tables do not have headers, but JsPDF is automatically repeating the first row of the table on every page, causing overlap. I don't want headers on every new pag ...

Tips for successfully sending a nested function to an HTML button and dropdown menu

I'm working on two main functions - getChart() and fetchData(). The goal is to retrieve chart data and x/y axes information from a database. Within the getChart function, I'd like to incorporate a dropdown menu for displaying different types of c ...

Determining when a message has been ignored using php

One of the features I am working on for my app is adding announcements, which are essentially personalized messages to users. Once a user receives a message and dismisses it, I want to ensure that specific message does not appear again. Here is the PHP co ...

The while-loop using Regex adds only a single value to my array

Within my variable htmlContent, there lies a string filled with properly formatted HTML code, which includes various img tags. The goal is to extract each value from the src attribute of these images and place them all in an array named srcList. The issu ...

JavaScript Promise Synchronization

I have a JavaScript function that returns an object using promises. The first time the function is called, it fetches the object, but for subsequent calls, it returns a cached instance. To simulate the fetching process, I've added a delay. var Promis ...

Arranging Divs into Two Columns in CSS - A Simple Guide

I'm trying to display a variable number of divs across two lines, like this: [1] [3] [5] [7] [2] [4] [6] ... I've explored using the column-count property in CSS, but it doesn't quite fit my needs since it requires a fixed number of ...

JavaScript appendChild method not functioning properly with dynamically created image elements in JavaScript code

I recently encountered an issue while working on a website project. I was trying to create an img element using JavaScript, but ran into a problem when I tried to add the src attribute and then use the appendChild function. I'm unsure if I am missing ...

"Authentic JavaScript Universal Time Coordinated (UTC) Date

I've been struggling to keep my dates in UTC within my JavaScript application. Surprisingly, the Date's getTimezoneOffset() method does not return a value of 0, which I expected it to do. This seems crucial for accurately converting dates between ...