Programação avançada – capitulo 8 – maquina de estados, exemplo3
Exemplo de uma maquina de estado, usando como referência a implementação de um jogo de 3×3, onde existem dois jogadores.
O diagrama da maquina de estados dado:
Outra versão do diagrama da maquina de estados:
package me_jogopecas; import me_jogopecas.iu.texto.IUTexto; import me_jogopecas.logica.estados.JogoMaquinaEstados; public class Me_jogoPecas { public static void main(String[] args) { IUTexto iuTexto = new IUTexto(new JogoMaquinaEstados()); iuTexto.corre(); } }
package me_jogopecas.iu.texto; import java.util.Scanner; import me_jogopecas.logica.estados.*; public class IUTexto { private JogoMaquinaEstados jogo; private boolean sair = false; public IUTexto(JogoMaquinaEstados jogo) { this.jogo = jogo; } void iuAguardaInicio() { if ((jogo.getJogador1() != null && jogo.getJogador1().isGanhou())) { System.out.println("\n" + jogo.getJogador1() + "\n" + jogo.grelhaToString()); } else if (jogo.getJogador2() != null && jogo.getJogador2().isGanhou()) { System.out.println("\n" + jogo.getJogador2() + "\n" + jogo.grelhaToString()); } System.out.println("\n=== AGUARDA INICIO ===\n" + (jogo.getJogador1() != null ? "" + jogo.getJogador1() : "") + (jogo.getJogador2() != null ? "" + jogo.getJogador2() : "")); while (true) { System.out.println("\n0 - Sair\n1 - Define nome de jogador\n2 - Comecar jogo\n3 - Ler jogo"); char c = ' '; Scanner sc = new Scanner(System.in); c = sc.next().charAt(0); if ((c == '0')) { sair = true; return; } if ((c == '1')) { //1 - Define nome de jogador System.out.println("Numero (1 ou 2) e nome do jogador: "); while (!sc.hasNextInt()); int num = sc.nextInt(); System.out.println(" numero: " + num); String nome = sc.next(); jogo.defineNomeJogador(num, nome); System.out.println(" nome: " + nome); return; } if ((c == '2')) { //2 - Comecar jogo System.out.println("Comecar jogo: "); jogo.comecarJogo(); return; } if ((c == '3')) { //3 - Ler o jogo System.out.println("Ler o jogo: "); String ficheiroLer = sc.next(); // jogo.ler(ficheiroLer); return; } } } void iuAguardaColocacao() { System.out.println("\n=== AGUARDA COLOCACAO === \n" + jogo.getJogador1() + jogo.getJogador2() + "\nJogador activo: " + jogo.getNomeJogadorActivo() + "\n" + jogo.grelhaToString()); System.out.println("\n1 - Jogar : linha coluna\n2 - Abandonar"); char c = ' '; Scanner sc = new Scanner(System.in); c = sc.next().charAt(0); if ((c == '1')) { System.out.print(jogo.getNomeJogadorActivo() + ">"); while (!sc.hasNextInt()); int linha = sc.nextInt(); while (!sc.hasNextInt()); int coluna = sc.nextInt(); jogo.jogar(jogo.getNumJogadorActivo(), linha, coluna); } if ((c == '2')) { System.out.println("Guardar o jogo: "); String ficheiroGuardar = sc.next(); // jogo.grava(ficheiroGuardar); jogo.abandonar(jogo.getNumJogadorActivo()); return; } } void iuAguardaDevolucao() { System.out.println("\n=== AGUARDA DEVOLUCAO === \n" + jogo.getJogador1() + jogo.getJogador2() + "\nJogador activo: " + jogo.getNomeJogadorActivo() + "\n" + jogo.grelhaToString()); // System.out.println("\nDevolver : linha coluna\nAbandonar: -1"); System.out.println("\n1 - Devolver : linha coluna\n2 - Abandonar"); char c = ' '; Scanner sc = new Scanner(System.in); c = sc.next().charAt(0); if ((c == '1')) { System.out.print(jogo.getNomeJogadorActivo() + ">"); while (!sc.hasNextInt()); int linha = sc.nextInt(); while (!sc.hasNextInt()); int coluna = sc.nextInt(); jogo.devolver(jogo.getNumJogadorActivo(), linha, coluna); } if ((c == '2')) { jogo.abandonar(jogo.getNumJogadorActivo()); return; } } public void corre() { while (!sair) { IEstado estado = jogo.getEstado(); if (estado instanceof AguardaInicio) { iuAguardaInicio(); } else if (estado instanceof AguardaColocacao) { iuAguardaColocacao(); } else if (estado instanceof AguardaDevolucao) { iuAguardaDevolucao(); } } } }
package me_jogopecas.logica; public interface Constantes { int DIM =3; }
package me_jogopecas.logica; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import static me_jogopecas.logica.Constantes.*; public class Jogador implements Constantes, Serializable{ private String nome; private JogoDados jogo; //lista de peças no inicio private List<Peca> mao = new ArrayList<Peca>(); private boolean ganhou; public Jogador(String nome, JogoDados j) { this.nome = nome; this.jogo = j; ganhou = false; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public JogoDados getJogo() { return jogo; } public void setJogo(JogoDados jogo) { this.jogo = jogo; } public List<Peca> getMao() { return mao; } public void setMao(List<Peca> mao) { this.mao = mao; } public boolean isGanhou() { return ganhou; } public void setGanhou(boolean ganhou) { this.ganhou = ganhou; } //quando começar o jogo! public void recebePecas() { mao.clear(); for (int i = 0; i < DIM; i++) { mao.add(new Peca(this)); } ganhou = false; } public int getNumPecas(){ return mao.size(); } //quando a peça é devolvida public void recebePeca(Peca peca) { mao.add(new Peca(this)); } public boolean temPecas() { return mao.size() > 0; } public boolean jogar(int linha, int coluna){ if(mao.size()==0){ return false; } //as peças são todas iguais Peca peca = mao.get(0); if(jogo.setPeca(peca, linha, coluna)){ //jogou mao.remove(0); if(jogo.ganhou(this)){ ganhou = true; } return true; } return false; } @Override public String toString() { return "Jogador " + nome + " mao=" + mao + (ganhou ? " == GANHOU ==" : "") + "\n" ; } }
package me_jogopecas.logica; import java.io.Serializable; import java.util.ArrayList; import java.util.List; public class JogoDados implements Constantes, Serializable { private List<Jogador> jogadores = new ArrayList<Jogador>(); private int numJoActivo; private Peca[][] grelha; public JogoDados() { jogadores.add(new Jogador("A", this)); jogadores.add(new Jogador("B", this)); grelha = new Peca[DIM][DIM]; } public Jogador getJogadorActivo() { //considera-se que o jogador activo é 1 ou 2, daí o -1 return jogadores.get(numJoActivo - 1); } public String getNomeJogadorActivo() { return jogadores.get(numJoActivo - 1).getNome(); } public Jogador getJogadorNaoActivo() { if (numJoActivo == 1) { return jogadores.get(1); } else if (numJoActivo == 2) { return jogadores.get(0); } return null; } public int getNumJogadorActivo() { return numJoActivo; } public int getNumJogadorNaoActivo() { return (numJoActivo == 1 ? 1 : 2); } public Jogador getJogador1() { return jogadores.get(0); } public Jogador getJogador2() { return jogadores.get(1); } public Peca getPeca(int linha, int coluna) { if (linha < 0 || linha >= DIM || coluna < 0 || coluna >= DIM) { return null; } if (grelha == null) { return null; } return grelha[linha][coluna]; } public boolean setPeca(Peca peca, int linha, int coluna) { if (linha < 0 || linha >= DIM || coluna < 0 || coluna >= DIM) { return false; } if (grelha[linha][coluna] != null) { return false; } grelha[linha][coluna] = peca; return true; } public boolean retiraPeca(int linha, int coluna) { if (linha < 0 || linha >= DIM || coluna < 0 || coluna >= DIM) { return false; } if (grelha[linha][coluna] == null) { return false; } grelha[linha][coluna] = null; return true; } public void jogaOutro() { numJoActivo = numJoActivo == 1 ? 2 : 1; } public boolean inicializa() { grelha = new Peca[DIM][DIM]; jogadores.get(0).recebePecas(); jogadores.get(1).recebePecas(); numJoActivo = 1; return true; } public boolean setNomeJogador(int num, String nome) { //falta validar se o num é válido try { //tento aceder a um elemento do array que nao existe jogadores.get(num - 1).setNome(nome); return true; } catch (IndexOutOfBoundsException e) { return false; } } private boolean isEmDiagonalPrincipal(Jogador jogador) { for (int i = 0; i < DIM; i++) { if (grelha[i][i] == null || grelha[i][i].getJogador() != jogador) { return false; } } return true; } private boolean isEmDiagonalSecundaria(Jogador jogador) { for (int i = 0; i < DIM; i++) { if (grelha[i][DIM - 1 - i] == null || grelha[i][DIM - 1 - i].getJogador() != jogador) { return false; } } return true; } private boolean isEmDiagonal(Jogador jogador) { return isEmDiagonalPrincipal(jogador) || isEmDiagonalSecundaria(jogador); } private boolean isEmHorizontal(Jogador jogador, int linha) { for (Peca peca : grelha[linha]) { if (peca == null || peca.getJogador() != jogador) { return false; } } return true; } private boolean isEmVertical(Jogador jogador, int coluna) { for (int i = 0; i < grelha[coluna].length; i++) { Peca peca = grelha[i][coluna]; if (peca == null || peca.getJogador() != jogador) { return false; } } return true; } private boolean isEmHorizontal(Jogador jogador) { for (int i = 0; i < DIM; i++) { if (isEmHorizontal(jogador, i)) { return true; } } return false; } private boolean isEmVertical(Jogador jogador) { for (int i = 0; i < DIM; i++) { if (isEmVertical(jogador, i)) { return true; } } return false; } public boolean ganhou(Jogador jogador) { return isEmHorizontal(jogador) || isEmDiagonal(jogador) || isEmVertical(jogador); } public boolean jogar(int numeroJogador, int linha, int coluna) { if (linha < 0 || linha >= DIM || coluna < 0 || coluna >= DIM) { return false; } if (numJoActivo != numeroJogador) { return false; } Jogador j = getJogadorActivo(); if (!j.jogar(linha, coluna)) { return false; } return true; } public boolean devolver(int numeroJogador, int linha, int coluna) { if (linha < 0 || linha >= DIM || coluna < 0 || coluna >= DIM) { return false; } if (numJoActivo != numeroJogador) { return false; } Peca peca = getPeca(linha, coluna); Jogador j = getJogadorActivo(); if (peca == null || peca.getJogador() != j) { return false; } if (!retiraPeca(linha, coluna)) { return false; } j.recebePeca(peca); return true; } public String grelhaToString() { String s = ""; for (int i = 0; i < DIM; i++) { for (int j = 0; j < DIM; j++) { String casa; if (grelha[i][j] != null) { casa = "" + grelha[i][j].getJogador().getNome().charAt(0); } else { casa = " "; } s += "|\t" + casa + "\t"; } s += "|\n"; } return s; } public boolean acabou() { return ganhou(jogadores.get(0)) || ganhou(jogadores.get(1)); } }
package me_jogopecas.logica; import java.io.Serializable; public class Peca implements Serializable { private Jogador jogador; public Peca(Jogador jgd) { this.jogador = jgd; } public Jogador getJogador() { return jogador; } public void setJogador(Jogador jogador) { this.jogador = jogador; } @Override public String toString() { return "" + jogador.getNome().charAt(0); } }
package me_jogopecas.logica.estados; import me_jogopecas.logica.JogoDados; public class AguardaColocacao extends EstadoAdapter { //para informação adicional int l, c; public AguardaColocacao(JogoDados jogodados) { super(jogodados); //para informação adicional l = c = -1; //se vier return this } //para informação adicional public AguardaColocacao(JogoDados jogo, int l, int c) { super(jogo); this.l = l; this.c = c; } //setas de saida @Override public IEstado abandona(int numeroJogador) { //podiamos atribuir a vitoria a um jogador, olhando para numeroJogador //voltamos ao inicio return new AguardaInicio(jogodados); } @Override public IEstado joga(int numeroJogador, int linha, int coluna) { //informação adicional if (linha == l && coluna == c) { return this; } //jogar normal, o jogar faz o teste se pode ou nao jogar jogodados.jogar(numeroJogador, linha, coluna); //verificar se o jogador activo if (jogodados.getJogadorActivo().isGanhou()) { return new AguardaInicio(jogodados); } jogodados.jogaOutro(); //jogar a um jogador que não tem peças //jogar que nao tem pecas if (jogodados.getJogadorActivo().temPecas()) { //return this; //tb funciona //para informação adicional return new AguardaColocacao(jogodados); } return new AguardaDevolucao(jogodados); } }
package me_jogopecas.logica.estados; import me_jogopecas.logica.JogoDados; public class AguardaDevolucao extends EstadoAdapter { public AguardaDevolucao(JogoDados jogodados) { super(jogodados); } @Override public IEstado abandona(int numeroJogador) { return new AguardaInicio(jogodados); } @Override public IEstado devolve(int numeroJogador, int linha, int coluna) { if (jogodados.devolver(numeroJogador, linha, coluna)) { //return new AguardaColocacao(jogodados); //informação adicional return new AguardaColocacao(jogodados, linha, coluna); } return this; } }
package me_jogopecas.logica.estados; import me_jogopecas.logica.JogoDados; public class AguardaInicio extends EstadoAdapter { //construtor que redireciona para a classe base public AguardaInicio(JogoDados jogodados) { super(jogodados); } //setas de saida, os outros não fazem sentido @Override public IEstado defineNomeJogador(int numeroJogador, String nome) { //qual o novo estado depois de defineNomeJogador //agora vou atuar sobre o jogo jogodados.setNomeJogador(numeroJogador, nome); return this; //fico no mesmo estado } @Override public IEstado comecaJogo() { //testes para verificar se já tinhamos os dois jogadores if(jogodados.getJogador1()==null || jogodados.getJogador2()==null){ return this; } jogodados.inicializa(); return new AguardaColocacao(jogodados); } }
package me_jogopecas.logica.estados; import java.io.Serializable; import me_jogopecas.logica.JogoDados; //abstract para nao ser instanciada public abstract class EstadoAdapter implements IEstado, Serializable{ JogoDados jogodados;//tem que ter acesso aos dados de jogo //podemos colocar como protected, para ser usado apenas nas classes derivadas public EstadoAdapter(JogoDados jogod) { this.jogodados = jogod; } public JogoDados getJogodados() { return jogodados; } public void setJogodados(JogoDados jogodados) { this.jogodados = jogodados; } @Override public IEstado defineNomeJogador(int numeroJogador, String nome) { return this; } @Override public IEstado comecaJogo() { return this; } @Override public IEstado joga(int numeroJogador, int linha, int coluna) { return this; } @Override public IEstado devolve(int numeroJogador, int linha, int coluna) { return this; } @Override public IEstado abandona(int numeroJogador) { return this; } //o interface precisa de ir buscar coisas para as mostrar }
package me_jogopecas.logica.estados; public interface IEstado { //definir todas as acções o jogo IEstado defineNomeJogador(int numeroJogador, String nome); IEstado comecaJogo(); IEstado joga(int numeroJogador, int linha, int coluna); IEstado devolve(int numeroJogador, int linha, int coluna); IEstado abandona(int numeroJogador); }
package me_jogopecas.logica.estados; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import me_jogopecas.logica.Jogador; import me_jogopecas.logica.JogoDados; public class JogoMaquinaEstados implements Serializable { //se JogoMaquinaEstados é Serializable as classes de base tb têm que ser JogoDados jogodados; IEstado estado; public JogoMaquinaEstados() { //criar o meu jogo this.jogodados = new JogoDados(); //desenvolver, evoluir, programação dos estados (do diagrama) this.estado = new AguardaInicio(jogodados); } public IEstado getEstado() { return estado; } public void setEstado(IEstado estado) { this.estado = estado; } //implementar todos os estados, através desta maquina de estados //interface de todas as classes public void defineNomeJogador(int numeroJogador, String nome) { //estado seguinte vai ser do retornar.. estado = estado.defineNomeJogador(numeroJogador, nome); } public void comecarJogo() { estado = estado.comecaJogo(); } public void jogar(int numeroJogador, int linha, int coluna) { estado = estado.joga(numeroJogador, linha, coluna); } public void devolver(int numeroJogador, int linha, int coluna) { estado = estado.devolve(numeroJogador, linha, coluna); } public void abandonar(int numeroJogador) { estado = estado.abandona(numeroJogador); } //os métodos que surgem no IUTexto public Jogador getJogador1() { return jogodados.getJogador1(); } public Jogador getJogador2() { return jogodados.getJogador2(); } public String getNomeJogadorActivo() { return jogodados.getNomeJogadorActivo(); } public int getNumJogadorActivo() { return jogodados.getNumJogadorActivo(); } public String grelhaToString() { return jogodados.grelhaToString(); } //ou em alternativa dava acesso ao jogodados public JogoDados getJogo() { return jogodados; } //gravação dos ficheiros public void grava(String filename) throws IOException { ObjectOutputStream oos = null; try { oos = new ObjectOutputStream(new FileOutputStream(filename)); oos.writeObject(this); } finally { if(oos != null) { oos.close(); } } } public static JogoMaquinaEstados ler(String filename) throws IOException, ClassNotFoundException { ObjectInputStream oos = null; try { oos = new ObjectInputStream(new FileInputStream(filename)); return (JogoMaquinaEstados) oos.readObject(); } finally { if(oos != null) { oos.close(); } } } }
Tags : java, Máquina de estados, Programação avançada
0 thoughts on “Programação avançada – capitulo 8 – maquina de estados, exemplo3”