// Cloned by MENGTE ZHU on 5 Dec 2022 from World "Tic-Tac-Toe (clone by Xiaoyu Lyu)" by Xiaoyu Lyu
// Please leave this clone trail here.
// 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);
};