What is causing the error when running multiple loops in the logic function of this tic-tac-toe game?

I've been tackling the logic for determining the winner in a Tic Tac Toe game, and found inspiration from this reference:

Connect Four Game Checking for Wins JS

The original win check algorithm was designed for a Connect Four game, so I made some adjustments.

When I run a single loop, like checking for down wins, it works fine. However, if I try to run both loops simultaneously, I encounter this error.

TTT.js:121 Uncaught TypeError: Cannot read properties of undefined (reading '0')
    at Object.checkWinner (TTT.js:121)
    at <anonymous>:1:4

Searching online for solutions to this error didn't yield much help.

const gameBoard = (() => {
    const rows = 3;
    const columns = 3;
    const board = [];

    // creating a 2D array in the console
    for (let i = 0; i < rows; i++) {
        board[i] = [];
        for (let j = 0; j < columns; j++) {
            board[i].push(Cell());
        }
    }

    // method for retrieving the entire board for UI rendering
    const getboard = () => board;

    const printBoard = () => {
        const boardWithCellValues = board.map((row) => row.map((cell) => cell.getValue()));
        console.log(boardWithCellValues);
        return boardWithCellValues;
        
    }


    // playMove function for available space checking and validating moves



    const playMove = (row, column, player) => {
        const availableCells = board.filter((row) => row.map((cell) => cell.getValue().value = 0));
        board[row][column].addToken(player);
    };

    return {
        getboard,
        printBoard,
        playMove,
        board
    }
})(); 



// cell represents one square on the board
function Cell() {
    let value = 0;   

    
    const addToken = (player) => {
        value = player;
        return value;
    }

   
    const getValue = () => value;

    return {
        getValue,
        addToken
    }
}


// GameController module/function. Controls flow of game, win logic


function gameController(
    playerOneName = "Player One",
    playerTwoName = "Player Two"
) {

    

    const players = [
        {
            name : playerOneName,
            token : 1
        },
        {
            name : playerTwoName,
            token : 2
        }
    ];

    
    let activePlayer = players[0];
    

    const switchPlayerTurn = () => {  
        activePlayer = activePlayer === players[0] ? players[1] : players[0];
    };


    const getActivePlayer = () => activePlayer;

    const printNewRound = () => {
        gameBoard.printBoard();
        console.log(`${getActivePlayer().name}'s turn'`);
    };

    function checkLine (a,b,c) {
        return ((a != 0) && (a == b) && (a == c));
    }

    function checkWinner (bd) {     

           
         
          
            
            for (r = 0; r < 3; r++)
                for (c = 0; c < 3; c++)
                    if (checkLine(bd[r][c], bd[r+1][c], bd[r+2][c])) {
                        return bd[r][c]; 
                    }
                    
                    
             
          
            for (r = 0; r < 3; r++)
                for (c = 0; c < 3; c++)
                    if (checkLine(bd[r][c], bd[r][c+1], bd[r][c+2])) {
                        return bd[r][c];
                    }
                    
                      
                    
                    
            return 0;          
    };

    const playRound = (row, column) => {
        gameBoard.playMove(row, column, getActivePlayer().token);

        


        

        switchPlayerTurn();
        printNewRound();
    }

    return {
        activePlayer,
        switchPlayerTurn,
        getActivePlayer,
        players,
        printNewRound,
        playRound,
        checkWinner
    };      
}

const gc = gameController();


gc.playRound(0,0);  
gc.playRound(1,0);
gc.playRound(0,1); 
gc.playRound(2,2); 
gc.playRound(0,2); 


/*
gc.playRound(0,0);  
gc.playRound(0,1); 
gc.playRound(1,0); 
gc.playRound(2,2); 
gc.playRound(2,0); 
*/

I have included code below to auto-populate the array with player tokens in the console. Example:

(3) [Array(3), Array(3), Array(3)]
0: (3) [1, 1, 1]
1: (3) [2, 0, 0]
2: (3) [0, 0, 2]

Individually, these loops work fine. But when combined as intended above, with the down check preceding the right check, it throws the mentioned error.

Why am I encountering issues trying to execute both loops?

Answer №1

It appears that a logical error can be found within your checkWinner function, specifically here:

for (r = 0; r < 3; r++)
    for (c = 0; c < 3; c++)
        if (checkLine(bd[r][c], bd[r+1][c], bd[r+2][c])) {
            return bd[r][c]; 
        }

You may notice that the if statement is being executed 9 times as a result of the nested loops, even though there are only 3 columns to check. This leads to issues when trying to access bd[r+2][c] in the second iteration of the outer loop since it goes out of bounds. The outer loop should not be present and the variable r should simply be 0. Therefore, consider revising it like so:

for (c = 0; c < 3; c++)
    if (checkLine(bd[0][c], bd[1][c], bd[2][c])) {
        return bd[0][c]; 
    }

By resolving this issue, you can proceed with rectifying any similar errors in other parts of your function.

To assist further, I've provided a spoiler:

for (r = 0; r < 3; r++)
     if (checkLine(bd[r][0], bd[r][1], bd[r][2])) {
       return bd[r][0];
     }

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

After pressing the ASP.NET button, the JavaScript function is called followed by the C# function being executed

There is an issue that I'm facing: I have developed an ASP.NET page which includes an Update panel with an ASP.NET control. I have a JavaScript function for validation. When the button is clicked, I want to use onclientclick to trigger the JavaScrip ...

Steps to resolve the issue: The 'jsx' functionality is not activated at the moment

I recently started working with ReactJS and I came across a similar error message in this post: Syntax Error: Support for the experimental syntax 'jsx' isn't currently enabled. Despite reading it, I am still unable to solve my issue. When I ...

What are some alternative methods for achieving a live re-render without relying on state variables?

Take a look at this array of objects: const tasksList = [ { text: "Complete this section", deadline: new Date("05/01/2022"), status: "complete", // ToDo: Incorporate priority fields }, { ...

What is the reasoning behind having the argument of the main character **argv represented as an array of Strings in the

When looking at a main function in C, it's common to come across code like this: int main(int argc, char **argv){} This raises some questions for me. It appears that char **argv is treated as an array of strings since I can access argv[0] to retriev ...

Unexpected token < error encountered during parsing in jQuery Ajax long polling append

How can I create a real-time ticker similar to Facebook using Jquery Ajax long poll and PHP? I encountered an error in my script that displays "error parsererror (SyntaxError: Unexpected token <)". What could be causing this error in my code? Here is ...

Show information in a React Native element | Firebase

Just starting out with react native and struggling to display data in a component? You're not alone! I'm having trouble too and would love some guidance on how to destructure the data for display. Any tips? import React,{useState,useEffect} from ...

Which is the quicker option: ternaries or if statements?

Given the scenario where I have two options with functions of identical types: (Entry->d_type == DT_DIR ? rmdirr : remove)(CurrentEntryPath); Alternatively, if (Entry->d_type == DT_DIR) { rmdirr(CurrentEntryPath); } else { remove(CurrentE ...

Discover the frequency of dynamically generated data stored in the Mongo Collection

When users add links to the Mongo Collection, I aim to retrieve the most popular ones based on the frequency of a particular link in the collection. For predefined data like the number of links from YouTube, you can use the following: Meteor.users.find({ ...

Displaying PHP output within a JavaScript expression

Let's dive into a scenario involving a basic HTML document and some JavaScript that's loaded within it: <!-- doc.html --> <!doctype html> <html lang="en"> <head> <script type="text/javascript" src=" ...

Navigating through the img src using JavaScript

Currently, I am working on a task that involves the following code snippet: <input type="file" id="uploadImage" name="image" /> <input type="submit" id="ImageName" name="submit" value="Submit"> My goal is to have the path of the selected imag ...

Establishing the properties of an object as it is being structured within a nested data format

I am in the process of creating a unique JSON representation, focusing on object composition to directly set key values during composition. However, I've encountered difficulty composing multiple objects in a nested manner. My goal is to find an expr ...

What steps can be taken to resolve the errors in a Redux-React application?

I am encountering errors: https://i.sstatic.net/fM1LU.jpg I have recently begun learning Redux and I need assistance in rectifying my code so that my Redux application can function seamlessly like it does on pure React. In this project, I will only p ...

Issue encountered while utilizing PHP sessions

I'm currently developing a basic login page that utilizes JS, JQuery, and PHP. login.php <!DOCTYPE html> <head> <title>AJAX Login Learning Activity</title> <link rel="stylesheet" type="text/css" href="login.css"> ...

ajax is unable to decode a JSON string from a GET request

Currently, I am leveraging angularjs to retrieve userId, userTitle, and userComment from a form. These values are then sent to a PHP page from the controller for communication with a server. Everything works well when sending integers, but I face an issue ...

What is the method for determining the size of two arrays?

Can someone help me figure out how to determine the sizes of both arrays? I've been struggling with this and haven't had any success so far. { "_id" : ObjectId("5dc36ebac1f4d52582abc3d1"), "array1" : [ { "array2" : [ ...

The AJAX success callback is malfunctioning

Below is the snippet I'm utilizing to interact with my web API controller titled Owner. However, despite everything appearing correct, the success function isn't triggering. Any suggestions on what might be causing this issue? $.ajax({ ...

Using makeStyles() in MUI for conditional rendering

Trying to dynamically change the value of backgroundColor under the property "& + $track" using props.disabled but it seems that MUI does not recognize it. Why could that be? const useStyles = makeStyles((theme) => ({ root: { overflow: "vis ...

Make sure the a-tag is set to be displayed as a block element, but keep

I'm trying to style an anchor tag as a block element for specific design purposes - setting the width, height, and padding. However, I also need this block element to be hidden initially, so I've used CSS to set its display value to none. The is ...

Utilizing Javascript to maintain an ongoing sum within a <span> tag

I'm working on a code snippet to create a running total feature. Essentially, every time a user clicks a button to add the subtotal to the total, I want it to keep accumulating in the running total. Currently, the setup involves a dropdown menu with t ...

The custom hook designed to clear and update time is not functioning as anticipated

After setting the default time using setInterval, it seems to be creating a new instance instead of updating as expected. How can I clear the existing setInterval in the custom hook and set a new value? app.jsx import React from 'react'; import ...