Generate a list of all unique Tic Tac Toe boards

前端 未结 7 2036

I would like to generate a text file containing all 19,683 Tic-Tac-Toe board layouts in the structure of 0 = Blank, 1 = X, and 2 = O. Unfortunately math is not my strong su

相关标签:
7条回答
  • 2020-12-30 09:29

    Generating all possible game boards (depth first search works best) and excluding duplicates under rotation and mirroring results in 765 boards. 626 are mid game, 91 games X has won, 44 games O has won and 3 games are a draw.

    If you are only intresetd in the optimal moves you can simply use https://xkcd.com/832/ as reference. Makes a nice poster.

    But all the fun in tic-tac-toe is in implementing it. So I leaves that to the reader. Just a few tips:

    1. Every tile on the board has 3 states so you can encode the board as number in base 3. For simpler math I use base 4 (2 bit per tile so I only need to shift). I then have a hash function that generates that number for a board under all possible rotations and mirroring (8 cases) and returns the minimum value. By that I can lookup if I played that board already.

    2. Starting with an empty board place a mark on the board in every possible position, check if the board was already played, mark it played, check if the game is over and count the board, otherwise recurse alternating players.

    3. The first X can only be set in 3 places (considering rotation and mirroring) and all later moves have at most 8 choices. Instead of encoding the absolute tile to be played you can only count empty tiles and encode that in 3 bit.

    4. Using the above hash function gives us 626 boards where we have to make a move (you just have to reverse the rotation/mirroring to get the real move out of the data). There is probably a not much larger relative prime number so that each board fits in a hash table without collisions. Lets say that number is 696 (I know, not relative prime). At 3 bits per board that would only need 261 byte of data to store the best move for every possible game.

    5. Since you are playing perfect the number of reachable boards goes way down again. Build a data set for playing X and one for playing O and you can cut that way down again.

    6. Want to make it even smaller? Just program in a few basic rules like: The first O should be in the middle if free. With 2 "my color" in a row complete the row. With 2 "other color" in a row block the row and so on. Wikipedia has a list of 8 rules but I think I had less when I did it that way.

    7. A perfect tic-tac-toe opponent is boring. You can never win. Why not make the game learn from failure? Keep track of all 626 boards and their possible moves. When a move results in a loss remove that move from the board. If the board has no more moves left remove from all boards leading to this one the move that causes it (recursively if that removes the last move there). Your game will never loose the same way twice. Similary for moves resulting in a win you remove the opponents move from the list of possible ones and if there are none left you mark the previous move as a sure win. That way if you can force a win you will always force it from now on. Playing X can you get it to loose 91 ways? Playing O can you get it to loose all 44 ways?

    0 讨论(0)
  • 2020-12-30 09:35

    Like an earlier solution, but easier to read and in Python.

    for i in range(3**9):
         c = i
         for j in range(9):
             if j % 3 == 0:
                 print("")
             print(str(c % 3) + " ", end='')
             c //= 3
         print("")
    
    0 讨论(0)
  • 2020-12-30 09:38

    There are 9 positions and an alphabet with 3 letters (X, O, empty). Total number of possible combinations is 3^9 = 19683.

    for(int i = 0; i < 19683; ++i)
    {
        int c = i;
        for (int j = 0; j < 9; ++j)
        {
            cout << (c % 3) << " ";
            c /= 3;
        }
    
        cout << endl;
    }
    
    0 讨论(0)
  • 2020-12-30 09:39

    Since you want board layouts, there's only a small number of them (19683).

    You can just brute-force generate all of these. Each box only has 3 possibilities. And there are 9 boxes, just run through all of them.

    EDIT:

    int c = 0;
    while (c < 262144){
        bool valid = (c & 3) < 3;
        valid &= ((c >>  2) & 3) < 3;
        valid &= ((c >>  4) & 3) < 3;
        valid &= ((c >>  6) & 3) < 3;
        valid &= ((c >>  8) & 3) < 3;
        valid &= ((c >> 10) & 3) < 3;
        valid &= ((c >> 12) & 3) < 3;
        valid &= ((c >> 14) & 3) < 3;
        valid &= ((c >> 16) & 3) < 3;
    
        if (valid){
            int i = c;
            int j = 0;
            while (j < 9){
                cout << (i & 3) << " ";
                i >>= 2;
                j++;
            }
            cout << endl;
        }
    
        c++;
    }
    

    This will print out all 19,683 board layouts. I'm not sure what format you want, but it should be fairly easy to extract that from the output.

    0 讨论(0)
  • 2020-12-30 09:42

    You can simply brute force your way through. Each of the squares is 0, 1 or 2 so...:

    for (int i1 = 0; i1 <= 2; i++) {
        for (int i2 = 0; i2 <= 2; i++) {
            // ...
            // lot's of nested for loops
            // ...
        }
    }
    

    Or, if you can't be bothered with that ;) then you can write a recursive function for it:

    int square[9];
    void place(int square_num) {
        if (square_num == 9) {
            output the current configuration
        }
    
        for (int i = 0; i <= 2; i++) {
            square[square_num] = i;
            place(square_num+1);
        }
    }
    

    Then just do:

    place(0);
    

    and magic will occur.

    This is in c++ by the way.

    0 讨论(0)
  • 2020-12-30 09:48

    My Minimax for Tic Tac Toe implementation generates a tree of 5477 nodes. Each node contains a Tic Tac Toe board state and satisfies the following conditions:

    • the board state is valid as per Tic Tac Toe rule that players must take turns in placing Xs and Os. i.e. there's no board positions like:

      XXX
      XXX
      XXO

    • all leafs of the tree contain board states that are consider end-game states as per Tic Tac Toe rules (player 1 wins, player 2 wins or draw). i.e. there's no branch of the tree like:

      XOX
      OXO
      X
      |
      |
      XOX
      OXO <-- no point in having this node, since its parent has an end-game position (X won)
      XO

    • A given tree node may have multiple parents (multiple tree nodes may have the same child).

      i.e. since a given board state can be obtained through multiple different move sequences, when the tree nodes are being created, if there's already a node containing the board state that I'm about to (re)generate, I reuse (reattach) that existing node. This way, when I score the tree nodes bottom-to-top (as per Minimax theory), I don't have to calculate the same score multiple times for some subset of tree branches (which would be identical if I didn't reuse existing nodes).

    I've also found a book which mentions the 5477 unique, distinct, valid Tic Tac Toe board states. :

    Tic-Tac-Toe is has 5477 valid states excluding the empty position

    0 讨论(0)
提交回复
热议问题