Tôi không biết mình đang làm gì sai, và tôi đã nhìn chằm chằm vào mã này cả ngày. Đây là một bộ giải Sudoku "tiêu chuẩn" trong Java, có một số int[][]
với số 0 trong đó các khoảng trống. Do tôi chỉ đi qua trong một bảng với 35 lỗ, điều này sẽ có thể giải quyết phần lớn các vấn đề, nhưng chỉ có thể giải quyết ~ 66%. Trong những trường hợp khác, có một số ít (thường là 2 hoặc 4) không gian trống còn lại, không thể giải quyết được (nghĩa là một số không chính xác đã được ghi thành board
.) Hầu như luôn luôn, nó sẽ là số 9 bị thiếu.Lỗi giải Sudoku
Tôi hiểu rằng giải pháp đơn giản như vậy sẽ không giải quyết được tất cả Sudokus. Tôi cố tình cho nó dễ dàng.
import java.util.ArrayList;
import java.util.List;
public class SudokuSolver
{
public SudokuSolver()
{
init();
}
public boolean solve()
{
/* Each method checks (in different ways) to see if it can find a new number
If said method does find a number, it sets off a chain reaction, starting back at the beginning.
*/
int countdown = 20;
while(!solved() && --countdown > 0)
{
if(given())
continue;
if(findSingletons())
continue;
if(zerosLeft() <= 4)
justGuess();
}
return solved();
}
public boolean given()
{
boolean repeat = false;
//Iterate through every given number
for(int i=0;i<9;i++)
{
for(int j=0;j<9;j++)
{
if(board[i][j] != 0 && !found[i][j])
{
repeat = true;
foundNum(i, j, board[i][j]);
}
}
}
//Call given every time a new number is found
return repeat;
}
public boolean findSingletons()
{
boolean repeat = false;
//LOTS of iteration, but I'm out of ideas.
int[] values;
ArrayList<Integer> singletons = new ArrayList<Integer>();
for(int i=0;i<9;i++)
{
values = new int[10];
singletons.clear();
for(int j=0;j<9;j++)
for(int k=0;k<possible[i][j].size();k++)
values[possible[i][j].get(k)]++;
for(int j=1;j<10;j++)
if(values[j] == 1)
singletons.add(j);
for(int j=0;j<9;j++)
for(int k=0;k<singletons.size();k++)
if(possible[i][j].contains(singletons.get(k)))
{
foundNum(i, j, singletons.get(k));
repeat = true;
}
}
for(int i=0;i<9;i++)
{
values = new int[10];
singletons.clear();
for(int j=0;j<9;j++)
for(int k=0;k<possible[j][i].size();k++)
values[possible[j][i].get(k)]++;
for(int j=1;j<10;j++)
if(values[j] == 1)
singletons.add(j);
for(int j=0;j<9;j++)
for(int k=0;k<singletons.size();k++)
if(possible[j][i].contains(singletons.get(k)))
{
foundNum(j, i, singletons.get(k));
repeat = true;
}
}
int[] corners = {0,3,6};
for(int a=0;a<3;a++)
for(int l=0;l<3;l++)
for(int i=corners[a];i<corners[a]+3;i++)
{
values = new int[10];
singletons.clear();
for(int j=corners[l];j<corners[l]+3;j++)
for(int k=0;k<possible[i][j].size();k++)
values[possible[i][j].get(k)]++;
for(int j=1;j<10;j++)
if(values[j] == 1)
singletons.add(j);
for(int j=0;j<9;j++)
for(int k=0;k<singletons.size();k++)
if(possible[i][j].contains(singletons.get(k)))
{
foundNum(i, j, singletons.get(k));
repeat = true;
}
}
return repeat;
}
public void justGuess()
{
outer:
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
if(board[i][j] == 0)
{
foundNum(i, j, possible[i][j].get(0));
break outer;
}
}
public void foundNum(int x, int y, int numFound)
{
if(board[x][y] != 0 && board[x][y] != numFound)
{
throw new RuntimeException("Attempting to place a number where one was already found");
}
board[x][y] = numFound;
possible[x][y].clear();
possible[x][y].add(numFound);
found[x][y] = true;
for(int i=0;i<9;i++) {
if(i != x)
if(possible[i][y].indexOf(numFound) != -1)
possible[i][y].remove(possible[i][y].indexOf(numFound));
}
for(int i=0;i<9;i++) {
if(i != y)
if(possible[x][i].indexOf(numFound) != -1)
possible[x][i].remove(possible[x][i].indexOf(numFound));
}
int cornerX = 0;
int cornerY = 0;
if(x > 2)
if(x > 5)
cornerX = 6;
else
cornerX = 3;
if(y > 2)
if(y > 5)
cornerY = 6;
else
cornerY = 3;
for(int i=cornerX;i<10 && i<cornerX+3;i++)
for(int j=cornerY;j<10 && j<cornerY+3;j++)
if(i != x && j != y)
if(possible[i][j].indexOf(numFound) != -1)
possible[i][j].remove(possible[i][j].indexOf(numFound));
}
public boolean solved() {
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
if(!found[i][j])
return false;
return true;
}
public void reset(int[][] board)
{
this.board = board;
init();
}
public void init()
{
possible = new ArrayList[9][9];
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
{
possible[i][j] = new ArrayList<Integer>();
for(int k=1;k<10;k++)
possible[i][j].add(k);
}
found = new boolean[9][9];
}
public void print()
{
for(int i=0;i<9;i++)
{
if(i%3==0 && i != 0)
System.out.println("- - - | - - - | - - -");
for(int j=0;j<9;j++)
{
if(j%3==0 & j != 0)
System.out.print("| ");
System.out.print(board[i][j] + " ");
}
System.out.println();
}
System.out.println();
}
private int zerosLeft()
{
int empty = 0;
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
if(board[i][j] == 0)
empty++;
return empty;
}
private void data(int difficulty)
{
int empty = 0;
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
if(board[i][j] == 0)
empty++;
System.out.println(empty);
}
public static void main(String[] args)
{
SudokuGenerator sg = new SudokuGenerator();
SudokuSolver ss = new SudokuSolver();
int[][] tempBoard = {{4, 0, 1, 0, 9, 7, 0, 5, 8 },
{2, 0, 0, 5, 3, 1, 4, 0, 6 },
{5, 0, 6, 4, 0, 2, 0, 3, 9 },
{0, 9, 0, 0, 0, 4, 3, 0, 2 },
{0, 0, 0, 9, 0, 0, 6, 4, 7 },
{7, 0, 4, 0, 0, 0, 9, 0, 5 },
{0, 0, 7, 0, 0, 3, 8, 9, 4 },
{8, 5, 0, 1, 4, 9, 7, 0, 0 },
{9, 0, 3, 8, 7, 6, 0, 0, 0 }};
ss.reset(tempBoard);
System.out.println(ss.solve());
ss.print();
ss.data(35);
}
int[][] board;
ArrayList<Integer>[][] possible;
boolean[][] found;
}
Tôi vẫn còn mới để lập trình, vì vậy mọi lời khuyên khác ngoài việc giải quyết điều này sẽ được hoan nghênh. (Đặc biệt tối ưu hóa possible
. Đó là mã độc nhất mà tôi đã viết cho đến nay.)
Cảm ơn!
"Đó là mã độc nhất mà tôi đã viết cho đến nay". Eric Lippert đã viết một bộ giải Sudoku khá đẹp như một phần của [loạt màu đồ thị] của anh ấy (http://blogs.msdn.com/b/ericlippert/archive/tags/graph+colouring/) trong C#. Nó sử dụng một số tính năng mà Java không có, nhưng tôi khuyên bạn nên xem xét. –
Phát triển ổ đĩa bằng cách viết các bài kiểm tra jUnit để kiểm tra các phương pháp cụ thể. Đọc về Phát triển theo hướng thử nghiệm (TDD), Đọc trên Thiết kế hướng đối tượng. Có một vài yếu tố tái tạo mã rõ ràng nên được áp dụng ở đây không có thời gian ngay bây giờ để thực hiện đánh giá đầy đủ. Nhưng đây là một số điểm nổi bật: findSingletons rất dài. Xem xét tái cấu trúc nó thành các phương thức nhỏ hơn. Ghi đè toString thay vì sử dụng phương thức in; Kiểm tra mã mà tôi đã viết trên một vấn đề tương tự nhưng đơn giản ở đây https://github.com/RobertKielty/q8impl/tree/master/workspace/EightQueens –
@Rob: Bạn có thể xóa nhận xét của riêng mình (bạn có cần danh tiếng hơn cho điều đó không ?) - ví dụ nếu bạn nhấn sớm "enter", có lẽ để tạo một dòng mới. –