Search code examples
javaregextic-tac-toe

TicTacToe using regex in java


using regex to do create a tictactoe function which receives a string of nine "X", "O", and/or "-" characters representing the state of a tic tac toe board, for example the string:"X-OXXXO-O" this represents:

X-O
XXX
O-O

some more examples:


"XOOOXXXXO" - False - no one got three in a row here.

"OXO-XOX-O" - True - player O won by getting three in a row vertically in the third column.

here is my attempt at writing the code:

public static boolean regexTicTacToeWinChecker(String b) {
        return b.matches("(((^(...)*000(...)*$)|(.*0..0..0.*)|(0(...0{2}))|(.(.0){3}..))) | (((^(...)*XXX(...)*$)|(.*X..X..X.*)|(X(...X){2})|(.(.X){3}..)))");
    }

using regex is much more useful then writing a lot of if's which cover all the cases. so answers with rejex please, help would be appreciated. thanks here are some tests that you can use to check:

import org.junit.Test;
import static org.junit.Assert.assertEquals;
import org.junit.runners.JUnit4;

public class ExampleTestCases {
    @Test
    public void SomeBoardsWithWinnersTests () {
      String[] winners = new String[]{"XXX-O-O-O", "X--OOOX-X", "O--OO-XXX", "O-XOX-O-X", "OXOOXOXX-", "X-O-OOXXO", "XO--X-OOX", "X-OXOOOXX"};
      for (String winner : winners) {
            System.out.println("Testing with board " + winner);
            assertEquals(true, RegexTicTacToeWinChecker.regexTicTacToeWinChecker(winner));
      }
    }

    @Test
    public void SomeBoardsWithoutWinnersTests () {
      String[] notWinners = new String[]{"XO-------", "XX-XOO---", "-XX-OO-O-", "OXO--XXO-", "OOXXXO---", "OXXX-XOO-", "OOXXX----", "XXOOXXOO-", "OXOXOX---"};
      for (String notWinner : notWinners) {
            System.out.println("Testing with board " + notWinner);
            assertEquals(false, RegexTicTacToeWinChecker.regexTicTacToeWinChecker(notWinner));
      }
    }
}


Solution

  • You can break it down into the individual cases:

    Horizontal match:

    (?:...){0,2}([OX])\1\1
    

    Vertical match:

    .{0,2}([OX])..\2..\2
    

    Diagonal match (two directions):

     ([OX])...\3...\3
     ..([OX]).\4.\4
    

    Now, you just have to or them all together and make sure that the regex matches at the beginning of the board string:

    ^(?:(?:...){0,2}([OX])\1\1|.{0,2}([OX])..\2..\2|([OX])...\3...\3|..([OX]).\4.\4)
    

    Edit: Here's a small Java program to test the regex:

    import java.util.regex.*;
    
    public class TicTacToe {
        public static void main(String[] args) {
        Pattern r = Pattern.compile("^(?:(?:...){0,2}([OX])\\1\\1|.{0,2}([OX])..\\2..\\2|([OX])...\\3...\\3|..([OX]).\\4.\\4)");
    
        String board = "XXX-O-O-O";
     
        Matcher m = r.matcher(board);
        System.out.println(m.lookingAt() ? "match" : "no match");
        }
    }