This gist covers how a TicTacToe regular expression I made works. It was made with a Golang flavour of RegEx in mind.
It is used to check if a player won or lost a TicTacToe game, or if it resulted in a draw.
You are expected to know a basic level of RegEx before reading this.
You can find the tests I made for the RegEx here.
When you have finished reading this gist, try making a RegEx to check if there is a win, loss or draw with connect4 - message me with your attempts and I will check them.
I doubt too many people are reading this, but if you find any typos or misinformation, let me know.
^(?:(?:...)*(?:(1)11|(2)22)|.*(?:(?:1..){2}(1)|(?:2..){2}(2))|(?:(?:1...){2}(1)|(?:2...){2}(2))|..(?:(?:1.){2}(1)|(?:2.){2}(2))|[12]*$)
- Why make a RegEx for TicTacToe?
- How does it work?
- Predefined rules
- Wins, losses and draws logic
- Making the RegEx
I just thought it would be funny, and it takes up less room than the massive if statement needed to validate it - although at the risk of readability, so I would not recommend doing this unless you're just bodging code together.
It works with some predefined rules on the input, before being given to the RegEx engine. Once that input is given, we make logical decisions based on some concatenation and made-up rules.
Before the text is given to the RegEx, it has some rules applied to it which is why the RegEx seems a bit vague, or like it would match anything. These rules are:
-
The input will always be 9 digits long because TicTacToe has 9 spots, or boxes.
-
Every
1stands for Player 1's spot. Every2stands for Player 2's spot.0stands for an unused spot. -
For every spot taken by
1,2can take a spot. Because of the turns nature of TicTacToe, for every1, there will be a2, with 1 more or less at times. This means the imposed limit is that the number of1s, is equal to the number of2s, plus or minus 1 or 0. -
The string is from top to bottom, left to right, meaning from the following table, the string would be "ABCDEFGHI" (we are ignoring the prior rules to explain it better).
A B C D E F G H I
There are only 8 ways to win a TicTacToe game, and when one person wins the other loses. When there are no 0s left, the game has resulted in a draw.
In these examples of wins, X accounts for either 1 or 2, but must stay consistent throughout the table (meaning they must stay the same). ? stands for any valid character i.e., 0, 1 and 2.
Under the table is its string equivalent to match against. They are numbered to be referred to later on.
-
X X X ? ? ? ? ? ? XXX??????
-
? ? ? X X X ? ? ? ???XXX???
-
? ? ? ? ? ? X X X ??????XXX
-
X ? ? X ? ? X ? ? X??X??X??
-
? X ? ? X ? ? X ? ?X??X??X?
-
? ? X ? ? X ? ? X ??X??X??X
-
X ? ? ? X ? ? ? X X???X???X
-
? ? X ? X ? X ? ? ??X?X?X??
One thing to keep in mind is that we need to capture either 1 or 2 when there is a match - this is because in the code we need to use this data to give an output of Player X won or the game resulted in a draw.
The total RegEx will have a position asserted at the start of line / string, because it is checked from left to right. I do some odd tricks because of some predefined rules
I will be breaking this up into sections to make it easier to understand - this is where the number in the wins, losses and draws section comes into play.
In the first 3 tables, 1, 2 and 3 we can see a clear pattern as they have 3 random characters, 0, 1 or 2 times, before having three 1 or 2 in a row. We can translate this into the RegEx:
(?:...)*(?:(1)11|(2)22)
In the next 3 tables, 4, 5 and 6, we can see another clear pattern being that each X has exactly 2 random characters between them, with 0, 1 or 2 random characters in front of the them.
.*(?:(?:1..){2}(1)|(?:2..){2}(2))
In the second last table i.e., 7, we can see that each X has 3 random characters between them. In this case, the fact that the entire RegEx is asserted at the start becomes extremely useful.
(?:(?:1...){2}(1)|(?:2...){2}(2))
In the last table i.e., 8, there is another pattern that can be clearly viewed. This is that there are two random characters that it ends and starts in, then 1 character between each X.
..(?:(?:1.){2}(1)|(?:2.){2}(2))
To account for draws, we just check if the entire string did not match any 0 from start to end. We check this at the end so it becomes a case of if there are no wins, check for draws.
[12]*$
This means when joined together, the entire RegEx becomes the following:
^(?:(?:...)*(?:(1)11|(2)22)|.*(?:(?:1..){2}(1)|(?:2..){2}(2))|(?:(?:1...){2}(1)|(?:2...){2}(2))|..(?:(?:1.){2}(1)|(?:2.){2}(2))|[12]*$)
If all capture groups return empty strings yet the RegEx still matches, the TicTacToe game resulted in a draw. If any capture groups return 1 or 2, that player won and the other lost.