-
Java
Jogo da Velha XML
Trabalho da Disciplina: Conceitos de XML
Christiny Goulart
Fabio Martins
Robson Martins
Prof. Ms. Marcos Macedo
MBA em Desenvolvimento de Aplicações Java - SOA / FIAP
09/01/2012
Download do código-fonte:
Jogo da Velha XML (ZIP ~3MB)
Tecnologias empregadas:
- XML e Validação Schema (XSD);
- Parser DOM;
- Sockets TCP (através do framework Apache Mina);
- Java Swing;
- Java2D API.
Enunciado:
O "Jogo da Velha" é um jogo de raciocínio projetado para versões em sistema desktop (PC Windows), internet e celulares.
Objetivo:
O objetivo ao desenvolver o "Jogo da Velha" é fornecer um jogo casual para entretenimento em curtos períodos de tempo, baseado no jogo da velha tradicional. O principal objetivo é realizar todas as jogadas entre 2 oponentes através do envio de XML entre máquinas, onde cada um pode desenvolver um Java Servlet ou Java Socket, tanto para receber o XML, criticar se alguém venceu, e devolver para os oponentes a configuração atual do tabuleiro. Como o foco da disciplina é o entendimento de XML, estaremos analisando os aspectos de uso, validações e controles. O grupo está livre para definir todo o contexto tecnológico, assim como os procedimentos de envio e recebimento de XML, e também da estrutura do XML.
Arquivos do Pacote ZIP:
ProjetosEclipse/
: Diretório que contém os projetos Java para Eclipse.ProjetosEclipse/
: Projeto Java para o Eclipse, contendo o Servidor de Sockets do Jogo da Velha.JogoDaVelhaServer.zip ProjetosEclipse/
: Projeto Java para o Eclipse, contendo um Cliente de Sockets do Jogo da Velha (aplicação com GUI em Swing).JogoDaVelhaClient.zip ProjetosEclipse/
: Projeto Java para o Eclipse, contendo um Robot do Jogo da Velha (aplicação com GUI em Swing). É semelhante ao Cliente, mas este permite o computador jogar contra outro jogador conectado ao Servidor (que poderá ser um "humano" ou outro "robot").JogoDaVelhaRobot.zip ProjetosEclipse/
: Projeto Java para o Eclipse, que contém casos de teste JUnit (4.0) usados durante o desenvolvimento, para testar as classesJogoDaVelhaTestsJUnit.zip VelhaEngine
eVelhaParser
. Não é necessário para a operação normal do jogo: somente incluímos este pacote por questões didáticas.ExemplosXML/
: Diretório que contém o arquivo velha.xsd (schema de validação do XML do Jogo da Velha) e alguns arquivos XML de exemplo.
Sobre a implementação:
Arquitetura da Solução
O "Jogo da Velha" utiliza transferência de arquivos XML por meio de sockets de rede.
A implementação de sockets TCP se baseia no framework Apache Mina (http://
O servidor de sockets ("Jogo da Velha Server") escuta em uma porta TCP (default: 9123), e espera pela conexão dos clientes.
A partida não inicia enquanto não houver exatamente dois clientes ("Jogo da Velha Client") conectados ao servidor.
A implementação do "Jogo da Velha Server" controla as sessões dos clientes conectados, impedindo que um terceiro jogador se conecte durante a partida (a conexão excedente é automaticamente derrubada).
O "Jogo da Velha Client" é uma aplicação cliente de sockets, com interface gráfica (GUI) escrita em Java Swing e Java2D, permitindo uma boa experiência de "jogabilidade" ao usuário.
Ainda há outro tipo de cliente, o "Jogo da Velha Robot", que é uma aplicação cliente de sockets, que se conecta a um servidor, permitindo o computador jogar.
Sendo assim, podem ser combinados Client's e Robot's em diferentes configurações, para alterar o tipo de partida:
- 2 Client’s ("humano" contra "humano")
- 1 Client e 1 Robot ("humano" contra "computador")
- 2 Robot’s ("computador" contra "computador")
Os arquivos XML que trafegam via sockets de rede são validados através de schema (XSD) e processados (parse) através do DOM.
A lógica que avalia o status do jogo e coordena o envio e recebimento dos arquivos XML, está implementada no servidor.
Formato do XML
O arquivo XML transmitido entre os clientes e o servidor segue um formato específico.
Abaixo há uma breve descrição dos principais elementos.
Identificação do Jogador:
<id>X</id>
Pode ser 'X' ou 'O'.
Representa qual é o jogador que está recebendo ou enviando o XML.
Status do Jogo:
<status>jogue</status>
O status do jogo pode ser um destes:
- "jogue" → é a vez do jogador definido pelo id
- "aguarde" → é a vez do outro jogador (oponente)
- "ganhou" → jogador definido pelo id ganhou
- "perdeu" → jogador definido pelo id perdeu (oponente ganhou)
- "empate" → houve empate ("deu velha")
- "wo" → jogador oponente abandonou jogo antes do final
Os status "ganhou", "perdeu", "empate" e "wo" são considerados como status de "game over".
Estado atual do tabuleiro:
<tabuleiro>
<p0></p0>
<p1></p1>
<p2></p2>
<p3></p3>
<p4></p4>
<p5></p5>
<p6></p6>
<p7></p7>
<p8></p8>
</tabuleiro>
p0..p8: Representam as posições no tabuleiro (de 0 a 8):
[0] [1] [2]
[3] [4] [5]
[6] [7] [8]
Os valores possíveis das posições são:
- 'X' (letra xis maiúsculo) → jogada do X
- 'O' (letra ó maiúsculo) → jogada do O
- ' ' (vazio ou espaço em branco) → posição vazia
Essa posição vazia, no XML, pode ser representada por uma tag vazia (sem conteúdo) ou por um caractere de espaço em branco.
Registro da posição jogada:
<jogada>4</jogada>
Indica em qual posição foi a jogada do Cliente (0 a 8). Essa tag pode ser vazia para sinalizar que não há jogada a ser registrada pelo jogador definido pelo id.
Arquivo XSD (schema):
O arquivo velha.xsd
define o formato esperado para o XML que trafega entre o servidor e os clientes, e é usado pelas aplicações para validar o conteúdo recebido.
Exemplos de XML
-
O servidor envia o XML ao cliente X:
<JogoDaVelha>
<id>X</id>
<status>jogue</status>
<jogada></jogada>
<tabuleiro>
<p0>X</p0>
<p1>O</p1>
<p2></p2>
<p3></p3>
<p4></p4>
<p5></p5>
<p6></p6>
<p7>O</p7>
<p8>X</p8>
</tabuleiro>
</JogoDaVelha>O tabuleiro desse jogador pode ser mostrado assim:
Jogador: X
Faça sua jogada:[X] [O] [ ]
[ ] [ ] [ ]
[ ] [O] [X]E, ao mesmo tempo, o servidor envia o XML ao cliente O:
<JogoDaVelha>
<id>O</id>
<status>aguarde</status>
<jogada></jogada>
<tabuleiro>
<p0>X</p0>
<p1>O</p1>
<p2></p2>
<p3></p3>
<p4></p4>
<p5></p5>
<p6></p6>
<p7>O</p7>
<p8>X</p8>
</tabuleiro>
</JogoDaVelha>O tabuleiro do jogador O pode ser mostrado assim:
Jogador: O
Aguarde a sua vez...[X] [O] [ ]
[ ] [ ] [ ]
[ ] [O] [X] -
O cliente X joga na posição 4, e envia esse XML para o servidor:
<JogoDaVelha>
<id>X</id>
<status>jogue</status>
<jogada>4</jogada>
<tabuleiro>
<p0>X</p0>
<p1>O</p1>
<p2></p2>
<p3></p3>
<p4></p4>
<p5></p5>
<p6></p6>
<p7>O</p7>
<p8>X</p8>
</tabuleiro>
</JogoDaVelha>O servidor confere o id (se é realmente o jogador X que está enviando o arquivo), se é a vez de jogar, se a posição 4 (em memória) está vazia, e então, grava a jogada.
O servidor ignora o tabuleiro enviado no XML: ele usa o que mantém internamente em memória (para evitar fraudes de um jogador que adultere o arquivo XML).
O servidor faz o parse, analisa se alguém ganhou e monta os dois XML's para os dois clientes.
O servidor envia o XML para o cliente X:
<JogoDaVelha>
<id>X</id>
<status>ganhou</status>
<jogada></jogada>
<tabuleiro>
<p0>X</p0>
<p1>O</p1>
<p2></p2>
<p3></p3>
<p4>X</p4>
<p5></p5>
<p6></p6>
<p7>O</p7>
<p8>X</p8>
</tabuleiro>
</JogoDaVelha>O tabuleiro do jogador X pode ser mostrado assim:
Jogador: X
Você Ganhou! Parabéns![X] [O] [ ]
[ ] [X] [ ]
[ ] [O] [X]O servidor envia o XML para o cliente O:
<JogoDaVelha>
<id>O</id>
<status>perdeu</status>
<jogada></jogada>
<tabuleiro>
<p0>X</p0>
<p1>O</p1>
<p2></p2>
<p3></p3>
<p4>X</p4>
<p5></p5>
<p6></p6>
<p7>O</p7>
<p8>X</p8>
</tabuleiro>
</JogoDaVelha>O tabuleiro do jogador O pode ser mostrado assim:
Jogador: O
Sinto muito, mas você perdeu!
Vá treinar mais![X] [O] [ ]
[ ] [X] [ ]
[ ] [O] [X]
Fluxo de Operação do Jogo da Velha
- Servidor inicializa e fica no ar escutando na porta TCP;
- Um Cliente (C1) conecta ao Servidor;
- O Servidor sorteia um ID (
JOGADOR_X
ouJOGADOR_O
) para o C1; - O Servidor envia um XML para o cliente (C1), com o ID, com o
STATUS_AGUARDE
e com o tabuleiro limpo; - Outro Cliente (C2) conecta ao Servidor;
- O Servidor envia um XML para o Cliente (C2), com o ID, com o
STATUS_AGUARDE
e com o tabuleiro limpo; - O Servidor sorteia quem vai começar o jogo (digamos que ele escolheu o Cliente C2);
- O Servidor envia para o Cliente C2 o XML com o
STATUS_JOGUE
; - O Cliente C2 recebe esse XML e libera o direito de jogada para esse jogador;
- O jogador faz a jogada e o Cliente C2 envia um XML para o Servidor:
JOGADA = <posição onde foi a jogada>
; - O Servidor valida e confere o XML enviado pelo Cliente C2: se o ID está certo, se a
JOGADA
é válida (de 0 a 8 e em posição correntemente marcada comoJOGADOR_VAZIO
) e se a vez da jogada corresponde ao Cliente C2; - O Servidor sempre ignora o tabuleiro escrito no XML enviado pelo cliente; ele usa o que está internamente armazenado (no objeto
VelhaEngine
); - Se a jogada for inválida, o Servidor repete o envio do XML (passo 8);
- Se a jogada for válida, o Servidor a registra no seu tabuleiro interno (no objeto
VelhaEngine
) e envia os XML's para os Clientes: - Cliente C2 recebe um XML com
STATUS_AGUARDE
e o novo tabuleiro; - Cliente C1 recebe um XML com
STATUS_JOGUE
e o novo tabuleiro; - Com isso, a vez da jogada vai para o Cliente C1.
- Todo o fluxo é repetido (passos 8 a 17), porém com os Clientes invertidos. O jogo pode acabar em uma das circunstâncias (game over):
VelhaEngine.isEmpate()
- Houve um empate. O Servidor envia os XML's para os dois Clientes, contendo oSTATUS_EMPATE
;VelhaEngine.isGanhador(JOGADOR_X)
- O jogador X ganhou. O Servidor envia para o Cliente cujoID == JOGADOR_X
o XML comSTATUS_GANHOU
, e para o outro Cliente o XML comSTATUS_PERDEU
;VelhaEngine.isGanhador(JOGADOR_O)
- O jogador O ganhou. O Servidor envia para o Cliente cujoID == JOGADOR_O
o XML comSTATUS_GANHOU
, e para o outro Cliente o XML comSTATUS_PERDEU
;- Um dos Clientes encerra a conexão no meio do jogo: Nesse caso, o Servidor envia para o Cliente que sobrou o XML com
STATUS_WO
. - Em qualquer caso de encerramento do jogo (citados nos passos 19 a 22), o Servidor encerra a conexão com os dois Clientes após o envio do último XML.
- Também, no encerramento do jogo, o Servidor limpa o tabuleiro contido no seu objeto
VelhaEngine
e o status do jogo encerrado. - Então, para iniciar uma nova partida, os Clientes têm que se reconectar ao Servidor, e tudo recomeça como no passo 2.
Descrição da Implementação Java
Classes comuns a todas as aplicações
br.com.fiap.velha
VelhaEngine.java
: Contém a lógica do Jogo da Velha, usada pelo Servidor para avaliar o status e gerenciar a dinâmica do jogo. Também contém métodos usados pelo "Robot do Jogo da Velha" para analisar o jogo, e escolher as melhores jogadas de forma automatizada. .
VelhaBean.java
: Bean (POJO) que representa o XML do Jogo da Velha.
VelhaParser.java
: Implementa um Parser baseado em DOM, capaz de transformar um objeto VelhaBean
em uma String contendo XML, e vice-versa.
Essa classe possui uma flag DEBUG_ENABLED
que pode ser colocada em true para exibir mensagens de depuração (default: false).
Classes do "Jogo da Velha Server":
br.com.fiap.velha.server
VelhaServer.java
: Contém o método principal main() que inicia o Servidor do Jogo da Velha.
VelhaServerHandler.java
: Contém a implementação do manipulador de sockets das conexões dos Clientes. Implementa toda a dinâmica do jogo, o gerenciamento de sessões e avalia o status do jogo, enviando e recebendo mensagens XML de / para os Clientes.
Essa classe possui uma flag DEBUG_ENABLED
que pode ser colocada em true para exibir mensagens de depuração (default: true).
Classes do "Jogo da Velha Client":
br.com.fiap.velha.client
VelhaClient.java
: Contém o método principal main() que inicia o Cliente do Jogo da Velha. Também possui métodos callback que são executados quando ocorre algum evento de GUI (como um clique) ou de socket (como o recebimento de uma mensagem).
VelhaHandler.java
: Contém a implementação do manipulador de sockets do Cliente. Responsável por chamar os métodos callback da classe VelhaClient
quando algum evento de socket ocorre.
Essa classe possui uma flag DEBUG_ENABLED
que pode ser colocada em true para exibir mensagens de depuração (default: false).
br.com.fiap.velha.gui
VelhaPanel.java
: Contém a implementação necessária para desenhar um tabuleiro de Jogo da Velha (usando Java2D) em um JPanel (componente "painel" do Swing), e converter coordenadas de tela (X,Y) para posições relativas do tabuleiro (0 a 8). Também chama um método callback da classe VelhaClient
quando algum clique no painel ocorre.
VelhaGUI.java
: Responsável por montar a GUI da aplicação, em Swing, contendo o VelhaPanel
e os controles de tela. Também chama um método callback da classe VelhaClient
quando um clique em algum controle ocorre.
VelhaListener.java
: Interface que define quais métodos callback a classe VelhaClient
deve implementar.
Classes do "Robot do Jogo da Velha":
br.com.fiap.velha.client
VelhaRobot.java
: Contém o método principal main() que inicia o Robot do Jogo da Velha. Também possui métodos callback que são executados quando ocorre algum evento de GUI (como um clique) ou de socket (como o recebimento de uma mensagem).
VelhaHandler.java
: Idêntica à classe VelhaHandler
do "Cliente do Jogo da Velha".
br.com.fiap.velha.gui
VelhaPanel.java
: Idêntica à classe VelhaPanel
do "Cliente do Jogo da Velha".
VelhaRobotGUI.java
: Responsável por montar a GUI da aplicação, em Swing, contendo o VelhaPanel
e os controles de tela. Também chama um método callback da classe VelhaRobot
quando um clique em algum controle ocorre.
VelhaListener.java
: Idêntica à interface VelhaListener
do "Cliente do Jogo da Velha".
Instruções para funcionamento das aplicações
As instruções a seguir pressupõem que os projetos serão executados a partir do Eclipse:
- Importar os projetos nos arquivos
JogoDaVelhaServer.zip
,JogoDaVelhaClient.zip
eJogoDaVelhaRobot.zip
, para um Workspace do Eclipse. - Executar a aplicação do Servidor (
JogoDaVelhaServer
), através da classeVelhaServer
do pacote "br.com.fiap.velha.server
". O Servidor do Jogo da Velha estará então ouvindo na porta TCP 9123 (default). - Abrir uma nova visualização de Console no Eclipse (se estiver no mesmo computador do servidor), e executar a aplicação Cliente (
JogoDaVelhaClient
), através da classeVelhaClient
do pacote "br.com.fiap.velha.client
". - Abrir outra visualização de Console no Eclipse (se estiver no mesmo computador do servidor), e executar mais uma instância da aplicação Cliente (
JogoDaVelhaClient
). - Nos Clientes, digitar o nome do host (ou endereço IP) do servidor (default: localhost) e a porta TCP (default: 9123) e clicar em "Conectar" para iniciar uma partida.
- Para jogar, deve-se clicar nas posições vazias do tabuleiro (na sua vez de jogar), para marcar a jogada.
- Para sair do jogo sem que ele esteja terminado, deve-se clicar em "Abortar".
- É possível conectar um ou dois Robot’s a um Servidor de Jogo da Velha, executando a aplicação
JogoDaVelhaRobotClient
através da classeVelhaRobot
do pacote "br.com.fiap.velha.client
".
O Robot é semelhante ao Cliente, porém ele não permite cliques no tabuleiro, e se auto reconecta ao Servidor do Jogo da Velha quando uma partida é finalizada. Além disso, o Robot permite especificar um "nível de inteligência de defesa" (de 0 a 10): quanto menor esse nível, mais aleatórias serão as jogadas de defesa desse Robot.