2013-03-11 2 views
1

현재 자바에서 제 두 번째 프로그래밍 과정을 공부하고 있으며 과정을 통과하기 위해 완료해야하는 과제에 문제가 있습니다. 기본적으로 그것은 역 추적으로 스도쿠를 재귀 적으로 해결하는 프로그램을 작성하는 것입니다. 이것이 내가 생각해 낸 알고리즘이다. 처음에는 0으로 채워진 격자를 나타 내기 위해 9x9 배열을 사용했습니다. checkFill은 숫자 (var)를 [i] [j] 위치에 삽입 할 수 있는지 여부를 확인합니다. 문제는 단지 스도쿠를 부분적으로 해결한다는 것입니다. 항상 부분적으로 항상 거짓 (솔루션 없음)을 반환하고 일부 셀에는 여전히 0이 포함됩니다. 여기서 내가 뭘 잘못하고 있니?스도쿠 해결을위한 재귀 방법

import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import javax.swing.*; 

public class Sudoku { 
    private int[][] sudoku; 
    private JFrame frame; 
    private JFormattedTextField[][] sudokuSquares; 
    private JButton solve, clear; 

    public Sudoku() { 
     sudoku = new int[9][9]; 
     frame = new JFrame("Sudoku Solver"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     JPanel northPanel = new JPanel(); 
     northPanel.setLayout(new GridLayout(9, 9)); 
     northPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 
     sudokuSquares = new JFormattedTextField[9][9]; 
     Font font1 = new Font("SansSerif", Font.BOLD, 20); 
     for(int i = 0; i < 9; i++) { 
      for(int j = 0; j < 9; j++) { 
       sudokuSquares[i][j] = new JFormattedTextField(); 
       sudokuSquares[i][j].setHorizontalAlignment(JTextField.CENTER); 
       sudokuSquares[i][j].setFont(font1); 
       sudokuSquares[i][j].setBorder(BorderFactory.createEtchedBorder(javax.swing.border.EtchedBorder.RAISED)); 
       northPanel.add(sudokuSquares[i][j]); 
      } 
     } 
     setColor(); 
     frame.add(northPanel, BorderLayout.NORTH); 
     JPanel southPanel = new JPanel(); 
     solve = new JButton("Solve"); 
     solve.addActionListener(new SolveButtonListener()); 
     clear = new JButton("Clear"); 
     clear.addActionListener(new ClearButtonListener()); 
     southPanel.add(clear); 
     southPanel.add(solve); 
     frame.add(southPanel, BorderLayout.SOUTH); 
     frame.setResizable(false); 
     frame.setSize(280, 330); 
     frame.setVisible(true); 
    } 

    private void solveSudoku() { 
     boolean hasSolution = solve(0, 0); 
     if(hasSolution) { 
      JOptionPane.showMessageDialog(frame, "Sudoku has been successfully solved"); 
     } else { 
      JOptionPane.showMessageDialog(frame, "Sudoku has no solution"); 
     } 

    } 

    private class SolveButtonListener implements ActionListener { 
     @Override 
     /** 
     * Checks input for errors and outputs the sudoku matrix after it's been solved. 
     */ 
     public void actionPerformed(ActionEvent e) { 
      String s; 
      setColor(); 
      for(int i = 0; i < 9; i++) { 
       for(int j = 0; j < 9; j++) { 
        s = sudokuSquares[i][j].getText(); 
        if(s.isEmpty()) { 
         s = "0"; 
        } else if(s.length() > 1 || !Character.isDigit(s.charAt(0)) || s.charAt(0) == '0') { 
         sudokuSquares[i][j].setBackground(Color.RED); 
         JOptionPane.showMessageDialog(frame, "Invalid entry! Please enter a number between 1-9"); 
         return; 
        } 
        sudoku[i][j] = Integer.parseInt(s); 
       } 
      } 
      solveSudoku(); 
      for(int i = 0; i < 9; i++) { 
       for(int j = 0; j < 9; j++) { 
        sudokuSquares[i][j].setText(String.valueOf(sudoku[i][j])); 
       } 
      } 
     } 
    } 

    private class ClearButtonListener implements ActionListener { 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      for(int i = 0; i < 9; i++) { 
       for(int j = 0; j < 9; j++) { 
        sudokuSquares[i][j].setText(""); 
       } 
      } 
      setColor(); 
     } 
    } 

    /** 
    * Sets the background color of sudoku cells 
    */ 
    private void setColor() { 
     for(int i = 0; i < 9; i++) { 
      for(int j = 0; j < 9; j++) { 
       if((i/3 < 1 || i/3 >= 2) && (j/3 < 1 || j/3 >= 2) || 
         (i/3 >= 1 && i/3 < 2) && (j/3 >= 1 && j/3 < 2)) { 
        sudokuSquares[i][j].setBackground(new Color(220, 220, 220)); 
       } else { 
        sudokuSquares[i][j].setBackground(Color.WHITE); 
       } 
      } 
     } 
    } 

    /** 
    * Solves the sudoku through recursive technique 
    * @param i row 
    * @param j column 
    * @return returns true if the sudoku has a solution, returns false otherwise 
    */ 
    private boolean solve(int i, int j) { 
     if(i > 8) { 
      return true; 
     } 
     if(sudoku[i][j] == 0) { 
      for(int var = 1; var < 10; var++) { 
       if(checkFill(i, j, var)) { 
        sudoku[i][j] = var; 
        if(j >= 8) { 
         solve(i + 1, 0); 
        } else { 
         solve(i, j+1); 
        } 
       } 
      } 
     } else { 
      if(j >= 8) { 
       solve(i + 1, 0); 
      } else { 
       solve(i, j+1); 
      } 
     } 
     return false; 
    } 

    /** 
    * Checks if var could be inserted at position [i][j] 
    * @param i row 
    * @param j column 
    * @param var number to be checked for possible insertion 
    * @return 
    */ 
    private boolean checkFill(int i, int j, int var) { 
     for(int a = 0; a < 9; a++) { 
      if(sudoku[a][j] == var) { 
       return false; 
      } 
     } 
     for(int a = 0; a < 9; a++) { 
      if(sudoku[i][a] == var) { 
       return false; 
      } 
     } 
     int tempI = (i/3) * 3; 
     int tempJ = (j/3) * 3; 
     for(int a = 0; a < 3; a++) { 
      for(int b = 0; b < 3; b++) { 
       if(sudoku[tempI + a][tempJ + b] == var) 
        return false; 
      } 
     } 
     return true; 
    } 

} 

누구에게 아이디어가 있습니까?

+1

디버깅 해 보셨습니까? – kunal

답변

2

은 행을 확인 , 열 및 로컬 3x3 표를 선택하고 세 개의 검사가 통과되면 영구적으로 배치합니다.

대부분의 스도쿠는 이러한 간단한 검사에서 단일 가능성을 산출하지 않기 때문에 문제가됩니다.

각 지점에 가능한 값의 목록을 작성한 다음 double pairs과 같은 기술을 사용하여 추가로 해결해야합니다.

컴퓨터이기 때문에 빠른 것이므로 일부 기술을 사용하면 무차별 강요를 시작할 수 있습니다.

다른 접근법은 수독 문제를 SAT 수식으로 변환하고 SAT 수식에 입력 한 다음 다시 수독 솔루션으로 변환하는 것입니다. 요즘에는 매우 빠른 SAT 솔버가있어 9x9 스도쿠를 매우 빠르게 처리 할 수 ​​있습니다. Here은 더 자세한 설명입니다.

0

간단한 자바 스도쿠 프로그램을 여기에서 찾을 수 있습니다. http://www.heimetli.ch/ffh/simplifiedsudoku.html

당신에게 방법 checkFill을 포함한 전체 소스 코드를 공유 할 수 있다면, 우리가 debuging에서 당신을 도와 드릴 수 있습니다 더

주어진 숫자가 주어진 슬롯에 들어갈 수있는 경우 프로그램이 단순히 검사 것으로 보인다
+0

나는 많은 경험이 없으므로 디버깅을 시도하지 않았다. – user2155599

+1

그런 다음 이것을 경험으로 익힐 수있는 기회로 삼으십시오. 그것은 당신이 자주 필요로하는 귀중한 기술입니다. – meriton

1

해결 방법에서 변경하기 전에 sudoku [i] [j] == 0인지 테스트합니다. 즉, 번호를 올리면 옳은지 여부를 판단 할 수 있습니다. 당신은 잘못된 움직임에서 벗어날 수 있어야합니다.

+0

이것은 if 문을 제거하는 것처럼 간단 할 수 있습니다. – phatfingers