I’m finding it really hard to follow all the logic in your code as it stands!
I’m not sure why it is so slow to allow the final click or why it behaves oddly, but I do notice that you read directly from the DOM a lot, which could be the culprit slowing you down. It might not be that, but it certainly doesn’t help readability in any case.
Take for example your numberOfSquares variable. You get your code to search through all the HTML looking for ‘square’ classed elements. Why don’t you just set the variable
var numberOfSquares = 9?
I know later on you want to access the text from that numberOfSquares behemoth you’ve stored, but there are cleaner ways to do that, too. In that later case, ‘numberOfSquares’ becomes a bad variable name because what it actually represents to you in your use case is an object containing all sorts of data relating to the HTML entities that have ‘square’ classes.
Look at the console.logged object you’re loading into your code:
That’s a lot of cruft considering you just want to see if there’s an X or O in a square.
I think the broader problem is that you are looking at this game as a human with eyeballs and fingers, and you are asking the computer to do the same.
The computer doesn’t actually need to ‘physically observe’ (i.e. search the DOM) for every move you make.
Instead, think about the mental model that might represent this game if there were no squares at all. Ultimately the game can be played with 9 possible moves, which alternate between players until there are no moves left or one of the players has picked a winning combo.
So you might have an store of possible moves, which gets smaller every time a valid move is made, and a store of player moves, which gets bigger. Imagine this like a card game with a pile in the middle and each player holding the cards they pick up…this can be achieved with arrays.
Sure, you need to watch for DOM events so you know which ‘card’ the player wants to pick up, but you shouldn’t need to have the computer keep looking at the page to track what’s going on. It can just look at the arrays (which is much faster, and easier to reason about yourself)
I know that’s not the exact answer you were looking for, but I think in the end you’ll be able to continue adding features and fulfill the remaining user stories more easily. You also suggested you wanted to try to implement a better AI…I haven’t tried that, but using a method that relies on arrays and simple numbers will be easier than your current method as well.