Tic tac toe how to prevent placing a mark on not vacant cell

Hey guys,
I am a beginner and i’m making a tic tac toe game in pure js. My problem is i’m trying to figure out how to block a cell from being marked again with either X or O.
So far i tried turning my board in to an array with “available” variable and splicing it after a click but i don’t think that’s gonna work…

any advice or hints would be great, thanks :slight_smile:

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

//Variables
let row = 3;
let col = 3;
const vacant = "white";
let sq = 100;
let w = canvas.clientWidth/3;
let h = canvas.clientHeight/3;
let currentPlayer = "";
//players
const players = ['X', 'O']
const player1 = players[0];
const player2 = players[1];


//draw a square
function drawSquare(x, y, color) {
	ctx.fillStyle = color;
	ctx.fillRect(x*sq, y*sq, sq, sq);
	ctx.strokeStyle = 'black';
	ctx.strokeRect(x*sq, y*sq, sq, sq);
}

//Create board
	let board = [ ];
		for(let r = 0; r < row; r++){
			board[r] = [ ];
				for(let c = 0; c < col; c++) {
					board[r][c] = vacant;
				}
		}

//Draw Board
function drawBoard() {
	for(r = 0; r < row; r++) {
		for(c = 0; c < col; c++){
			drawSquare(c, r, board[r][c]);
		}
	}
}
drawBoard();

// sets up the game
function setup() {
	
	//let the starting player be selected at random
	let randomPlayer = Math.floor(Math.random() *2 );
	currentPlayer = player1;
	if (randomPlayer == !0){
		currentPlayer = player2;
		alert('Player 2 starts the game !')
	}else {
		alert('Player 1 starts the game !')
	};
}
setup();
document.getElementById("currentPlayerH2").innerHTML = currentPlayer + "'s turn";

// listens for clicks on the canvas to draw the symbol
function drawSymbol () {
		canvas.addEventListener('click', () => {
			// get the position of the board relative to the page
			let {left, top} = canvas.getBoundingClientRect();

			// get the position of the click relative to the page
			let mouseX = event.clientX - left;
			let mouseY = event.clientY - top;
			
			// calculate which square is being clicked 
			let newRow = Math.floor(mouseY / sq);
			let newCol = Math.floor(mouseX / sq);
			
			// Calculate middle of a square
			let x = w * newCol + w/2;
			let y = h * newRow + h/2;
			let xr = w/4;

			let notVacant = (newCol, newRow);


			board[r][c] = notVacant;
			// Draw an X or O depending on the player's turn
			if(board[r][c] == vacant){
				console.log(newRow, newCol);
				
				if(currentPlayer == players[0]) {  //
					ctx.lineWidth = 5;
					ctx.strokeStyle = 'black';	
					ctx.beginPath();
					ctx.moveTo(x-xr, y-xr);
					ctx.lineTo(x+xr, y+xr);
					ctx.moveTo(x+xr, y-xr);
					ctx.lineTo(x-xr, y+xr);
					ctx.stroke();
					currentPlayer = player2;
				} else { 
					ctx.lineWidth = 5;
					ctx.strokeStyle = 'black';
					ctx.beginPath();
					ctx.arc(x , y, 40, 0, 2 * Math.PI);
					ctx.stroke();
					currentPlayer = player1;
				}
			} else {
				return;
			}
			
		}
		)
}
drawSymbol();


Splicing sounds slightly complicated for the task. You have 3x3 board initialized with all fields vacant, so all that is needed is keeping track of and checking which fields are vacant and which were changed to something like not vacant.

hmm so something like adding board[r][c] = !vacant after click event ?

Maybe not literally !vacant, but yes, change the relevant board[r][c] value to something that would mark it as not available anymore, when the field is marked with symbol. And checking whether picked field is vacant, when field is clicked, would stop drawing on the same field twice or more.

Right, i don’t think i can do it without another hint :confused: what i tried to do is this:
In drawSymbol function i have added variable notVacant and i assigned newRow and newCol to it(so basically position of the click) then i changed board[r][c] = notVacant. After that i wrapped the if statement in the drawSymbol with another if statement that is checking if(board[r][c] == vacant) and if its not } else { return; . When i click on any cell it does not draw anything and just shows me this error in console :
tictactoe.js:83 Uncaught TypeError: Cannot set property '3' of undefined
at HTMLCanvasElement.<anonymous> (tictactoe.js:83)
Like i said earlier i am a beginner and i’m probably doing some stupid mistake somewhere but i really need to start seeing it :stuck_out_tongue:

Can you show the changed code?

Sure, just edited the code in the first post

Notice that r and c variables are not set in that function. Instead you have newRow and newCol which corresponds the clicked square and they should be used in the board checking and potential setting field as not vacant. Consider too whether your order in which you set square as notVacant and check whether it is vacant is correct.

Thank you very much, good sir ! Seems to be working no problems now ! :slight_smile:

1 Like