Code viewer for World: Tic-Tac-Toe (clone by Xiao...

// Cloned by Xiaoyu Lyu on 28 Nov 2022 from World "Tic-Tac-Toe" by Scott Brady 
// Please leave this clone trail here.
 
// Adapted from https://editor.p5js.org/cs4all/sketches/Bk3TOJzlE
// positioning information from https://github.com/processing/p5.js/wiki/Positioning-your-canvas

//---- normal P5 code -------------------------------------------------------

AB.world.newRun = function() {
    AB.socketStart();
    AB.runReady = false;
};

function splashScreen() {
    let text = "Welcome to Tic Tac Toe. The aim of the game is to fill a row, diagonal or column with your symbol, X or O. First to do so is the winner.";        
    return (text);
}
AB.newSplash( splashScreen() );

$("#splashbutton").click (function () {
   AB.removeSplash();
   AB.runReady = true;
  if (AB.socket) {
    if (AB.socket.connected) {
        console.log("SOCKET CONNECTED");
        // AB.socketOut("TESTING SOCKETS!!!");
        }
    }
});


AB.world.nextStep = function() {
}

let board;
let p1;
let p2;
let turn;
let scoreDiv;
let turnText = "";

var data = {
    totalOnes: 0,
    totalMinusOnes: 0,
};

const POP_SOUND = '/uploads/mrprice/mixkit-game-ball-tap-2073.wav'

var cnv;

let height;

function setup() {
    height = windowHeight - 300
    p1 = new Player("X")
    p2 = new Player("O")
    var cnv = createCanvas(height, height);
    var x = (windowWidth - width) / 2;
    var y = (windowHeight - height) / 2;
    cnv.position(x, y);
    // background(255, 255, 200);
    scoreDiv = createDiv('').size(180, 100);
    board = new Board(p1, p2)
}



// function centerCanvas() {
//     var x = (windowWidth - width) / 2;
//     var y = (windowHeight - height) / 2;
//     cnv.position(x, y);
// }

// function windowResized() {
//     height = windowHeight - 300
//     resizeCanvas(height, height)
// }

function draw() {
    background(0, 128, 128)
    AB.hideRunHeader();
    board.display();
    scoreDiv.style('font-size', '50px');
    scoreDiv.style('font-family', 'sans-serif');
    scoreDiv.style('padding-top', '25px');
    scoreDiv.style('margin', 'auto');
    scoreDiv.style('width', '100%');
    scoreDiv.style('height', '100%');
    scoreDiv.style('color', 'white');
    scoreDiv.style('text-align', 'center');
    // set the scoreDiv background image
    scoreDiv.style('background-image', 'url(/uploads/mrprice/bg.jpg)');
    scoreDiv.style('background-size', 'cover');
    scoreDiv.style('background-position', 'center');
    scoreDiv.style('background-repeat', 'no-repeat');
    scoreDiv.style('background-attachment', 'fixed');
    




}

function playSound(instance) {
    if (instance == "pop") {
        var sound = new Audio(POP_SOUND);
        sound.play();
    }
}

function mousePressed() {

    // check if mouse is in the board
    if (mouseX > 0 && mouseX < 800 && mouseY > 0 && mouseY < 800 && AB.runReady === true) {
        if (!board.winState) {
            // nobody has won yet
            if (board.turn === "X") {
                playSound("pop");
                p1.select(board);
            } else {
                playSound("pop");
                // AB.socketOut(p2.select(board));
                p2.select(board);
            }
            board.toggleTurn();
        } else {
            // someone has one, toggle a new game
            board.newGame();
        }
    }
}



// board attributes & methods
class Board {
    constructor(p1, p2) {
        this.cells = [];
        this.cellSize = (width - 1) / 3;

        this.p1 = p1;
        this.p2 = p2;
        this.turn = this.p1.symbol;

        this.winState = false;
        this.resultText = "";
        this.newGame();
    }

    display() {
        let cellSize = this.cellSize;

        if (this.winState) {
            // someone has won, display the result
            var hv = (height / 2) - 400
            textSize(40);
            textAlign(CENTER);
            text(this.resultText, width / 2, height / 2);
            text("Click anywhere for a new game", width / 2, height - 200)
            var bc = color("yellow");
            fill(bc);
        } else {
            // nobody has won yet, display the board
            this.cells.forEach(function (element) {
                // draw the cell
                strokeWeight(25);
                stroke('rgba(0, 80, 80, 0.8)');
                var c = color('teal');
                fill(c);
                rect(element.row * cellSize, element.col * cellSize, cellSize, cellSize);
                
                // strokeWeight(0)
                c = color('yellow');
                fill(c);
                strokeWeight(10)
                stroke('rgba(173, 167, 0, 0.8)');
                textSize(168);
                textAlign(CENTER);
                // draw the X or O
                // centre the text in the cell
                text(element.symbol, element.row * cellSize + cellSize / 2, element.col * cellSize + cellSize / 2 + 60);
                // text(element.symbol, element.row*cellSize + cellSize/2, element.col*cellSize + cellSize/2 + 20);
                // text(element.symbol, element.row*cellSize + cellSize/2, element.col*cellSize+cellSize/1.5)
                strokeWeight(0)
            });
        }

    }


    update(row, col, symbol) {
        // update the board with the new move
        let turn = this.turn;

        this.cells.forEach(function (element) {
            // element.col is the column and element.row is the row
            // element.symbol is the X or O and element.val is the value
            // element is the cell object
            // if the cell's row and column match the row and column of the move
            if (element.row === row && element.col === col && element.val === 0) {
                // update the cell's text and value
                element.symbol = symbol;
                if (turn === "X") {
                    // if it's X's turn, the value is 1
                    element.val = 1;
                    data.totalOnes++;
                    data["element"] = element;
                } else {
                    // if it's O's turn, the value is -1
                    element.val = -1;
                    data.totalMinusOnes++;
                    data["element"] = element;
                }
            }
        });
        let result = this.checkResult();
        if (result === "X") {
            this.winState = true;
            this.resultText = "X wins!";
        } else if (result === "O") {
            this.winState = true;
            this.resultText = "O wins!";
        } else if (result === "tie") {
            this.winState = true;
            this.resultText = "It's a tie!";
        }
    }



    toggleTurn() {
        // if it's X's turn, make it O's turn
        if (this.turn == p1.symbol) {
            data["currentTurn"] = p2.symbol;
            this.turn = p2.symbol;
            turnText = "Turn: " + p2.symbol;
            // AB.socketOut(turnText);
        } else {
            // if it's O's turn, make it X's turn
            data["currentTurn"] = p1.symbol;
            this.turn = p1.symbol;
            turnText = "Turn: " + p1.symbol;
            // AB.socketOut(turnText);

        }
        // console.log(turnText);
        scoreDiv.html(turnText);
        data["turnText"] = turnText;
        AB.socketOut(data);
    }


    // check if someone has won
    checkResult() {
        let winner;
        let p1 = this.p1;
        let p2 = this.p2;
        // this.s is the size of the board
        let rowSums = new Array(3);
        let colSums = new Array(3);
        let diagSums = new Array(3);
        // numOpen is the number of open cells
        let numOpen = 9;


        let s = 3

        // initialize the rowSums, colSums, and diagSums arrays
        for (let i = 0; i < 3; i++) {
            rowSums[i] = 0
            colSums[i] = 0
            diagSums[i] = 0
        }

        // loop through the cells
        this.cells.forEach(function (element) {
            // if the cell is open, decrement numOpen
            rowSums[element.row] += element.val;


            colSums[element.col] += element.val;
            numOpen -= abs(element.val);

            // if the cell is on the main diagonal
            if (abs(element.row - element.col) === 0) {
                // add the cell's value to the main diagonal sum
                diagSums[0] += element.val;
            }
            // if the cell is on the secondary diagonal
            if (abs(element.row - element.col) === 2 || (element.row == 1 && element.col == 1)) {
                // add the cell's value to the secondary diagonal sum
                diagSums[1] += element.val;
            }
        });
        // check if any of the sums are 3 or -3
        rowSums.forEach(function (element) {
            if (element === s) {
                winner = p1.symbol;
                // if the sum is 3, X won
                p1.win();
            }
            if (element === -1 * s) {
                winner = p2.symbol;
                // if the sum is -3, O won
                p2.win();
            }
        });

        colSums.forEach(function (element) {
            if (element === s) {
                winner = p1.symbol;
                p1.win();
            }
            if (element === -1 * s) {
                winner = p2.symbol;
                p2.win();
            }
        });
        diagSums.forEach(function (element) {
            if (element === s) {
                winner = p1.symbol;
                p1.win();
            }
            if (element === -1 * s) {
                winner = p2.symbol;
                p2.win();
            }
        });
        if (numOpen === 0) {
            winner = "tie";
        }
        return winner;
    }

    newGame() {
        this.winState = false;
        this.turn = this.p1.symbol;
        scoreDiv.html("Turn: " + this.p1.symbol);

        // reset the cells
        this.cells = [];

        // create the cells
        for (let i = 0; i < 3; i++) {
            for (let j = 0; j < 3; j++) {
                this.cells.push({
                    // the row
                    "row": i,

                    // the column
                    "col": j,

                    // the text
                    "symbol": "",

                    // the value
                    "val": 0
                });
            }
        }
    }
}

class Player {
    constructor(symbol) {

        this.symbol = symbol;
        this.score = 0;
    }

    select(board) {
        // if it's X's turn, the value is 1
        if (board.turn == this.symbol) {
            // cx and cy are the coordinates of the mouse


            let cx = int(Math.floor(mouseX / board.cellSize));
            let cy = int(Math.floor(mouseY / board.cellSize));
            board.update(cx, cy, this.symbol);
            data["row"] = cx;
            data["col"] = cy;
            data["symbol"] = this.symbol;

        }
    }

    win() {
        this.score++
    }
}




// Sockets
AB.socketIn = function (data) {
    console.log(data.turnText);
    // update the board with the new play
    scoreDiv.html(data.turnText);
    board.update(data.row, data.col, data.symbol);
    console.log(data.currentTurn);
    board.turn = data.currentTurn;
    

};


AB.socketUserlist = function ( array ) {
    console.log(array.length);
};