Jogo da Velha [Treinando Swing e AWT]

Então galera, como sou desenvolvedor Java Web, estava uns 2 anos sem brincar com Swing e AWT. Então hoje em meu horário de almoço resolvi relembrar meus velhos tempos. Vou disponibilizar o código fonte e o jar pra galera jogar ou pra quem está começando a estudar Java, visualizar uma implementação simples, podendo modificá-la, melhorando o código, criando novas funcionalidades, etc.

OBS: Criei tudo em uma classe só, o importante era criar uma camada de visão, uma de controle e um modelo. Entretanto, só tinha o horário de almoço de hoje, aí fiz rapidão hehe. Sem falar que tinha como melhorar bastante o código, raciocínio, reutilização, mas como disse, foi só um treino de Swing e AWT.

package br.com.jogo_da_velha;

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;

/** 
 * -------------JOGO DA VELHA-------------
 *  Desenvolvido por Ronnie Mikihiro Sato Lopes,
 *  que é Bacharel em Sistemas de Informação pela UniEvangélica,
 *  e atualmente trabalha como Desenvolvedor Java Pleno na Indra Sistemas.
 * 
 * @date 10/04/2015 - 08:57:44
 * @author ronnie-msl
 */
public class JogoDaVelha extends JFrame {

	private static final long serialVersionUID = 1L;
	
	private JPanel contentPane;
	private JLabel lblRodada;
	private JLabel lblVez;
	private String[][] tab;
	private int rodada;
	private Character vez;
	private boolean ganhou;
	
	private int qtdVitoriasJogX;
	private int qtdVitoriasJogO;
	
	private JButton btn1;
	private JButton btn2;
	private JButton btn3;
	private JButton btn4;
	private JButton btn5;
	private JButton btn6;
	private JButton btn7;
	private JButton btn8;
	private JButton btn9;
	private JMenu mnSobre;
	private JLabel lblVitoriasJogX;
	private JLabel lblVitoriasJogO;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					JogoDaVelha frame = new JogoDaVelha();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Classe construtora que monta a tela, botões e menu.
	 */
	public JogoDaVelha() {
		setTitle("Jogo da Velha");
		setResizable(false);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 555, 678);
		
		JMenuBar menuBar = new JMenuBar();
		setJMenuBar(menuBar);
		
		mnSobre = new JMenu("Sobre");
		mnSobre.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				JOptionPane.showMessageDialog(null, 
						"	Desenvolvido por: Ronnie Mikihiro Sato Lopes em 10/04/2015\n"
						+ "	Programador Java Pleno na Indra Sistemas\n"
						+ "	Bacharel em Sistemas de Informação - UniEvangélica", 
						"Sobre", JOptionPane.INFORMATION_MESSAGE);
			}
		});
		menuBar.add(mnSobre);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(null);
		
		btn1 = new JButton("");
		btn1.setFont(new Font("MV Boli", Font.PLAIN, 11));
		btn1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				jogar(btn1, 1);
			}
		});
		btn1.setBounds(0, 149, 183, 160);
		contentPane.add(btn1);
		
		btn2 = new JButton("");
		btn2.setFont(new Font("MV Boli", Font.PLAIN, 11));
		btn2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				jogar(btn2, 2);
			}
		});
		btn2.setBounds(183, 149, 183, 160);
		contentPane.add(btn2);
		
		btn3 = new JButton("");
		btn3.setFont(new Font("MV Boli", Font.PLAIN, 11));
		btn3.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				jogar(btn3, 3);
			}
		});
		btn3.setBounds(366, 149, 183, 160);
		contentPane.add(btn3);
		
		btn4 = new JButton("");
		btn4.setFont(new Font("MV Boli", Font.PLAIN, 11));
		btn4.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				jogar(btn4, 4);
			}
		});
		btn4.setBounds(0, 309, 183, 160);
		contentPane.add(btn4);
		
		btn5 = new JButton("");
		btn5.setFont(new Font("MV Boli", Font.PLAIN, 11));
		btn5.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				jogar(btn5, 5);
			}
		});
		btn5.setBounds(183, 309, 183, 160);
		contentPane.add(btn5);
		
		btn6 = new JButton("");
		btn6.setFont(new Font("MV Boli", Font.PLAIN, 11));
		btn6.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				jogar(btn6, 6);
			}
		});
		btn6.setBounds(366, 309, 183, 160);
		contentPane.add(btn6);
		
		btn7 = new JButton("");
		btn7.setFont(new Font("MV Boli", Font.PLAIN, 11));
		btn7.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				jogar(btn7, 7);
			}
		});
		btn7.setBounds(0, 469, 183, 160);
		contentPane.add(btn7);
		
		btn8 = new JButton("");
		btn8.setFont(new Font("MV Boli", Font.PLAIN, 11));
		btn8.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				jogar(btn8, 8);
			}
		});
		btn8.setBounds(183, 469, 183, 160);
		contentPane.add(btn8);
		
		btn9 = new JButton("");
		btn9.setFont(new Font("MV Boli", Font.PLAIN, 11));
		btn9.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				jogar(btn9, 9);
			}
		});
		btn9.setBounds(366, 469, 183, 160);
		contentPane.add(btn9);
		
		lblRodada = new JLabel("");
		lblRodada.setForeground(new Color(0, 0, 0));
		lblRodada.setHorizontalAlignment(SwingConstants.CENTER);
		lblRodada.setFont(new Font("MV Boli", Font.BOLD, 15));
		lblRodada.setBounds(0, 11, 549, 14);
		contentPane.add(lblRodada);
		
		lblVez = new JLabel("");
		lblVez.setHorizontalAlignment(SwingConstants.CENTER);
		lblVez.setForeground(Color.BLACK);
		lblVez.setFont(new Font("MV Boli", Font.BOLD, 15));
		lblVez.setBounds(0, 46, 549, 14);
		contentPane.add(lblVez);
		
		lblVitoriasJogX = new JLabel("<html>Jogador <font color=red>X</font> : 0 vit\u00F3ria(s).</html>");
		lblVitoriasJogX.setHorizontalAlignment(SwingConstants.CENTER);
		lblVitoriasJogX.setForeground(Color.BLACK);
		lblVitoriasJogX.setFont(new Font("MV Boli", Font.BOLD, 15));
		lblVitoriasJogX.setBounds(0, 99, 275, 14);
		contentPane.add(lblVitoriasJogX);
		
		lblVitoriasJogO = new JLabel("<html>Jogador <font color=blue>O</font> : 0 vit\u00F3ria(s).</html>");
		lblVitoriasJogO.setHorizontalAlignment(SwingConstants.CENTER);
		lblVitoriasJogO.setForeground(Color.BLACK);
		lblVitoriasJogO.setFont(new Font("MV Boli", Font.BOLD, 15));
		lblVitoriasJogO.setBounds(274, 99, 275, 14);
		contentPane.add(lblVitoriasJogO);
		
		iniciarAtributos();
	}
	
	/**
	 * <p> Método responsável por criar um novo jogo. <p>
	 *
	 * @date 10/04/2015 - 13:28:06
	 * @author ronnie-msl
	 */
	public void novoJogo() {
		btn1.setText("");
		btn1.setBackground(null);
		btn2.setText("");
		btn2.setBackground(null);
		btn3.setText("");
		btn3.setBackground(null);
		btn4.setText("");
		btn4.setBackground(null);
		btn5.setText("");
		btn5.setBackground(null);
		btn6.setText("");
		btn6.setBackground(null);
		btn7.setText("");
		btn7.setBackground(null);
		btn8.setText("");
		btn8.setBackground(null);
		btn9.setText("");
		btn9.setBackground(null);
		
		iniciarAtributos();
	}
	
	/**
	 * <p> Método responsável por iniciar os atributos do jogo. <p>
	 *
	 * @date 10/04/2015 - 13:28:15
	 * @author ronnie-msl
	 */
	public void iniciarAtributos() {
		tab = new String[3][3];
		for (int l = 0; l < 3; l++) {
			for (int c = 0; c < 3; c++) {
				tab[l][c] = "";
			}
		}
		
		ganhou = false;
		rodada = 1;
		vez = 'X';
		
		lblRodada.setText("Rodada "+ rodada);
		lblVez.setText("<html>É a vez do Jogador <font color=red>"+ vez + "</font></html>");
	}
	
	/**
	 * <p> Método responsável por realizar a alteração da rodada e do jogador. <p>
	 *
	 * @date 10/04/2015 - 13:28:31
	 * @author ronnie-msl
	 */
	public void alterarRodadaEVezJogador() {
		rodada++;
		vez = vez == 'X' ? 'O' : 'X';
		
		lblRodada.setText("Rodada "+ rodada);
		lblVez.setText("<html>É a vez do Jogador <font color="+(vez == 'X' ? "red" : "blue") + ">" + vez +"</font></html>");
	}
	
	/**
	 * <p> Método responsável por realizar chamar todos os métodos de realização da jogada,
	 * como setar na matriz qual foi a posição jogada, tipo de símbolo jogada, cor do símbolo,
	 * verificar se algum jogador ganhou, etc.  <p>
	 *
	 * @param btnClicado
	 * @param numBtnClicado
	 * @date 10/04/2015 - 13:28:41
	 * @author ronnie-msl
	 */
	public void jogar(JButton btnClicado, final int numBtnClicado) {
		boolean posicaoJaJogada = false;
		final String simbolo = vez.toString();
		
		switch (numBtnClicado) {
			case 1: if(!isVazio(tab[0][0])) {posicaoJaJogada = true;} else {tab[0][0] = simbolo;} break;
			case 2: if(!isVazio(tab[0][1])) {posicaoJaJogada = true;} else {tab[0][1] = simbolo;} break;
			case 3: if(!isVazio(tab[0][2])) {posicaoJaJogada = true;} else {tab[0][2] = simbolo;} break;
			case 4: if(!isVazio(tab[1][0])) {posicaoJaJogada = true;} else {tab[1][0] = simbolo;} break;
			case 5: if(!isVazio(tab[1][1])) {posicaoJaJogada = true;} else {tab[1][1] = simbolo;} break;
			case 6: if(!isVazio(tab[1][2])) {posicaoJaJogada = true;} else {tab[1][2] = simbolo;} break;
			case 7: if(!isVazio(tab[2][0])) {posicaoJaJogada = true;} else {tab[2][0] = simbolo;} break;
			case 8: if(!isVazio(tab[2][1])) {posicaoJaJogada = true;} else {tab[2][1] = simbolo;} break;
			case 9: if(!isVazio(tab[2][2])) {posicaoJaJogada = true;} else {tab[2][2] = simbolo;} break;
			
			default: break;
		}
		
		if(!posicaoJaJogada) {
			btnClicado.setText(simbolo); //seta o texto de símbolo, X ou O
			btnClicado.setFont(new Font("MV Boli",Font.BOLD, 120));
			btnClicado.setForeground(vez == 'X' ? Color.RED : Color.BLUE);
			btnClicado.setFocusPainted(false);
			
			verificarSeGanhou();
			
			if(ganhou) {

				if(vez == 'X') {
					qtdVitoriasJogX++;
					lblVitoriasJogX.setText("<html>Jogador <font color=red>X</font> : " + qtdVitoriasJogX + " vit\u00F3ria(s).</html>");
				} else {
					qtdVitoriasJogO++;
					lblVitoriasJogO.setText("<html>Jogador <font color=blue>O</font> : " + qtdVitoriasJogO + " vit\u00F3ria(s).</html>");
				}
				
				int escolha = JOptionPane.showConfirmDialog(this, "O Jogador " + vez 
						+ " ganhou!!!\n\n Deseja jogar outra partida? ", "Fim de jogo!", JOptionPane.YES_NO_OPTION);
				
				if(escolha == JOptionPane.YES_OPTION) {
					novoJogo();
				} else {
					System.exit(0);
				}
				
			} else {
				if(rodada == 9) {
					int escolha = JOptionPane.showConfirmDialog(this, "Deu velha!!!\n\n Deseja jogar outra partida? ", 
							"Fim de jogo!", JOptionPane.YES_NO_OPTION);
					
					if(escolha == JOptionPane.YES_OPTION) {
						novoJogo();
					} else {
						System.exit(0);
					}
					
				} else {
					alterarRodadaEVezJogador();
				}
			}
		}
	}
	
	/**
	 * <p> Método responsável por verificar se depois da última jogada, algum jogador ganhou. <p>
	 *
	 * @date 10/04/2015 - 13:29:16
	 * @author ronnie-msl
	 */
	public void verificarSeGanhou() {
		//Verifica se ganhou pelas linhas.
		if(!isVazio(tab[0][0]) && tab[0][0].equals(tab[0][1]) && tab[0][1].equals(tab[0][2])) {
			ganhou = true;
			btn1.setBackground(Color.GREEN);
			btn2.setBackground(Color.GREEN);
			btn3.setBackground(Color.GREEN);
		} else if (!isVazio(tab[1][0]) && tab[1][0].equals(tab[1][1]) && tab[1][1].equals(tab[1][2])) {
			ganhou = true;
			btn4.setBackground(Color.GREEN);
			btn5.setBackground(Color.GREEN);
			btn6.setBackground(Color.GREEN);
		} else if (!isVazio(tab[2][0]) && tab[2][0].equals(tab[2][1]) && tab[2][1].equals(tab[2][2])) {
			btn7.setBackground(Color.GREEN);
			btn8.setBackground(Color.GREEN);
			btn9.setBackground(Color.GREEN);
			ganhou = true;
		
		//Verifica se ganhou pelas colunas.
		} else if (!isVazio(tab[0][0]) && tab[0][0].equals(tab[1][0]) && tab[1][0].equals(tab[2][0])) {
			ganhou = true;
			btn1.setBackground(Color.GREEN);
			btn4.setBackground(Color.GREEN);
			btn7.setBackground(Color.GREEN);
		} else if (!isVazio(tab[0][1]) && tab[0][1].equals(tab[1][1]) && tab[1][1].equals(tab[2][1])) {
			ganhou = true;
			btn2.setBackground(Color.GREEN);
			btn5.setBackground(Color.GREEN);
			btn8.setBackground(Color.GREEN);
		} else if (!isVazio(tab[0][2]) && tab[0][2].equals(tab[1][2]) && tab[1][2].equals(tab[2][2])) {
			ganhou = true;
			btn3.setBackground(Color.GREEN);
			btn6.setBackground(Color.GREEN);
			btn9.setBackground(Color.GREEN);
		
		//Verifica se ganhou pelas diagonais.
		} else if (!isVazio(tab[0][0]) && tab[0][0].equals(tab[1][1]) && tab[1][1].equals(tab[2][2])) {
			ganhou = true;
			btn1.setBackground(Color.GREEN);
			btn5.setBackground(Color.GREEN);
			btn9.setBackground(Color.GREEN);
		} else if (!isVazio(tab[0][2]) && tab[0][2].equals(tab[1][1]) && tab[1][1].equals(tab[2][0])) {
			ganhou = true;
			btn3.setBackground(Color.GREEN);
			btn5.setBackground(Color.GREEN);
			btn7.setBackground(Color.GREEN);
		}
	}
	
	/**
	 * <p> Método responsável por verificar se a string passada por parâmetro encontra-se nula ou vazia. <p>
	 *
	 * @param string
	 * @return true se string for vazia
	 * @date 10/04/2015 - 13:29:37
	 * @author ronnie-msl
	 */
	private boolean isVazio(final String string) {
		return string == null || string.isEmpty();
	}
}

Download JAR (Executável) ----> https://www.sendspace.com/file/trwzmk