2016-04-01 18 views
2

'da ana yöntemle yapılan her çağrıda uyku veya bekleme süresi Ana bilgisayarda, bir yöntem için solve() yöntemine yalnızca bir çağrı olduğunu bir Swing sınıfı kodladım. Bu yöntem bir süre döngü uygular ve hemen hemen her turda başka bir yöntem kullanır, bu yöntem boya() olarak adlandırılır ve referansı bir 2B dizisinde saklanan 9x9 GridLayout'un içindeki bir JPanel değerini değiştirir.Saldırı sınıfı

Panel değiştirilmeden önce 2 saniye geçiş yapmadan önce paint() numaralı bir zamanlayıcıya ihtiyacım var. Bunu ilk kez deniyor, ama 2 saniyeden sonra beklemeden döngünün her turunu yapıyor. Amaç, herhangi bir panel değiştirilmeden önce 2 saniye geçmesidir. Javax Timer'ı kullanmayı denedim. Thread.sleep() görünüşte bir Swing sınıfında çalışmaz.

import javax.swing.*; 
import javax.swing.Timer; 
import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.*; 
import java.util.Stack; 

public class SudokuApp { 

    private JFrame frame; 
    int i = 9; 
    int j = 9; 
    JPanel[][] board = new JPanel[i][j]; 
    JButton nextButton = new JButton("Resolver"); 
    Box[][] sudoku = new Box[9][9]; 
    Box newCurrent = new Box(); 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       try { 
        SudokuApp window = new SudokuApp(); 
        window.frame.setVisible(true); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 
    } 

    public SudokuApp() { 
     initialize(); 
    } 

    private void initialize() { 
     frame = new JFrame(); 
     frame.setTitle("Sudoku Solver"); 
     frame.setBounds(100, 100, 510, 555); 
     frame.setLocationRelativeTo(null); 
     frame.setResizable(false); 
     frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 

     JPanel panel = new JPanel(); 
     frame.getContentPane().add(panel, BorderLayout.CENTER); 
     panel.setLayout(new GridLayout(i, j)); 

     //Initiate board 

     for (int m = 0; m < i; m++) { 
      for (int n = 0; n < j; n++) { 
       board[m][n] = new JPanel(); 
       JTextField textField = new JTextField(1); 
       textField.setFont(new Font("Lucida Grande", Font.BOLD, 25)); 
       board[m][n].add(textField); 
       panel.add(board[m][n]); 
      } 
     } 

     Box last = new Box(); 
     for (int m = 0; m < this.i; m++) { 
      for (int n = 0; n < this.j; n++) { 
       sudoku[m][n] = new Box(m, n); 
       if (m != 0 || n != 0) sudoku[m][n].back = last; 
       last = sudoku[m][n]; 
      } 
     } 

     //Solve button action listener 

     nextButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { 
      if (validBoard()) { 
       nextButton.setEnabled(false); 
       solve(); 
      } 
      else JOptionPane.showMessageDialog(null, "Condiciones iniciales inválidas."); 
     } }); 
     frame.getContentPane().add(nextButton, BorderLayout.SOUTH); 
    } 

    private boolean validBoard() { 
     for (int m = 0; m < i; m++) { 
      for (int n = 0; n < j; n++) { 
       JTextField current = (JTextField) board[m][n].getComponent(0); 
       String text = current.getText(); 
       if (text.length() == 1 && !text.contains("0")) { 
        try { 
         int number = Integer.parseInt(text); 
         if (!add(number, m, n)) return false; 
         current.setEditable(false); 
        } catch (NumberFormatException e) { 
         return false; 
        } 
       } else { 
        current.setText(""); 
        current.setEditable(false); 
       } 
      } 
     } 
     return true; 
    } 

    private void solve() { 
     int i = 0; 
     int j = 0; 
     int newI = i + 1; 

     while (i < 9) { 
      while (j < 9) { 
       Box current = sudoku[i][j]; 

       if (current.number == 0) { 
        HashSet<Integer> possibles = new HashSet<>(); 
        HashSet<Integer> takenNumbers = getTakenNumbers(i, j); 
        for (int k = 1; k <= 9; k++) if (!takenNumbers.contains(k)) possibles.add(k); 

        if (possibles.isEmpty()) { 
         current.number = 0; 
         erase(i, j); 
         tryOther(current.back); 

         i = newCurrent.i; 
         newI = i + 1; 
         j = newCurrent.j + 1; 
        } else { 
         for (Integer p : possibles) current.possibles.push(p); 
         current.number = (int) current.possibles.pop(); 

         paint(current.number, i, j); 

         j++; 
         newI = i + 1; 
        } 
       } else { 
        j++; 
        newI = i + 1; 
       } 
      } 
      i = newI; 
      j = 0; 
     } 
    } 

    private void tryOther(Box box) { 
     if (box.possibles.empty()) { 
      if (box.back != null) { 
       if (!box.initial) { 
        box.number = 0; 
        erase(box.i, box.j); 
       } 
       tryOther(box.back); 
      } 
      else newCurrent = null; 
     } else { 
      if (getTakenNumbers(box.i, box.j).contains(box.possibles.peek())) { 
       box.possibles.pop(); 
       tryOther(box); 
      } 
      newCurrent = box; 
      box.number = (int) box.possibles.pop(); 
      paint(box.number, box.i, box.j); 
     } 
    } 

    private boolean add(int a, int i, int j) { 
     if (getTakenNumbers(i, j).contains(a)) return false; 
     sudoku[i][j].number = a; 
     sudoku[i][j].initial = true; 
     return true; 
    } 

    private void paint(int a, int i, int j) { 
     JPanel panel = board[i][j]; 
     JTextField jTextField = (JTextField) board[i][j].getComponent(0); 
     jTextField.setFont(new Font("Lucida Grande", Font.PLAIN, 25)); 
     jTextField.setForeground(Color.gray); 

     ActionListener task = new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       System.out.println("T"); 
      } 
     }; 
     Timer timer = new Timer(3000 , task); 
     timer.setRepeats(false); 
     timer.start(); 

     jTextField.setText("" + a); 
     panel.revalidate(); 
     panel.repaint(); 
    } 

    private void erase(int i, int j) { 
     JTextField jTextField = (JTextField) board[i][j].getComponent(0); 
     jTextField.setText(""); 
     board[i][j].revalidate(); 
     board[i][j].repaint(); 
    } 

    private HashSet<Integer> getTakenNumbers(int i, int j) { 
     HashSet<Integer> takenNumbers = new HashSet<>(); 

     for (int k = 0; k < 9; k++) if (sudoku[i][k].number != 0 && k != j) takenNumbers.add(sudoku[i][k].number); 
     for (int k = 0; k < 9; k++) if (sudoku[k][j].number != 0 && k != i) takenNumbers.add(sudoku[k][j].number); 

     int bigBoxRow = 0; 
     int bigBoxColumn = 0; 
     if (i <= 5 && i > 2) bigBoxRow = 3; 
     if (i <= 8 && i > 5) bigBoxRow = 6; 
     if (j <= 5 && j > 2) bigBoxColumn = 3; 
     if (j <= 8 && j > 5) bigBoxColumn = 6; 

     for (int k = bigBoxRow; k < bigBoxRow + 3; k++) for (int l = bigBoxColumn; l < bigBoxColumn + 3; l++) if (sudoku[k][l].number != 0 && k != i && l != j) takenNumbers.add(sudoku[k][l].number); 

     return takenNumbers; 
    } 
} 



import java.util.Stack; 
public class Box { 

    public int number = 0; 
    public int i, j; 
    public Stack possibles = new Stack(); 
    public Box back; 
    public boolean initial = false; 

    public Box(int i, int j) { 
     this.i = i; 
     this.j = j; 
    } 

    public Box() {} 
} 
+0

' "Javax Timer'ı kullanmayı denedim ama kullanmak için herhangi bir eylem dinleyicim yok ..." - bu bir anlam ifade etmiyor. Neden jTextField'ın metnini ayarlayan basit bir ActionListener yaratmıyorsunuz? –

+0

Haklısın, ben de yaptım ama sadece ilk kez bekliyorum. Güncellenen koda bak. – niklabaz

+1

Bu işe yaramalı. Değilse, o zaman [mcve] 'yi oluşturup gönderin ve kodunuzu test etmemize izin verin. –

cevap

3

Programınızın yapısını değiştirmeniz gerekir. Özellikle, çözme yönteminizdeki iç içe geçmiş döngülerden kurtulmak ve bunun yerine tek bir Swing Timer ile değiştirmek isteyeceksiniz. Bu Zamanlayıcı 9 * 9 kez tekrarlanacak ve bunun içinde bir sayaç alanı olacak ve bunun içinde iç içe geçmiş döngüler içinde yapmakta olduğunuz kodu yapmak isteyeceksiniz. Bu şuna benzer olabilir

... gecikmeyle alanlardaki metni yerleştirir (ama hiçbir şey çözmez) işleyen bir programın bir örnek için

// TIMER_DELAY could be 2000 if you want a 2 second delay 
    new Timer(TIMER_DELAY, new ActionListener() { 
     private int i = 0; 
     private int j = 0; 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      // MAX_ROWS is 9 
      if (i == MAX_ROWS) { 
       // we've iterated through the whole thing 
       ((Timer) e.getSource()).stop(); 
      } 
      if (j == MAX_ROWS) { 
       // we've gone through all the columns 
       i++; // the next row 
       j = 0; // start at column 0 
      } 
      // TODO the code in the nested while loop. 

      j++; 
     } 
    }).start(); 

:

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Font; 
import java.awt.GridLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import javax.swing.*; 

public class SudokuMCVE extends JPanel { 
    private static final int CLUSTER = 3; 
    private static final int MAX_ROWS = 9; 
    private static final float FIELD_PTS = 32f; 
    private static final int GAP = 3; 
    private static final Color BG = Color.BLACK; 
    private static final Color SOLVED_BG = Color.LIGHT_GRAY; 
    public static final int TIMER_DELAY = 2 * 1000; 
    private JTextField[][] fieldGrid = new JTextField[MAX_ROWS][MAX_ROWS]; 

    public SudokuMCVE() { 
     JPanel mainPanel = new JPanel(new GridLayout(CLUSTER, CLUSTER)); 
     mainPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP)); 
     mainPanel.setBackground(BG); 
     JPanel[][] panels = new JPanel[CLUSTER][CLUSTER]; 
     for (int i = 0; i < panels.length; i++) { 
      for (int j = 0; j < panels[i].length; j++) { 
       panels[i][j] = new JPanel(new GridLayout(CLUSTER, CLUSTER, 1, 1)); 
       panels[i][j].setBackground(BG); 
       panels[i][j].setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP)); 
       mainPanel.add(panels[i][j]); 
      } 
     } 

     for (int row = 0; row < fieldGrid.length; row++) { 
      for (int col = 0; col < fieldGrid[row].length; col++) { 
       fieldGrid[row][col] = createField(row, col); 
       int i = row/3; 
       int j = col/3; 
       panels[i][j].add(fieldGrid[row][col]); 
      } 
     } 

     setLayout(new BorderLayout()); 
     add(mainPanel, BorderLayout.CENTER); 
     add(new JButton(new SolveAction("Solve")), BorderLayout.PAGE_END); 
    } 

    private JTextField createField(int row, int col) { 
     JTextField field = new JTextField(2); 
     field.setHorizontalAlignment(JTextField.CENTER); 
     field.setFont(field.getFont().deriveFont(Font.BOLD, FIELD_PTS)); 

     return field; 
    } 

    private class SolveAction extends AbstractAction { 

     public SolveAction(String name) { 
      super(name); 
      int mnemonic = (int) name.charAt(0); 
      putValue(MNEMONIC_KEY, mnemonic); 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      new Timer(TIMER_DELAY, new ActionListener() { 
       private int i = 0; 
       private int j = 0; 

       @Override 
       public void actionPerformed(ActionEvent e) { 
        // MAX_ROWS is 9 
        if (i == MAX_ROWS) { 
         ((Timer) e.getSource()).stop(); 
        } 
        if (j == MAX_ROWS) { 
         i++; 
         j = 0; 
        } 
        int number = (int) (MAX_ROWS * Math.random()) + 1; 
        fieldGrid[i][j].setBackground(SOLVED_BG); 
        fieldGrid[i][j].setText(String.valueOf(number)); 

        j++; 
       } 
      }).start(); 
     } 
    } 

    private static void createAndShowGui() { 
     SudokuMCVE mainPanel = new SudokuMCVE(); 

     JFrame frame = new JFrame("SudokuMCVE"); 
     frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
     frame.getContentPane().add(mainPanel); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(() -> { 
      createAndShowGui(); 
     }); 
    } 
} 
+0

Tam çözüm yöntemi, tamamlanmadan önce belirli bir süre beklemez mi? Söylediklerinizi yapabilir miyim, ama sadece boya() çağırdığımda zamanlayıcıyı kullanabilir miyim? – niklabaz

+0

@nxbarz: Kareler arasındaki 2 saniyelik bir gecikmeyle her kareyi birer birer çözer - istediğiniz gibi değil mi? Dene ve ne olacağını gör. –

+0

Bu, newI zamansal değişkenim ile çalışmaz değil mi? Yeniden düşünmeli miyim? – niklabaz