2

私はCでソルバーを含む数独ゲームを書いていましたが、Javaで試してみて、人々が少し簡単に使用できるようにしたいと思いました(移植性)。言語間の類似性が非常に高いため、移植はかなり単純になると思いましたが、少し面倒なようです。

私のソルバーは無限に繰り返されますが、これはCでは発生しませんでした。パズルを解くための元のC関数は次のとおりです。

int sudoku_solve(struct sudoku* sudoku)
{
    if(!sudoku) return 0;

    int mask = 0x1ff;
    int best_x = 0, best_y = 0;
    int best_mask = 0x2ff;


    for(int y = 0; y < 9; ++y){
        for(int x = 0; x < 9; ++x){
            if( sudoku->grid[y][x] != 0 ) continue;
            mask = sudoku_get_mask(sudoku, x, y);
            if( mask < best_mask ){
                best_mask = mask;
                best_x = x;
                best_y = y;
            }
        }
    }

    if( best_mask == 0x2ff ) return 1; // this puzzle is already solved!

    if( best_mask == 0x000 ) return 0; // this puzzle can't be solved!

    int start_c = rand() % 9;
    int c = start_c;
    do{
        if( (best_mask & (1<<c)) ){
            sudoku->grid[best_y][best_x] = c+1;
            if( sudoku_solve(sudoku) ) return 1;
        }
        c = (c+1) % 9;
    } while( c != start_c );

    sudoku->grid[best_y][best_x] = 0;


    return 0;
}

これが必ずしも最速または最高のソルバーであるとは限りませんが、機能しました。可能な限り最小の値を持つタイルを見つけるだけで、ランダムな値から開始し、解決可能なパズルが得られるまで(再帰を使用して)すべての可能な値を試します。sudoku_get_maskは、対応する値に最初の9ビットが設定された整数を返します。すでに使用されている値の水平、垂直、およびサブスクエアをチェックし、それらをマスクから削除します。

さて、これがJavaポートです:

public int Solve()
{
    int mask = 0x2FF;
    int bmask = 0x2FF, bx = 0, by = 0;

    for(int y = 0; y < 9; ++y){
        for(int x = 0; x < 9; ++x){
            if( grid[y][x] != 0 ) continue; // ignore spaces with values already set
            mask = GetMask(x, y);
            if( mask < bmask ) // less bits set == less possible choices
            {
                bmask = mask;
                bx = x;
                by = y;
            }
        }
    }

    if( bmask == 0x2FF ) // the puzzle had no good slots, it must be solved
        return 1;

    if( bmask == 0 ) // the puzzle is unsolvable
        return -1;

    int start_c = rand() % 9;
    int c = start_c;
    do{
        if( (bmask & (1<<c)) != 0 ){
            grid[by][bx] = (char) (c+1);
            if( Solve() == 1 ) return 1;
        }
        c = (c+1)%9;
    }while( c != start_c );

    grid[by][bx] = 0; // restore old value

    return 0;
}

それらはほとんど同じなので、Javaポートが無限に繰り返される理由がわかりません。ソルバーは常に1.解決策を見つけるか2.解決策がないことを見つける必要があります。私の論理では、それが無限に繰り返される方法を私は見ることができません。

GetMaskJavaコードは次のとおりです。

protected int GetMask(int x, int y)
{
    int mask = 0x1FF;
    for(int cx = 0; cx < 9; ++cx){
        mask &= (grid[y][cx] == 0 ? mask : ~(1 << (grid[y][cx]-1)));
    }
    for(int cy = 0; cy < 9; ++cy){
        mask &= (grid[cy][x] == 0 ? mask : ~(1 << (grid[cy][x]-1)));
    }
    int idx = squareIndex[y][x];
    int[] pt = null;
    for(int c = 0; c < 9; ++c){
        pt = squarePoint[idx][c];
        mask &= (grid[pt[1]][pt[0]] == 0 ? mask : ~(1 << (grid[pt[1]][pt[0]]-1)));
    }
    return mask;
}

これがsquareIndexとsquarePoint(サブスクエアのルックアップテーブルのみ)です。

static int squareIndex[][] = {
    {0,0,0,1,1,1,2,2,2},
    {0,0,0,1,1,1,2,2,2},
    {0,0,0,1,1,1,2,2,2},
    {3,3,3,4,4,4,5,5,5},
    {3,3,3,4,4,4,5,5,5},
    {3,3,3,4,4,4,5,5,5},
    {6,6,6,7,7,7,8,8,8},
    {6,6,6,7,7,7,8,8,8},
    {6,6,6,7,7,7,8,8,8}
};

static int[] squarePoint[][] = {
    { {0,0}, {1,0}, {2,0}, {0,1}, {1,1}, {2,1}, {0,2}, {1,2}, {2,2} },
    { {3,0}, {4,0}, {5,0}, {3,1}, {4,1}, {5,1}, {3,2}, {4,2}, {5,2} },
    { {6,0}, {7,0}, {8,0}, {6,1}, {7,1}, {8,1}, {6,2}, {7,2}, {8,2} },
    { {0,3}, {1,3}, {2,3}, {0,4}, {1,4}, {2,4}, {0,5}, {1,5}, {2,5} },
    { {3,3}, {4,3}, {5,3}, {3,4}, {4,4}, {5,4}, {3,5}, {4,5}, {5,5} },
    { {6,3}, {7,3}, {8,3}, {6,4}, {7,4}, {8,4}, {6,5}, {7,5}, {8,5} },
    { {0,6}, {1,6}, {2,6}, {0,7}, {1,7}, {2,7}, {0,8}, {1,8}, {2,8} },
    { {3,6}, {4,6}, {5,6}, {3,7}, {4,7}, {5,7}, {3,8}, {4,8}, {5,8} },
    { {6,6}, {7,6}, {8,6}, {6,7}, {7,7}, {8,7}, {6,8}, {7,8}, {8,8} }
};
4

1 に答える 1

1

ミスター・スミスは公式の回答を提出するつもりはないと思います (私は彼にポイントを与えることにしました)。

問題は、std C 関数 rand() が [0,INT_MAX] の範囲の整数を返し、Java 関数 Randomizer.nextInt() が [INT_MIN,INT_MAX] の範囲にあることでした。「generator.nextInt() % 9」を「generator.randInt(9)」に置き換える必要がありましたが、うまくいきました。

于 2012-02-12T23:39:41.620 に答える