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:

Em que ficou:

Com:

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 : , ,