DEV Community

Cover image for Check for a Tic Tac Toe winner with Regular Expressions
Tom
Tom

Posted on

Check for a Tic Tac Toe winner with Regular Expressions

Regular Expressions are complicated. The syntax can be very messy and it's all too easy to make mistakes. I am fairly inexperienced with them and so I decided to get some practice during one of my projects. I built a Tic Tac Toe game that uses a Regular Expression to identify the winner. Here I will discuss how I achieved this and if someone has a cleaner solution (as I'm sure there are many!) please comment below.

The problem

Imagine the following setup. We have built a 3x3 grid as a table in HTML. The grid squares have id's numbered as such:

|1|2|3|
|4|5|6|
|7|8|9|
Enter fullscreen mode Exit fullscreen mode

Clicking on a square fills it with an X or O depending on who's turn it is. We need a way of determining if the play that has just been made, won that player the game.

For the sake of this discussion the game is being played by 2 people, each clicking on squares in turn.

The solution

Before the game starts we define two empty strings to track each player's moves and an array of the free grid squares.

let xLocations = '';
let oLocations = '';
let empty = ['1', '2', '3', '4', '5', '6', '7', '8', '9'];
Enter fullscreen mode Exit fullscreen mode

When a player clicks on a square we add that square's id to the relevant string. For example, if the first move of the game is X clicking the center square, then xLocations becomes equal to the string '5'. We also remove that id from the empty array.

Next we define every winning combination in Tic Tac Toe.

const winners = ['123', '456', '789', '147',
 '258', '369', '159', '357'];
Enter fullscreen mode Exit fullscreen mode

After each play, we need to check if the locations string matches any of these winning combinations. However there are several complicating factors:

  • The play '321' is technically the same as '123' as the order played is irrelevant.
  • The length of the location string will not be constant, eg '17382' is a valid winner as it contains '123'.

Therefore we need to test if a given location string contains any of the winning combinations. My solution is as follows. Every time a square is clicked we run the following function and pass in either xLocations or oLocations depending on whether X or O just played.

const checkWinner = (locations) => {
  if (locations.length < 3) return;

  for (let i = 0; i < winners.length; i++) {
    let regexStr = winners[i].split('').join('|');
    let regex = new RegExp(regexStr, 'g');
    if (regex.test(locations)) {
      if (locations.match(regex).length === 3) return 'win';
    }
  }
  if (empty.length === 0) return 'draw';
};
Enter fullscreen mode Exit fullscreen mode

Let's break this down.

Firstly, as a minimum of 3 plays is required to win, we can discard any locations strings shorter than 3. We then loop over the winners array and create a Regular Expression for each value in turn. For the first value this would look like the following:

// winners[0] = '123'
let regexStr = winners[0].split('').join('|');
// regexStr = '1|2|3|'
let regex = new RegExp(regexStr, 'g');
// regex = /1|2|3/g
Enter fullscreen mode Exit fullscreen mode

This can be used to test if locations contains any of those three numbers. Therefore all we need to do is test for strings that match it exactly 3 times.

if (regex.test(locations)) {
  if (locations.match(regex).length === 3) return 'win';
}
Enter fullscreen mode Exit fullscreen mode

Finally if the line if (empty.length === 0) return 'draw'; runs true it means that the grid is full and there is no winner.

And that's it! If you have any questions or improvements feel free to comment them below.

Oldest comments (1)

Collapse
 
cliftononeal profile image
CliftonOneal

I'm working on a tictactoe game. I want to use RegEx to check if someone is winning. make him want you spell