在 java 中使用正则表达式的井字棋

TicTacToe using regex in java

使用正则表达式创建一个井字 该函数接收表示井字棋盘状态的九个“X”、“O”、and/or“-”字符的字符串,例如字符串:"X-OXXXO-O" 这代表:

X-O
XXX
O-O

更多示例:


"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.

这是我编写代码的尝试:

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}..)))");
    }

使用正则表达式比编写大量涵盖所有情况的 if 更有用。所以请用 rejex 回答,我们将不胜感激。谢谢 这里有一些您可以用来检查的测试:

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));
      }
    }
}

您可以将其分解为个别情况:

水平匹配:

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

垂直匹配:

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

对角匹配(两个方向):

 ([OX])......
 ..([OX])..

现在,您只需 or 将它们放在一起,并确保正则表达式匹配板字符串的开头:

^(?:(?:...){0,2}([OX])|.{0,2}([OX])....|([OX])......|..([OX])..)

编辑:这是一个 Java 小程序来测试正则表达式:

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");
    }
}

如果您希望能够在几个月后维护您的正则表达式,老实说,我宁愿选择更具可读性的东西,而不是过于聪明,例如;

Vertical match:   X..X..X..|.X..X..X.|..X..X..X
Horizontal match: XXX......|...XXX...|......XXX
Diagonal match:   X...X...X|..X.X.X..

在一起:

^(?:X..X..X..|.X..X..X.|..X..X..X|XXX......|...XXX...|......XXX|X...X...X|..X.X.X..)$

这使得仅通过查看正则表达式就几乎可以看到获胜模式。

O 做同样的事情,你应该可以开始了:)

我希望您的正则表达式尽可能简单!这意味着您需要停止将所有内容压缩到一个字符串中。

想象一下:

XOX
OOX
XXO

为什么不创建多个字符串,例如:

  1. 水平线:XOX
  2. 水平线:OOX
  3. 水平线:XXO

  1. 竖线:XOX
  2. 竖线:OOX
  3. 竖线:XXO

  1. 左上对角线:XOO
  2. 左下对角线:XOX

和 运行 这些值中的每一个都反对:

"^X{3}$" = player 1 won
"^O{3}$" = player 2 won

在代码中:

Pattern player1Pattern = Pattern.compile("^X{3}$");
Pattern player2Pattern = Pattern.compile("^O{3}$");
for(String s: tictactoe) {
    if(player1Pattern.matcher(s).matches()){
         //Player 1 wins
    }else if(player2Pattern.matcher(s).matches()){
         //Player 2 wins
    }else{
         //nobody wins
    }
}

你可以试试这个:

regex-demo

我只是将输入作为模式输入:

X-O
XXX
O-O
Pattern pattern = Pattern.compile("([XO])(?:(?:\1\1)|(?:(?:[\sXO-]{2}\1){2})|(?:[\sXO-]{3}\1){2}|(?:[\sXO-]{4}\1){2})", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher("X-O\n" +
                "XXX\n" +
                "O-O");
        boolean matchFound = matcher.find();
        if(matchFound) {
            System.out.println("Match found and "+ matcher.group(1) + " win!");
        } else {
            System.out.println("Match not found!");
        }

输出:

Match found and X win!