import java.awt.*; import java.awt.event.*; import java.io.File; import javax.swing.*; /* * Implementacao da interface grafica para o EP3 - MAC110 BCC - 2006 * * Atencao: a classe Jogada contém valores de linha/coluna de 1 a 9 * * versao 0.3 (01/07/2006) * - Nao mostra valores de celula quando for 0 ou -1 * - Apaga graus de liberdade depois de uma jogada * - ExecutaJogada(...) recebe valores de linha/coluna de 1 a 9 (e nao de 0 a 8 !) * - CelulaGUI guarda os valores de 1 a 9 * - PossiveisJogadas aceita valor null ou vetor vazio qdo não há jogadas * - PossiveisJogadas e SugerirJogada acendem a celula correspondente * - ExecutaJogada mostra em verde/vermelho se a jogada deu certo. * * A parte grafica supoe que o codigo do Sudoku de vcs * implementa a interface SudokuGame (que eh uma lista de metodos). * Para isso, a definicao da classe devera ser a seguinte: * // class Sudoku implements SudokuGame * * * Para usar vcs devem criar um objeto do tipo SudokuGUI e * passar no construtor uma referencia para a implementacao * do Sudoku de vcs. * Exemplo: * public static void main(String[] args) { // Cria um objeto com a implementacao do Sudoku do aluno System.out.println("Criando objeto Sudoku..."); Sudoku jogo = new Sudoku(); // Cria a janela e passa a referancia para a implementacao System.out.println("Criando interface grafica SudokuGUI..."); SudokuGUI janela = new SudokuGUI(jogo); } * * Assim que encontrarem algum erro, coloque uma mensagem no wiki: * http://julian.com.br/dokuwiki * ou envie um email para mim: jm@ime.usp.br * * * Created by JM on Jun 24, 2006 * CopyLeft IME/USP * */ class SudokuGUI extends JFrame implements ActionListener { // ===== SUDOKU ==== SudokuGame sudoku; // Implementacao do Sudoku feita pelo aluno static final String title = "-=# Sudoku v0.3 - BCC 2006 #=-"; // ===== BOTOES ===== private JPanel painelBotoes; private JButton botaoLer; private JButton botaoGerar; private JButton botaoVerificar; private JButton botaoLimpar; private JButton botaoGrausLiberdade; private JButton botaoSugerir; private JButton botaoDesfazer; private JButton botaoJogar; private JButton botaoPossiveisJogadas; private JLabel labelJogar; private JTextField numeroJogada; // ===== TABULEIRO ===== private JPanel painelTabuleiro; private JPanel painelCaixas; private CelulaGUI tabuleiro[][]; // Tabuleiro CelulaGUI celSelecionada = null; // Celula selecionada CelulaGUI celSugestao = null; // Sugestao de proxima jogada // ===== STATUS ===== private JPanel painelStatus; private JLabel labelStatus; // ===== OUTROS ===== JFileChooser fc; /** * Construtor * */ public SudokuGUI(SudokuGame sudoku) { this.sudoku = sudoku; //Guarda uma referencia para a implementacao do sudoku initComponents(); //Inicializa componentes da Janela this.setVisible(true); } /** * initComponents: Inicializa os compenentes da Janela * */ private void initComponents() { tabuleiro = new CelulaGUI[9][9]; //Create a file chooser fc = new JFileChooser(); //============================= //===== PAINEL BOTOES painelBotoes = new JPanel(); painelBotoes.setBackground(new java.awt.Color(240, 240, 250)); painelBotoes.setBorder(javax.swing.BorderFactory.createTitledBorder("Opções")); painelBotoes.setLayout(new GridLayout(3,1)); //============================= //===== 1a LINHA DE BOTOES: Tabuleiro JPanel botoes = new JPanel(); botoes.setLayout(new FlowLayout(FlowLayout.LEFT)); botoes.setBackground(new Color(240, 240, 250)); botoes.add(new JLabel("Tabuleiro:")); botaoLer = new JButton("Abrir"); botaoLer.addActionListener(this); botoes.add(botaoLer); botaoGerar = new JButton("Gerar"); botaoGerar.addActionListener(this); botoes.add(botaoGerar); botaoVerificar = new JButton("Verificar"); botaoVerificar.addActionListener(this); botoes.add(botaoVerificar); //botaoAtualizar = new JButton("Atualizar"); //botaoAtualizarr.addActionListener(this); //botoes.add(botaoAtualizar); botaoLimpar = new JButton("Limpar"); botaoLimpar.addActionListener(this); botoes.add(botaoLimpar); painelBotoes.add(botoes); //============================= //===== 2a LINHA DE BOTOES : Jogada JPanel botoesJogo = new JPanel(); botoesJogo.setLayout(new FlowLayout(FlowLayout.LEFT));//setLayout(new GridLayout(1,6,3,3)); botoesJogo.setBackground(new Color(220, 220, 230)); botoesJogo.add(new JLabel("Jogada: ")); botaoGrausLiberdade = new JButton("Graus de Liberdade"); botaoGrausLiberdade.addActionListener(this); botoesJogo.add(botaoGrausLiberdade); botaoSugerir = new JButton("Sugerir"); botaoSugerir.addActionListener(this); botoesJogo.add(botaoSugerir); botaoDesfazer = new JButton("Desfazer"); botaoDesfazer.addActionListener(this); botoesJogo.add(botaoDesfazer); painelBotoes.add(botoesJogo); //============================= //===== 3a LINHA DE BOTOES : Celula //#### JOGAR #### JPanel botoesCelula = new JPanel(); botoesCelula.setBackground(new Color(240, 240, 250)); botoesCelula.setLayout(new FlowLayout(FlowLayout.LEFT)); //BoxLayout(botoesCelula, BoxLayout.X_AXIS)); //GridLayout(1,6)); labelJogar = new JLabel("Célula (?,?)"); numeroJogada = new JTextField(3); botoesCelula.add(labelJogar); botoesCelula.add(new JLabel(" ")); botoesCelula.add(numeroJogada); botoesCelula.add(new JLabel(" ")); botaoJogar = new JButton("Jogar"); botaoJogar.addActionListener(this); botoesCelula.add(botaoJogar); botaoPossiveisJogadas = new JButton("Possíveis Jogadas"); botaoPossiveisJogadas.addActionListener(this); botoesCelula.add(botaoPossiveisJogadas); painelBotoes.add(botoesCelula); //========================= //===== PAINEL TABULEIRO painelTabuleiro = new JPanel(); painelTabuleiro.setLayout(new BorderLayout());//new java.awt.GridLayout(3, 3)); painelTabuleiro.setBorder(javax.swing.BorderFactory.createTitledBorder("Tabuleiro")); // Adiciona as numeracoes laterais (de 1 a 9) JPanel painelNumeros = new JPanel(); painelNumeros.setLayout(new GridLayout(1,10,2,2)); for (int i = 1; i <= 9; i++) { JLabel num = new JLabel(""+i); num.setForeground(Color.BLUE.darker()); num.setHorizontalAlignment(JLabel.CENTER); painelNumeros.add(num); } painelTabuleiro.add(painelNumeros, BorderLayout.NORTH); painelNumeros = new JPanel(); painelNumeros.setLayout(new GridLayout(9,1,2,2)); for (int i = 1; i <= 9; i++) { JLabel num = new JLabel(""+i); num.setForeground(Color.BLUE.darker()); num.setHorizontalAlignment(JLabel.CENTER); painelNumeros.add(num); } painelTabuleiro.add(painelNumeros, BorderLayout.WEST); // Adiciona 3x3 caixas, cada caixa ira conter 3x3 celulas painelCaixas = new JPanel(); painelCaixas.setLayout(new java.awt.GridLayout(3, 3)); for (int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { initCaixa(i,j); } } painelTabuleiro.add(painelCaixas, BorderLayout.CENTER); //============================= //===== PAINEL STATUS painelStatus = new JPanel(); painelStatus.setBackground(new java.awt.Color(240, 240, 250)); painelStatus.setBorder(javax.swing.BorderFactory.createTitledBorder("Sudoku:")); painelStatus.setLayout(new FlowLayout(FlowLayout.LEFT)); labelStatus = new JLabel("Para iniciar clique em Ler ou Gerar tabuleiro"); labelStatus.setForeground(Color.GREEN.darker()); painelStatus.add(labelStatus); //============================= //===== PAINEL PRINCIPAL // // Adiciona todos os paineis na Janela, um em cima do outro setTitle(title); getContentPane().setLayout(new BorderLayout(2, 2)); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); getContentPane().add(painelStatus, java.awt.BorderLayout.NORTH); getContentPane().add(painelTabuleiro, java.awt.BorderLayout.CENTER); getContentPane().add(painelBotoes, java.awt.BorderLayout.SOUTH); // ===== pack(); } /** * initCaixa: Inicializa uma caixa (cria 9x9 celulas) e * adiciona no painel do tabuleiro */ private void initCaixa(int i, int j) { JPanel painelCaixa = new JPanel(); painelCaixa.setLayout(new java.awt.GridLayout(3, 3)); painelCaixa.setBackground(new java.awt.Color(190, 190, 190)); painelCaixa.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1)); painelCaixa.setMaximumSize(new java.awt.Dimension(120, 120)); painelCaixa.setMinimumSize(new java.awt.Dimension(120, 120)); painelCaixa.setPreferredSize(new java.awt.Dimension(120, 120)); for (int l = 0; l < 3; l++) { for (int c = 0; c < 3; c++) { int linha = l+3*i; int coluna = c+3*j; //Guarda em celulaGUI valores de 1 a 9 tabuleiro[linha][coluna] = new CelulaGUI(linha + 1, coluna + 1); painelCaixa.add(tabuleiro[linha][coluna]); } } painelCaixas.add(painelCaixa); } /** * Guarda celula que foi selecionada (clicada) para ser usada posteriormente * */ private void clicouCelula(CelulaGUI cel, MouseEvent evt) { //DEBUG: System.out.println("Mouse clicked: "+evt.paramString()); if(celSelecionada != null) celSelecionada.deseleciona(); celSelecionada = cel; celSelecionada.seleciona(); labelJogar.setForeground(Color.BLUE.darker()); labelJogar.setText("Celula ( "+cel.getLinha()+","+cel.getColuna()+" )"); numeroJogada.setText(""); numeroJogada.grabFocus(); } /** * Atualiza todas as celulas do tabuleiro */ public void atualizaTabuleiro(int[][] tab) { for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { tabuleiro[i][j].setNumero(tab[i][j]); tabuleiro[i][j].limpaGrauLiberdade(); tabuleiro[i][j].limpaSugestao(); } } } /** * Atualiza todas as celulas do tabuleiro */ public void mostraGrausDeLiberdade(int[][] graus) { for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { tabuleiro[i][j].setGrauLiberdade(graus[i][j]); } } } /** * Trata as acoes de cada botao */ public void actionPerformed(ActionEvent e) { // ========================================================== // ===== Ler Tabuleiro do Arquivo if (e.getSource() == botaoLer) { labelStatus.setText("Escolha: Ler tabuleiro do arquivo"); labelStatus.setForeground(Color.BLACK); int returnVal = fc.showOpenDialog(SudokuGUI.this); if (returnVal == JFileChooser.APPROVE_OPTION) { File file = fc.getSelectedFile(); labelStatus.setText("Ler tabuleiro do arquivo "+file.getName()); labelStatus.setForeground(Color.GREEN.darker()); sudoku.leTabuleiroArquivo(file.getPath()); atualizaTabuleiro(sudoku.devolveTabuleiro()); } else { labelStatus.setText("Ler tabuleiro: operação cancelada"); labelStatus.setForeground(Color.RED.darker()); } return; } // ========================================================== // ===== Gerar tabuleiro aleatorio if (e.getSource() == botaoGerar) { labelStatus.setText("Gerar tabuleiro aleatório"); sudoku.geraTabuleiroAleatorio(); atualizaTabuleiro(sudoku.devolveTabuleiro()); return; } // ========================================================== // ===== Verificar Tabuleiro if (e.getSource() == botaoVerificar) { boolean tabuleiroValido = sudoku.verificaValidadeTabuleiro(); if (tabuleiroValido) { labelStatus.setText("Tabuleiro Válido :-)"); labelStatus.setForeground(Color.GREEN.darker()); } else { labelStatus.setText("Tabuleiro Inválido..."); labelStatus.setForeground(Color.RED.darker()); } return; } // ========================================================== // ===== Limpar if (e.getSource() == botaoLimpar) { labelStatus.setText("Limpar tabuleiro"); labelStatus.setForeground(Color.BLUE.darker()); sudoku.limpaTabuleiro(); atualizaTabuleiro(sudoku.devolveTabuleiro()); return; } // ========================================================== // ===== Graus de Liberdade if (e.getSource() == botaoGrausLiberdade) { labelStatus.setText("Mostrar Graus de Liberdade"); labelStatus.setForeground(Color.BLUE.darker()); int graus[][] = sudoku.calculaGrausDeLiberdade(); //TODO: arrumar mostraGrausDeLiberdade(graus); return; } // ========================================================== // ===== Sugerir Jogada if (e.getSource() == botaoSugerir) { Jogada prox = sudoku.sugereProximaJogada(); if (prox != null) { labelStatus.setText("Sugestão para próxima jogada: ("+ prox.leLinha()+","+prox.leColuna()+") = "+prox.leValor()); // mostra a celula selecionada celSugestao = tabuleiro[prox.leLinha()-1][prox.leColuna()-1]; celSugestao.setSugestao(prox.leValor()); labelStatus.setForeground(Color.GREEN.darker()); } else { labelStatus.setText("Não há sugestão para próxima jogada"); labelStatus.setForeground(Color.RED.darker()); celSugestao.limpaSugestao(); } //atualizaTabuleiro(graus); return; } // ========================================================== // ==== Desfazer Jogada if (e.getSource() == botaoDesfazer) { boolean voltou = sudoku.desfazerJogada(); atualizaTabuleiro(sudoku.devolveTabuleiro()); if (voltou) { labelStatus.setText("Desfazer: voltou uma jogada"); labelStatus.setForeground(Color.GREEN.darker()); } else { labelStatus.setText("Desfazer: não há mais jogadas a desfazer"); labelStatus.setForeground(Color.RED.darker()); } return; } // ========================================================== // ==== JOGAR if (e.getSource() == botaoJogar) { if (celSelecionada == null || numeroJogada.getText().compareTo("") == 0) { labelStatus.setText("Clique em uma célula e prencha um valor antes de jogar"); labelStatus.setForeground(Color.RED.darker()); return; } int linha = celSelecionada.getLinha(); int coluna = celSelecionada.getColuna(); int valor = 0; try { valor = Integer.parseInt(numeroJogada.getText()); } catch(NumberFormatException ex) { labelStatus.setText("Jogada inválida: não é um número"); labelStatus.setForeground(Color.RED.darker()); return; } Jogada nova = new Jogada(linha, coluna, valor); boolean jogadaValida = sudoku.executaJogada(nova); atualizaTabuleiro(sudoku.devolveTabuleiro()); if (jogadaValida) { labelStatus.setText("Jogada válida ("+linha+","+coluna+") = "+valor); labelStatus.setForeground(Color.GREEN.darker()); celSelecionada.setBackground(new Color(180,230,180)); //Verdinho } else { labelStatus.setText("Jogada ("+linha+","+coluna+") = "+valor+" é inválida!"); labelStatus.setForeground(Color.RED.darker()); celSelecionada.setBackground(new Color(230,180,180)); //Vermelhinho } return; } // ========================================================== // ==== Possiveis Jogadas if (e.getSource() == botaoPossiveisJogadas) { if (celSelecionada == null) { labelStatus.setText("Clique em uma célula antes de mostrar possíveis jogadas"); labelStatus.setForeground(Color.RED.darker()); return; } int linha = celSelecionada.getLinha(); int coluna = celSelecionada.getColuna(); Jogada[] jogadas = sudoku.calculaPossiveisJogadas(linha,coluna); if(jogadas != null && jogadas.length > 0) { String txtJogadas = "Possíveis jogadas em ("+linha+","+coluna+"): "; for (int i = 0; i < jogadas.length; i++) { if (i > 0) txtJogadas += ", "; txtJogadas += jogadas[i].leValor(); } labelStatus.setText(txtJogadas); labelStatus.setForeground(Color.GREEN.darker()); celSelecionada.setBackground(new Color(180,230,230)); //cian } else { labelStatus.setText("Não há jogadas possíveis para a célula ("+ linha+","+coluna+")"); labelStatus.setForeground(Color.RED.darker()); celSelecionada.setBackground(new Color(230,230,180)); //amarelinho } } return; } //------------------------------------------------------------------------------- /* * Classe interna que contem os dados de uma celula (linha,coluna e valor). * Ele existe para facilitar o tratamento dos cliques com o mouse. */ class CelulaGUI extends JPanel { private int linha; //valores de 1 a 9 private int coluna; // valores de 1 a 9 private JLabel numero; private JLabel grauLiberdade; private JLabel sugestao; public CelulaGUI(int linha, int coluna) { this.linha = linha; this.coluna = coluna; this.initComponents(); } private void initComponents() { setBackground(Color.WHITE); setBorder(BorderFactory.createLineBorder(Color.BLACK)); setLayout(new BorderLayout()); //===== NUMERO ===== numero = new JLabel(); numero.setHorizontalAlignment(JLabel.CENTER); numero.setVerticalAlignment(JLabel.CENTER); numero.setFont(new Font("Arial", Font.BOLD, 15)); numero.setText(""); add(numero, BorderLayout.CENTER); //===== GRAUS DE LIBERDADE (numero pequeno no canto) ===== grauLiberdade = new JLabel(); grauLiberdade.setVerticalAlignment(JLabel.NORTH); grauLiberdade.setFont(new Font("Arial",Font.PLAIN,9)); grauLiberdade.setText(""); grauLiberdade.setForeground(Color.BLUE); add(grauLiberdade, BorderLayout.EAST); //===== Sugestao (numero pequeno no canto em baixo) ===== sugestao = new JLabel(); sugestao.setHorizontalAlignment(JLabel.RIGHT); sugestao.setFont(new Font("Arial",Font.PLAIN,10)); sugestao.setText(""); sugestao.setForeground(Color.BLACK); add(sugestao, BorderLayout.SOUTH); // Ao clicar, chama o metodo clicouCelula em CelulaGUI addMouseListener(new MouseAdapter() { public void mousePressed(java.awt.event.MouseEvent evt) { //DEBUG: System.out.println("Mouse click: ("+linha+","+coluna+")"); clicouCelula(CelulaGUI.this, evt); } }); } public void seleciona() { setBackground(new Color(190,190,210)); } public void deseleciona() { setBackground(Color.WHITE); } public void setNumero(int valor) { if (valor == 0 || valor == -1) { this.numero.setText(""); } else { this.numero.setText(""+valor); } } public void setGrauLiberdade(int valor) { this.grauLiberdade.setText(""+valor); } public void limpaGrauLiberdade() { this.grauLiberdade.setText(""); } public void setSugestao(int valor) { this.sugestao.setText(""+valor); setBackground(new Color(180,230,180)); } public void limpaSugestao() { this.sugestao.setText(""); setBackground(Color.WHITE); } public int getLinha() { return linha; } public int getColuna() { return coluna; } } }