[英]Recursive Sudoku Solver doesn't work in Java
我用C語言編寫了一個包含求解器的Sudoku游戲,並想在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.找到沒有解決方案。 按照我的邏輯,我看不到它應該無限遞歸的方法。
這是GetMask Java代碼:
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} }
};
我猜史密斯先生不會提交正式答復(我想我可以讓他提出要點)。
問題在於標准C函數rand()返回范圍為[0,INT_MAX]的整數,而Java函數Randomizer.nextInt()則為[INT_MIN,INT_MAX]范圍。 我必須將“ generator.nextInt()%9”替換為“ generator.randInt(9)”,它才有效。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.