生成具有对称性的所有可能的Tic Tac Toe板

时间:2016-05-01 21:52:24

标签: java artificial-intelligence

我正在编写一个遗传算法程序,该程序将开发出解决Tic Tac Toe板的最佳解决方案。我已经做了很多研究,并且发现当考虑到电路板的对称性时,有765种可能的电路板组合。我需要编写一个代码来生成每个组合,但我无法弄清楚如何做到这一点。我是编码新手,无法弄清楚如何将对称性融入代码中。

你将如何创建一个能够生成Tic Tac Toe板的所有可能的独特板组合(考虑对称性)的代码?

Here是解释对称性的好文档:

谢谢

3 个答案:

答案 0 :(得分:1)

您可以像在minimax中一样构建游戏树,但不是计算板的值,而是将它们放在首选数据结构中以存储所有765块板。一些示例代码,如果这有帮助:

//Where you'll save the unique boards
HashSet<Board> mySavedBoards = new HashSet<Board>();
mySavedBoards.add(emptyBoard) //add the original empty board

//player = 'X' or 'O'
public static void find_all_boards(Board board, String player) {
    for (Move move : board.get_all_possible_moves()) {
        board = board.applyMove(move, player);
        my_saved_boards.add(board);
        if(!board.isWin()) {
            next_player = (player == 'O') ? 'X' : 'O';
            find_all_boards(board, next_player);
        }
    }
}
  • get_all_possible_moves(board)只返回网格中的空方格列表(允许玩家进入的任何地方)
  • board.applyMove(move)采取行动并返回与玩家一起玩的结果(&#39; X&#39;或&#39; O&#39;)
  • isWin()返回此委员会是否是某些玩家的胜利(即不再继续寻找更多的董事会)

此代码将访问所有可能的tic-tac-toe板,但会有一些重复,因此您必须隐式地管理它(为您的Board类重写equals和hashCode以便为您执行此检查当您将棋盘添加到HashSet时,它不会添加重复项

这很大程度上取决于你对董事会的表述,采取行动以及参与者,但我希望这个一般性的想法有所帮助!

编辑:我现在看到你在询问如何生成对称板 我会在电路板上使用两种方法:flip()rotate()。您可以使用此方法生成板的8种变体,如下面的答案中所示。您可以编写equals方法来检查给定的板是否在另一块板上的变体集中

boolean equals(Board other) {
    //Insert normal checks for object type here
    HashSet<Board> variantsOfOther = other.variants();
    return variantsOfOther.contains(this)
}

答案 1 :(得分:0)

B板有1到8个对称变体,包括它自己。通过以90度增量旋转B可以获得三个。其他可以通过镜像原件然后再旋转三次来找到。 (并非所有旋转/反射都必须是唯一的:中间带有X的板和相同值的所有其他正方形没有其他变体。)

通过将其视为三元数,您还可以轻松地将0 ..(3 ^ 9)-1范围内的值分配给每个电路板。例如。如果你指定0 =空白,1 = O,2 = X并且你有一个董事会

X O _
_ X O
_ _ _

您可以将其解释为210021000(基数3)= 15498(基数为10)。

variants(B)成为接受B板并返回一组最多8个对称变量的函数。让value(B)返回板B的整数值,如上所述。

现在你可以使用一个简单的粗暴算法:

U = {}
for B in the set of 19683 possible boards
  // Set y to the minimum-valued variant of B.
  y = argmin_{ x in variants(B) } . value(x)
  U = U + y // add y to the unique variants.

完成后,U包含独特的电路板

答案 2 :(得分:0)

一点也不麻烦。并且有126种组合,而不是700或数千种。

  1. 生成0到511之间的所有整数,包括
  2. 抓住每个的 2-base表示,即。二进制表示。之前填充零,因此每个二进制表示总是有9个数字,0或1。从你生成的数字6中得到它的二进制表示1,1,0当你填充额外的零时,你有0,0,0,0,0,0,1,1,0。
  3. (你可以在循环中逐一完成所有这些,我只是碰巧使用一种名为Dyalog APL的并行语言,所以我一起展示它们)

    下面。二进制:

    0 0 0 0 0 0 0 0 0 <- this is 0
    0 0 0 0 0 0 0 0 1 <- this is 1
    0 0 0 0 0 0 0 1 0
    0 0 0 0 0 0 0 1 1
    0 0 0 0 0 0 1 0 0
    0 0 0 0 0 0 1 0 1
    0 0 0 0 0 0 1 1 0 <- 6
    0 0 0 0 0 0 1 1 1
    0 0 0 0 0 1 0 0 0
    0 0 0 0 0 1 0 0 1 <- 9
    ...
    0 0 1 0 0 1 1 0 1 <- 77
    ...
    1 1 1 1 1 1 1 1 1 <- 511
    

    你(计算机)是一个,对手是零。

    1. 计算每个中的数量。如果对手开始游戏,只能获得4个的行。如果计算机启动游戏,则仅采用5行的行。在这两种情况下,最终都会有126行。
    2. 以下是15个第一行(126个)保留,当对手开始游戏时(会占用太多空间来写入126行):

      0 0 0 0 0 1 1 1 1
      0 0 0 0 1 0 1 1 1
      0 0 0 0 1 1 0 1 1
      0 0 0 0 1 1 1 0 1
      0 0 0 0 1 1 1 1 0
      0 0 0 1 0 0 1 1 1
      0 0 0 1 0 1 0 1 1
      0 0 0 1 0 1 1 0 1
      0 0 0 1 0 1 1 1 0
      0 0 0 1 1 0 0 1 1
      0 0 0 1 1 0 1 0 1
      0 0 0 1 1 0 1 1 0
      0 0 0 1 1 1 0 0 1
      0 0 0 1 1 1 0 1 0
      0 0 0 1 1 1 1 0 0
      

      这里有所有行保留(对手开始),重新塑造成3个3个表 - 相同数据但略有不同:

      ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
      │0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 1 0│0 1 0│0 1 0│0 1 0│0 1 0│0 1 0│0 1 0│0 1 0│0 1 0│0 1 0│0 1 0│0 1 0│0 1 0│0 1 0│0 1 0│0 1 0│0 1 0│0 1 0│0 1 0│0 1 0│0 1 1│0 1 1│0 1 1│0 1 1│0 1 1│0 1 1│0 1 1│0 1 1│0 1 1│0 1 1│0 1 1│0 1 1│0 1 1│0 1 1│0 1 1│1 0 0│1 0 0│1 0 0│1 0 0│1 0 0│1 0 0│1 0 0│1 0 0│1 0 0│1 0 0│1 0 0│1 0 0│1 0 0│1 0 0│1 0 0│1 0 0│1 0 0│1 0 0│1 0 0│1 0 0│1 0 1│1 0 1│1 0 1│1 0 1│1 0 1│1 0 1│1 0 1│1 0 1│1 0 1│1 0 1│1 0 1│1 0 1│1 0 1│1 0 1│1 0 1│1 1 0│1 1 0│1 1 0│1 1 0│1 1 0│1 1 0│1 1 0│1 1 0│1 1 0│1 1 0│1 1 0│1 1 0│1 1 0│1 1 0│1 1 0│1 1 1│1 1 1│1 1 1│1 1 1│1 1 1│1 1 1│
      │0 0 1│0 1 0│0 1 1│0 1 1│0 1 1│1 0 0│1 0 1│1 0 1│1 0 1│1 1 0│1 1 0│1 1 0│1 1 1│1 1 1│1 1 1│0 0 0│0 0 1│0 0 1│0 0 1│0 1 0│0 1 0│0 1 0│0 1 1│0 1 1│0 1 1│1 0 0│1 0 0│1 0 0│1 0 1│1 0 1│1 0 1│1 1 0│1 1 0│1 1 0│1 1 1│0 0 0│0 0 1│0 0 1│0 0 1│0 1 0│0 1 0│0 1 0│0 1 1│0 1 1│0 1 1│1 0 0│1 0 0│1 0 0│1 0 1│1 0 1│1 0 1│1 1 0│1 1 0│1 1 0│1 1 1│0 0 0│0 0 0│0 0 0│0 0 1│0 0 1│0 0 1│0 1 0│0 1 0│0 1 0│0 1 1│1 0 0│1 0 0│1 0 0│1 0 1│1 1 0│0 0 0│0 0 1│0 0 1│0 0 1│0 1 0│0 1 0│0 1 0│0 1 1│0 1 1│0 1 1│1 0 0│1 0 0│1 0 0│1 0 1│1 0 1│1 0 1│1 1 0│1 1 0│1 1 0│1 1 1│0 0 0│0 0 0│0 0 0│0 0 1│0 0 1│0 0 1│0 1 0│0 1 0│0 1 0│0 1 1│1 0 0│1 0 0│1 0 0│1 0 1│1 1 0│0 0 0│0 0 0│0 0 0│0 0 1│0 0 1│0 0 1│0 1 0│0 1 0│0 1 0│0 1 1│1 0 0│1 0 0│1 0 0│1 0 1│1 1 0│0 0 0│0 0 0│0 0 0│0 0 1│0 1 0│1 0 0│
      │1 1 1│1 1 1│0 1 1│1 0 1│1 1 0│1 1 1│0 1 1│1 0 1│1 1 0│0 1 1│1 0 1│1 1 0│0 0 1│0 1 0│1 0 0│1 1 1│0 1 1│1 0 1│1 1 0│0 1 1│1 0 1│1 1 0│0 0 1│0 1 0│1 0 0│0 1 1│1 0 1│1 1 0│0 0 1│0 1 0│1 0 0│0 0 1│0 1 0│1 0 0│0 0 0│1 1 1│0 1 1│1 0 1│1 1 0│0 1 1│1 0 1│1 1 0│0 0 1│0 1 0│1 0 0│0 1 1│1 0 1│1 1 0│0 0 1│0 1 0│1 0 0│0 0 1│0 1 0│1 0 0│0 0 0│0 1 1│1 0 1│1 1 0│0 0 1│0 1 0│1 0 0│0 0 1│0 1 0│1 0 0│0 0 0│0 0 1│0 1 0│1 0 0│0 0 0│0 0 0│1 1 1│0 1 1│1 0 1│1 1 0│0 1 1│1 0 1│1 1 0│0 0 1│0 1 0│1 0 0│0 1 1│1 0 1│1 1 0│0 0 1│0 1 0│1 0 0│0 0 1│0 1 0│1 0 0│0 0 0│0 1 1│1 0 1│1 1 0│0 0 1│0 1 0│1 0 0│0 0 1│0 1 0│1 0 0│0 0 0│0 0 1│0 1 0│1 0 0│0 0 0│0 0 0│0 1 1│1 0 1│1 1 0│0 0 1│0 1 0│1 0 0│0 0 1│0 1 0│1 0 0│0 0 0│0 0 1│0 1 0│1 0 0│0 0 0│0 0 0│0 0 1│0 1 0│1 0 0│0 0 0│0 0 0│0 0 0│
      └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
      

      看看这是怎么回事? :-)这些是你的“所有组合”。

      1. 在游戏过程中的任何时候,使用当前游戏状态过滤上方的行。示例:对手通过将他的O放在左上角开始,并且计算机通过将其放置在中心来回复,对手通过将他的O放置在上排的中心来回复。
      2. 因此游戏现在看起来像这样:

        ┌─┬─┬─┐
        │0│0│ │
        ├─┼─┼─┤
        │ │1│ │
        ├─┼─┼─┤
        │ │ │ │
        └─┴─┴─┘
        

        或相同,扁平化:

        ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
        │0│0│ │ │1│ │ │ │ │ │
        └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
        

        仅保留与此匹配的行(即,第1列和第2列为0,第5列为1)。现在你只有这些行=这些可能的游戏结果:

        0 0 0 0 1 0 1 1 1
        0 0 0 0 1 1 0 1 1
        0 0 0 0 1 1 1 0 1
        0 0 0 0 1 1 1 1 0
        0 0 0 1 1 0 0 1 1
        0 0 0 1 1 0 1 0 1
        0 0 0 1 1 0 1 1 0
        0 0 0 1 1 1 0 0 1
        0 0 0 1 1 1 0 1 0
        0 0 0 1 1 1 1 0 0
        0 0 1 0 1 0 0 1 1
        0 0 1 0 1 0 1 0 1
        0 0 1 0 1 0 1 1 0
        0 0 1 0 1 1 0 0 1
        0 0 1 0 1 1 0 1 0
        0 0 1 0 1 1 1 0 0
        0 0 1 1 1 0 0 0 1
        0 0 1 1 1 0 0 1 0
        0 0 1 1 1 0 1 0 0
        0 0 1 1 1 1 0 0 0
        
        1. 将每行重新塑造为3乘3.
        2. 同样,更容易看到:

          ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
          │0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│0 0 1│
          │0 1 0│0 1 1│0 1 1│0 1 1│1 1 0│1 1 0│1 1 0│1 1 1│1 1 1│1 1 1│0 1 0│0 1 0│0 1 0│0 1 1│0 1 1│0 1 1│1 1 0│1 1 0│1 1 0│1 1 1│
          │1 1 1│0 1 1│1 0 1│1 1 0│0 1 1│1 0 1│1 1 0│0 0 1│0 1 0│1 0 0│0 1 1│1 0 1│1 1 0│0 0 1│0 1 0│1 0 0│0 0 1│0 1 0│1 0 0│0 0 0│
          └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
          

          这些都是游戏的可能结果,从此阶段开始。显然,你现在要计算每行,每列,对角线和对角线的数量。提取那些连续3个的替代品,然后从中选出一个,放置下一个X.不知道哪个,或者你如何优化 - 我猜你需要做一些mambo jambo :-)。应该很简单。这只是粗略的指导。

          当仔细思考时,你需要保持两个数据集,因为你也想从对手的角度来处理,到阻碍他排在第3位。 IE浏览器。有一个类似的数据集,其中对手是1,你是0,计算行,列,对角线,并且做出反应,如果其中任何一个总和为3 - 那么你必须阻止他!相同的原则,只需管理一个根据需要有所不同。

          (注意:与所有这些并行,你必须跟踪空闲插槽!例如,应该是简单的9长度阵列,其中1表示占用,例如。随着游戏的进展,只需更新它。它的目的是为了)定义计算机可以勾选标记的位置,以及b)验证对手使用空闲位置

          1. 你(计算机)把你的X放在某个地方,对手做出反应,你显然会回到第4步,再次进行过滤(阻止他排成3行+优化你自己的动作)。等