考虑对称性,生成Java中所有可能未完成的井字位置的列表

时间:2016-12-29 16:38:27

标签: java recursion tic-tac-toe

鉴于此

  • 如果可以在Tic-Tac-Toe游戏中发生,则可以使用棋盘
  • 空白板算作有效解决方案
  • 董事会不能完成" (即,任何一方都不能连续三件)
  • 如果两个电路板仅通过反射或旋转而不同,则它们被计为相同的位置

存在多少这样的职位,如何获得这些职位的清单。我试过这个:

import java.util.ArrayList;
import java.util.Arrays;

public class Second {
static ArrayList<int[]> arr = new ArrayList<int[]>();
static int[] board = new int[9];

public static void main(String[] args) {
    for(int i = 0; i < 19683; ++i){
        int c = i;
        for (int j = 0; j < 9; ++j){
            board[j] = c%3;
            c /= 3;
        }  

        //Check for Xs and Os
        int diff = 0;
        for(int x : board){
            if(x==1){
                diff++;
            }else if(x==2){
                diff--;
            }
        }
        if(diff==0 || diff==1){
            add(board);
        }
    }   
    System.out.println(arr.size());
}

public static void add(int[] board){
    //If the board is won by either side
    if(isCompleted(board)){return;}

    //Get all possible arrangements
    int[] board1 = {board[6],board[7],board[8],   board[3],board[4],board[5],   board[0],board[1],board[2]};
    int[] board2 = {board[2],board[1],board[0],   board[5],board[4],board[3],   board[8],board[7],board[6]};
    int[] board3 = {board[8],board[5],board[2],   board[7],board[4],board[1],   board[6],board[3],board[0]};
    int[] board4 = {board[0],board[3],board[6],   board[1],board[4],board[7],   board[2],board[5],board[8]};
    int[] board5 = {board[2],board[5],board[8],   board[1],board[4],board[7],   board[0],board[3],board[6]};
    int[] board6 = {board[8],board[7],board[6],   board[5],board[4],board[3],   board[2],board[1],board[0]};
    int[] board7 = {board[6],board[3],board[0],   board[7],board[4],board[1],   board[8],board[5],board[2]};

    int[][] boards = {board1, board2, board3, board4, board5, board6, board7};

    //Find the smallest of the 8 possible arrangements
    int[] smallestBoard = board;
    for(int k=0; k<7; k++){
        if(isGreater(boards[k], smallestBoard)){
            smallestBoard = boards[k];
        }
    }

    for(int[] x : arr){
        if(Arrays.equals(x, smallestBoard)){
            return;
        }
    }
    arr.add(smallestBoard);     
}

public static boolean isCompleted(int[] board){
    int piece = 1;

    if(isAll(piece, new int[]{board[0], board[1], board[2]})){return true;}
    if(isAll(piece, new int[]{board[3], board[4], board[5]})){return true;}
    if(isAll(piece, new int[]{board[6], board[7], board[8]})){return true;}
    if(isAll(piece, new int[]{board[0], board[3], board[6]})){return true;}
    if(isAll(piece, new int[]{board[1], board[4], board[7]})){return true;}
    if(isAll(piece, new int[]{board[2], board[5], board[8]})){return true;}
    if(isAll(piece, new int[]{board[0], board[4], board[8]})){return true;}
    if(isAll(piece, new int[]{board[2], board[4], board[6]})){return true;}

    piece = 2;

    if(isAll(piece, new int[]{board[0], board[1], board[2]})){return true;}
    if(isAll(piece, new int[]{board[3], board[4], board[5]})){return true;}
    if(isAll(piece, new int[]{board[6], board[7], board[8]})){return true;}
    if(isAll(piece, new int[]{board[0], board[3], board[6]})){return true;}
    if(isAll(piece, new int[]{board[1], board[4], board[7]})){return true;}
    if(isAll(piece, new int[]{board[2], board[5], board[8]})){return true;}
    if(isAll(piece, new int[]{board[0], board[4], board[8]})){return true;}
    if(isAll(piece, new int[]{board[2], board[4], board[6]})){return true;}

    return false;
}

public static boolean isGreater(int[] first, int[] second){
    for(int j=0; j<9; j++){
        if(first[j]>second[j]){return true;}
        if(second[j]>first[j]){return false;}
    }
    return true;
}

public static boolean isAll(int value, int[] arr){
    for(int x : arr){
        if(x != value){
            return false;
        }
    }
    return true;
}

}

这给出了628个可能位置的结果。但是,Michal Forišek's answer to a Quora question给出了630个职位的答案,其中包括三个我没有的职位。我的程序还输出[2,2,2,2,2,2,2,2]作为有效位置,它不可能。

1 个答案:

答案 0 :(得分:0)

基本问题是你永远不会回溯。你从一个空板开始,制作一个包含九个动作的线性脚本集,填充板。没有更多可能的移动,所以算法终止,让 arr 只保留那九个位置,正方形按顺序占用。

要获得适当的覆盖率,请将 board 设为动态变量,而不是类的静态属性。将其作为参数传递给 playThrough ,以便每个实例都有自己的副本。这不是空间问题:您的调用堆栈的最大深度为10。

动态处理棋盘会让运行时堆栈管理你的回溯(因为每个实例都维持自己的部分游戏状态)。

我希望你能够为大量的解决方案做好准备; 9!某些标准并不大,但你的数组是9!需要考虑大小为9的整数数组。