Tag: Máquina de estados

Programação avançada – capitulo 8 – maquina de estados, exemplo3 (revisitado)

Revisitar o exercício acerca do uso de maquina de estados com a implementação de um jogo de 3×3, onde existem dois jogadores.

A máquina de estados:
é um padrão de programação;
serve para abordar problemas mais complexos;
vai ajudar no fluxo na evolução das aplicações (redirecciona para o estado que vai fazer um determinado processamento);
permite identificar os momentos importantes, na evolução da aplicação/jogo;

Definição dos estados:
está relacionada com a interacção do utilizador;
existem transições entre os estados;
as transições de entrada (métodos) e podem/devem ser condicionados pelo estado do jogo;
as transições de saída (métodos) e podem/devem ser condicionados pelo estado do jogo;
existem então acções do utilizador sobre o jogo, e estas acções resultam em métodos, para haver evolução no jogo;
(identificar as etapas do jogo, que vão ser implementadas, para resolver mini problemas, sub dividir para se simplificar o código que é implementado);

Os estados, são assim:
são representados através de classes;
existe uma classe base, da qual os estados vão derivar (polimorfismo), normalmente do IEstado (através do implements);
e devem ser implementados todos os métodos abstractos que estão definidos no IEstado (usando return para o new “estado”) ou então fica nele próprio (return this).

(2)O IEstado, serve então:
é uma interface, dos estados (e não uma classe);
serve para representar/declarar o que existe, acções possíveis e comuns em todos os estados (através de métodos);
esses métodos são do tipo da interface IEstado;
mas atenção que podem existir algumas acções que podem não ser usadas/implementadas em todos os estados (fica o return this, nas bases), mas têm que ser aqui colocadas, construindo implementações default;
assim sendo os IEstado representam as evoluções (transições) do nosso modelo.

(3)O EstadoAdapter, serve então para:
é uma classe intermédia/genérica que vai implementar os comportamentos default, sem qualquer actualização de estado, para evitar a programação destas acções em estados onde não fazem sentido (normalmente ficam no mesmo estado).
só depois e em cada um dos estados é que os vamos implementar, pois só se justifica no contexto desse estado haver uma evolução na maquina de estados, e é em cada um desses estados que fica implementado
esta classe implementa o IEstado (implements)
implementa todos os métodos abstractos / default (return this), isto é, não existe evolução de estado/fica no mesmo estado.
surge aqui também os testes da evolução, assim estes estados vão ter que ter acesso aos dados do jogo (JogoDados), construtor e get e set
esta classe deve ser public abstract, para não ser instanciada,
e o JogoDados fica protected, evitando fazer uso do método getJogo, e pelas derivadas acedo a esta instância

(4)E agora construir os estados, que são classes derivadas e:
são extends EstadoAdapter
por ser protected a base, esta derivada tem que ter o construtor correspondente (super)
implementar os métodos correspondentes às acções que fazem sentido, são as setas de saída;
os outros não fazem sentido num estado, ficam com o default do EstadoAdapter
os métodos implementados em cada um dos estados fazem então um return new estado, ou this se voltar ao mesmo, sendo que é implementada também a lógica de cada um dos métodos

Surge uma classe
surge então o inicio da máquina de estados, representando numa classe que inicia o primeiro estado por onde arranca (new..), e que vai permitir aceder (get) ou alterar o estado (set)
esta classe vai ter que satisfazer as ordens do utilizador, define os métodos que permitem alterar/mudança de estado (métodos de transição)

Na iteração com o utilizador (texto ou gráfica):
recebe a maquina de estados;
obtém permanente o estado em que se encontra a máquina de estados;
faz uso de instanceof dos estados para invocar a interface que deve surgir ao utilizador.

neste exemplo:
(1)o JogoMaqEstados, gestão/ver a evolução/mudança entre os estados (no diagrama ir de um estado para outro), conhece o estado atual, é a classe de interface entre o IU do utilizador e todas as classes internas (quer aquelas que representam os estados, quer os dados, que representam o jogo (tem assim informação sobre o jogo (JogoDados), e o estado em que estamos (IEstado));
o JogoMaqEstados tem ainda a interface para todos os outros estados, onde actualiza a situação do estado;
os estados, recebem a entidade jogo, como referência;
já a grelha, onde estão as peças, o jogador, este tipo de dados ficam em JogoDados;
JogoDados, representa assim o tabuleiro do jogo, onde se fazem todas as verificações;
Jogador, representada cada um dos jogos;
Peca, as peças do tabuleiro de jogo;
IEstado;
EstadoAdapter

(10) A interface (IU) também precisa de ir buscar coisas ao jogo, mas quem trata disso é o JogoMaqEstados

package me_jogopecasr;

import me_jogopecasr.iu.texto.IUtexto;
import me_jogopecasr.logica.JogoMaqEstados;

public class Me_jogoPecasR {

    public static void main(String[] args) {

        IUtexto iuTexto = new IUtexto(new JogoMaqEstados());
        iuTexto.corre();
    }
}
package me_jogopecasr.iu.texto;

import java.util.Scanner;
import me_jogopecasr.logica.JogoMaqEstados;
import me_jogopecasr.logica.estados.AguardaColocacao;
import me_jogopecasr.logica.estados.AguardaDevolucao;
import me_jogopecasr.logica.estados.AguardaInicio;
import me_jogopecasr.logica.estados.IEstado;

public class IUtexto {

    private JogoMaqEstados jogo;
    private boolean sair = false;

    public IUtexto(JogoMaqEstados 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");
            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;
            }
        }
    }

    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')) {
            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_jogopecasr.logica;

public interface Constantes {
    int DIM = 3;
}
package me_jogopecasr.logica;

import java.util.ArrayList;
import java.util.List;


public class Jogador implements Constantes {

    private JogoDados jogo;
    private String nome;
    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 void setNome(String nome) {
        this.nome = nome;
    }

    public String getNome() {
        return nome;
    }

    public boolean isGanhou() {
        return ganhou;
    }

    public void setGanhou(boolean ganhou) {
        this.ganhou = ganhou;
    }

    public void recebePecas() {
        mao.clear();
        for (int i = 0; i < DIM; i++) {
            mao.add(new Peca(this));
        }
        ganhou = false;
    }
     public void recebePeca(Peca peca) {
            mao.add(peca);   
    }

    public boolean temPecas() {
        return mao.size() > 0;
    }

    public boolean jogar(int linha, int coluna) {
        if (mao.size() == 0) {
            return false;
        }
        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";
    }

    public int getNumPecas() {
        return mao.size();
    }
}
package me_jogopecasr.logica;

import java.util.ArrayList;
import java.util.List;

public class JogoDados implements Constantes{
 
    private List<Jogador> jogadores = new ArrayList<Jogador>();

    private int numJogActivo;
    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() {
        return jogadores.get(numJogActivo - 1);
    }
    public String getNomeJogadorActivo() {
        return jogadores.get(numJogActivo - 1).getNome();
    }

    public Jogador getJogadorNaoActivo() {
        if (numJogActivo == 1) {
            return jogadores.get(1);
        } else if (numJogActivo == 2) {
            return jogadores.get(0);
        }
        return null;
    }

    public int getNumJogadorActivo() {
        return numJogActivo;
    }

    public int getNumJogadorNaoActivo() {
        return (numJogActivo == 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() {
        numJogActivo = numJogActivo == 1 ? 2 : 1;
    }

  
    public boolean inicializa() {

        grelha = new Peca[DIM][DIM];
        jogadores.get(0).recebePecas();
        jogadores.get(1).recebePecas();

        numJogActivo = 1;

        return true;
    }

    public boolean setNomeJogador(int num, String nome) {
        try{
            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(numJogActivo != 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(numJogActivo != 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_jogopecasr.logica;

import me_jogopecasr.logica.estados.AguardaInicio;
import me_jogopecasr.logica.estados.IEstado;

public class JogoMaqEstados {
    JogoDados jogo;
    IEstado estado;

    public JogoMaqEstados() {
        //1)
        this.jogo = new JogoDados();
        //7
        this.estado = new AguardaInicio(jogo);
    }

    public JogoDados getJogo() {
        return jogo;
    }

    public void setJogo(JogoDados jogo) {
        this.jogo = jogo;
    }

    public IEstado getEstado() {
        return estado;
    }

    public void setEstado(IEstado estado) {
        this.estado = estado;
    }

    //8 redirecionar, agulhar, as acções para os estados, o interface para todas as outras classes
    public void defineNomeJogador(int numeroJogador, String nome) {
        //8.1 a evolução do estado, retorna o estado seguinte
        estado = estado.defineNomeJogador(numeroJogador, nome); //ou usar o setEstado
    }

    public void comecarJogo() { //no infitivo
        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);
    }

    //9 redirencuionar para o modelo de dados
    public Jogador getJogador1() {
        return jogo.getJogador1();
    }

    public Jogador getJogador2() {
        return jogo.getJogador2();
    }

    //11 redirencuionar para o modelo de dados
    public String getNomeJogadorActivo() {
        return jogo.getNomeJogadorActivo();
    }

    public String grelhaToString() {
        return jogo.grelhaToString();
    }

    public int getNumJogadorActivo() {
        return jogo.getNumJogadorActivo();
    }

}

package me_jogopecasr.logica;

public class Peca {
    private Jogador jogador;

    public Peca(Jogador jogador) {
        this.jogador = jogador;
    }

    public Jogador getJogador() {
        return jogador;
    }

    public String toString(){
        return "" + jogador.getNome().charAt(0);
    }
}

package me_jogopecasr.logica.estados;

import me_jogopecasr.logica.JogoDados;
//5
public class AguardaColocacao extends EstadoAdapter{
    //6.2.3 ver se ele não colocou no mesmo local
    int l, c; 
    
    //5.1
    public AguardaColocacao(JogoDados jogo) {
        super(jogo);
        //6.2.5
        l = c-1;
    }
    //6.2.4
        public AguardaColocacao(JogoDados jogo, int l, int c) {
        super(jogo);
        this.l = l;
        this.c = c;
    }

    //5.2
    @Override
    public IEstado abandona(int numeroJogador) {
        //poderia ver qual é o jogador e atribuir a vitória ao outro
        return new AguardaInicio(jogo);
    }
    
    //5.3
    @Override
    public IEstado joga(int numeroJogador, int linha, int coluna) {
         //6.2.6, testar se é a mesma jogada
         if(linha == l && coluna == c){
             return this;
         }
        
        
        //5.3.1, vamos realizar o jogar
        if(!jogo.jogar(numeroJogador, linha, coluna)){
            return this;
        }
        
        //5.3.2, ver se ele ganhou
        if(jogo.getJogadorActivo().isGanhou()){
            return new AguardaInicio(jogo);
        }
        //5.3.3, mudar de jogador
        jogo.jogaOutro();
        
        //5.3.4, ver se tem peças 
         if(jogo.getJogadorActivo().isGanhou()){
            return new AguardaColocacao(jogo); //ou return this, fica no mesmo estado, e com l e c a -1
        }
         
         
         //5.3.5, 
         return new AguardaDevolucao(jogo);
    }
    
    
    
}


package me_jogopecasr.logica.estados;

import me_jogopecasr.logica.JogoDados;

//6
public class AguardaDevolucao extends EstadoAdapter {

    public AguardaDevolucao(JogoDados jogo) {
        super(jogo);
    }

    //6.1
    @Override
    public IEstado abandona(int numeroJogador) {
        return new AguardaInicio(jogo);
    }
    
    //6.2
    @Override
    public IEstado devolve(int numeroJogador, int linha, int coluna) {
        //6.2.1 adcionar a devolção
        if(jogo.devolver(numeroJogador, linha, coluna)){
            //o devolver já verifica
            return new AguardaColocacao(jogo, linha, coluna);  //6.2.7
        }
        //6.2.2 fica no mesmo estado
        return this;
    }
    
    
}

package me_jogopecasr.logica.estados;

import me_jogopecasr.logica.JogoDados;

public class AguardaInicio extends EstadoAdapter{
    //4) por ser protected a base, esta derivada tem que ter um construtor correspondente
    public AguardaInicio(JogoDados jogo) {
        super(jogo);
    }
    
    //4.2) implementar os métodos correspondentes às acções que fazem sentido, são as setas de saída

    @Override
    public IEstado defineNomeJogador(int numeroJogador, String nome) {
        //4.4
        jogo.setNomeJogador(numeroJogador, nome);
        //4.3
        return this;
    }

    @Override
    public IEstado comecaJogo() {
        //4.4 testes para começar um jogo
        if(jogo.getJogador1()== null || jogo.getJogador2() ==null){
        //fico no mesmo estado
        return this;
        }
        
        //12
        jogo.inicializa();
        return new AguardaColocacao(jogo);
    }
    
    
}

package me_jogopecasr.logica.estados;

    //3) existem acções que não fazem sent
import me_jogopecasr.logica.JogoDados;

public abstract class EstadoAdapter implements IEstado{
    //3.2) acesso aos jogos de dados
    //3.3) protected, evitando fazer uso do método getJogo, e pelas derivadas acedo a esta instancia
    protected JogoDados jogo;

    public EstadoAdapter(JogoDados jogo) {
        this.jogo = jogo;
    }

    public JogoDados getJogo() {
        return jogo;
    }

    public void setJogo(JogoDados jogo) {
        this.jogo = jogo;
    }
    
    
    //3.1)
    @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;
    }
    
}

package me_jogopecasr.logica.estados;

//2) definir todos os estados
public interface IEstado {
    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);
}
Tags : , , ,

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

Programação avançada – capitulo 8 – maquina de estados, exemplo2

Exemplo de uma maquina de estado, simples, usando as referências a um mecanismo de um elevador com dois estados extra: erro e chaveManutencao

Em que ficou:

Com:

package me_me_elevador;

import me_me_elevador.IU.Texto.UsaElevador;
import me_me_elevador.logica.Elevador;

public class Me_ME_elevador {
    public static void main(String[] args) {
        Elevador e = new Elevador();
        UsaElevador usaE = new UsaElevador(e); //interface com o utilizador
        usaE.corre();
    }
}
package me_me_elevador.IU.Texto;

import me_me_elevador.logica.*;
import me_me_elevador.util.IUUtil;

public class UsaElevador {

    //o interface com o utilizador, com o nosso elevador.
    private Elevador elevador;
    private boolean sair = false;

    public UsaElevador(Elevador elevador) {
        this.elevador = elevador;
    }

    public void corre() {
        while (!sair) {
            //saber em que estado estou
            IEstado estado = elevador.getEstado();
            if (estado instanceof RC) {
                iuRC();
            } else if (estado instanceof Andar1) {
                iuAndar1();
            } else if (estado instanceof Andar2) {
                iuAndar2();
            } else if (estado instanceof Andar3) {
                iuAndar3();
            }else if (estado instanceof Manutencao) {
                iuManutencao();
            }
        }
    }
    
    
     private void iuManutencao() {
        int opcao = IUUtil.getOpcao("Em modo de manutenção", "Usar a chave", "Sair do elevador");
        switch (opcao) {
            case 0:
                elevador.chaveManutencao();
            case 1:
                sair = true;
                break;
        }
    }

    private void iuRC() {
        //opcoa 1
        //pedir ao utilizador: sair ou subir
        int opcao = IUUtil.getOpcao("Piso R/C", "Sair do prédio", "Subir", "Erro");
        switch (opcao) {
            case 0:
                sair = true;
                break;
            case 1:
                //fazer evoluir a maquina de estados
                elevador.sobe();
                break;
            case 2:
                elevador.erro();
                break;
        }
    }

    private void iuAndar1() {
        int opcao = IUUtil.getOpcao("Piso 1 andar", "Descer", "Subir", "Erro");
        switch (opcao) {
            case 0:
                //fazer evoluir a maquina de estados
                elevador.desce();
                break;
            case 1:
                //fazer evoluir a maquina de estados
                elevador.sobe();
                break;
            case 2:
                elevador.erro();
                break;
        }
    }

    private void iuAndar2() {
        int opcao = IUUtil.getOpcao("Piso 2 andar", "Descer", "Subir", "Erro");
        switch (opcao) {
            case 0:
                //fazer evoluir a maquina de estados
                elevador.desce();
                break;
            case 1:
                //fazer evoluir a maquina de estados
                elevador.sobe();
                break;
            case 2:
                elevador.erro();
                break;
        }
    }

    private void iuAndar3() {
        int opcao = IUUtil.getOpcao("Piso 3 andar", "Descer", "Erro");
        switch (opcao) {
            case 0:
                //fazer evoluir a maquina de estados
                elevador.desce();
                break;
            case 1:
                elevador.erro();
                break;
        }
    }
}
package me_me_elevador.logica;

public class Andar1 extends Piso {

    @Override
    public IEstado sobe() {
        //altero de estado
        return new Andar2();
    }

    @Override
    public IEstado desce() {
        //altero de estado
        return new RC();
    }
    
    //se fossem todos iguais podia ser implementado no Piso
    // com return this;
    @Override
    public IEstado erro() {
        return new Manutencao(this);
    }
}
package me_me_elevador.logica;

public class Andar2 extends Piso{

    @Override
    public IEstado sobe() {
        return new Andar3();
    }

    @Override
    public IEstado desce() {
        return new Andar1();
    }
    @Override
    public IEstado erro() {
                return new Manutencao(this);
    }
}
package me_me_elevador.logica;

public class Andar3 extends Piso{

    @Override
    public IEstado sobe() {
        //fico no mesmo estado
       return this;
    }

    @Override
    public IEstado desce() {
        //altero de estado
        return new Andar2();
    }
    @Override
    public IEstado erro() {
                return new Manutencao(this);
    }
}

package me_me_elevador.logica;

public class Elevador {
    IEstado estado;

    public Elevador() {
        estado = new RC();
    }

    public IEstado getEstado() {
        return estado;
    }
    public void setEstado(IEstado estado) {
        this.estado = estado;
    }
    public void sobe() {
        setEstado(estado.sobe());
    }

    public void desce() {
        setEstado(estado.desce());
    }
    
    public void erro(){
        setEstado(estado.erro());
    }
    
    public void chaveManutencao(){
        setEstado(estado.chaveManutencao());
    }
}

package me_me_elevador.logica;

public interface IEstado {
    IEstado sobe();
    IEstado desce();
    
    IEstado erro();
    IEstado chaveManutencao();
}

package me_me_elevador.logica;

public class Manutencao extends Piso{
    //vai recordar qual era o estado antes
    private IEstado anterior;

    public Manutencao(IEstado ant) {
        this.anterior = ant;
    }
    
    @Override
    public IEstado chaveManutencao() {
      return anterior;
    }   
}
package me_me_elevador.logica;

public abstract class Piso implements IEstado {
    @Override
    public IEstado sobe() {
        return this;
    }

    @Override
    public IEstado desce() {
        return this;
    }

    @Override
    public IEstado chaveManutencao() {
        return this;
    }

    @Override
    public IEstado erro() {
        return this;
    }
}
package me_me_elevador.logica;

public class RC extends Piso {

    @Override
    public IEstado sobe() {
        //altero de estado
        return new Andar1();
    }

    @Override
    public IEstado desce() {
        //fico no mesmo estado
        return this;
    }

    @Override
    public IEstado erro() {
        return new Manutencao(this);
    }
}

package me_me_elevador.util;

import java.util.Scanner;

public class IUUtil {
    public static int getOpcao(String question, String... options) {
        System.out.println(question);
        char[] ops = new char[options.length];
        for (int i = 0; i < options.length; i++) {
            char o = '\0';
            int c = 0;
            while (c < options[i].length()) {
                o = Character.toUpperCase(options[i].charAt(c));
                for (int j = 0; j < i; j++) {
                    if (ops[j] == o) {
                        o = '\0';
                        break;
                    }
                }
                if (o != '\0') {
                    break;
                }
                c++;
            }
            if (c >= options[i].length()) {
                return -1;
            }
            ops[i] = o;
            if (i > 0) {
                System.out.print(", ");
            }
            if (c > 0) {
                System.out.print(options[i].substring(0, c));
            }
            System.out.print("(" + ops[i] + ")" + options[i].substring(c + 1));
        }
        System.out.println();
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.print("Option: ");
            char o = Character.toUpperCase(sc.nextLine().charAt(0));
            for (int i = 0; i < ops.length; i++) {
                if (o == ops[i]) {
                    return i;
                }
            }
        }
    }
}

O erro e a chaveEmergencia são acções, sendo que o evento que surge é a Manutenção.

Tags : , ,

Programação avançada – capitulo 8 – maquina de estados, exemplo1

Exemplo de uma maquina de estado, simples, usando as referências a um mecanismo de um elevador

Em que ficou:

Com:

package me_me_elevador;

import me_me_elevador.IU.Texto.UsaElevador;
import me_me_elevador.logica.Elevador;

public class Me_ME_elevador {
    public static void main(String[] args) {
        Elevador e = new Elevador();
        UsaElevador usaE = new UsaElevador(e); //interface com o utilizador
        usaE.corre();
    }
}
package me_me_elevador.IU.Texto;

import me_me_elevador.logica.*;
import me_me_elevador.util.IUUtil;

public class UsaElevador {

    //o interface com o utilizador, com o nosso elevador.
    private Elevador elevador;
    private boolean sair = false;

    public UsaElevador(Elevador elevador) {
        this.elevador = elevador;
    }

    public void corre() {
        while (!sair) {
            //saber em que estado estou
            IEstado estado = elevador.getEstado();
            if (estado instanceof RC) {
                iuRC();
            } else if (estado instanceof Andar1) {
                iuAndar1();
            } else if (estado instanceof Andar2) {
                iuAndar2();
            } else if (estado instanceof Andar3) {
                iuAndar3();
            }
        }
    }

    private void iuRC() {
        //opcoa 1
        //pedir ao utilizador: sair ou subir
        int opcao = IUUtil.getOpcao("Piso R/C", "Ir embora", "Subir");
        switch (opcao) {
            case 0:
                sair = true;
                break;
            case 1:
                //fazer evoluir a maquina de estados
                elevador.sobe();
                break;
        }
    }

    private void iuAndar1() {
        int opcao = IUUtil.getOpcao("Piso 1 andar","Descer", "Subir");
        switch (opcao) {
            case 0:
                //fazer evoluir a maquina de estados
                elevador.desce();
                break;
            case 1:
                //fazer evoluir a maquina de estados
                elevador.sobe();
                break;
        }
    }

    private void iuAndar2() {
        int opcao = IUUtil.getOpcao("Piso 2 andar","Descer", "Subir");
        switch (opcao) {
            case 0:
                //fazer evoluir a maquina de estados
                elevador.desce();
                break;
            case 1:
                //fazer evoluir a maquina de estados
                elevador.sobe();
                break;
        }
    }

    private void iuAndar3() {
        int opcao = IUUtil.getOpcao("Piso 3 andar","Descer");
        switch (opcao) {
            case 0:
                //fazer evoluir a maquina de estados
                elevador.desce();
                break;
        }
    }
}
package me_me_elevador.logica;

public class Andar1 extends Piso{

    @Override
    public IEstado sobe() {
        //altero de estado
        return new Andar2();
    }

    @Override
    public IEstado desce() {
        //altero de estado
        return new RC();
    }
}
package me_me_elevador.logica;

public class Andar2 extends Piso{

    @Override
    public IEstado sobe() {
        return new Andar3();
    }

    @Override
    public IEstado desce() {
        return new Andar1();
    }
}
package me_me_elevador.logica;

public class Andar3 extends Piso{

    @Override
    public IEstado sobe() {
        //fico no mesmo estado
       return this;
    }

    @Override
    public IEstado desce() {
        //altero de estado
        return new Andar2();
    }
}
package me_me_elevador.logica;

public class Elevador {
//é a maquina de estados, que faz alterar os estados
    IEstado estado;

    public Elevador() {
        //o estado incial//arranque é então:
        estado = new RC();
    }

    public IEstado getEstado() {
        return estado;
    }

    public void setEstado(IEstado estado) {
        this.estado = estado;
    }

    //podia ter outras informações, como o numero de pessoas
    //as luzes que estão ou não ligadas..
    //métodos que dão origem à mudança de estado
    public void sobe() {
        setEstado(estado.sobe()); //versão1
        //this.estado = estado.sobe();  //versão2
    }

    public void desce() {
        setEstado(estado.desce()); //versão1
        //this.estado = estado.desce();  //versão2
    }
}
package me_me_elevador.logica;

public interface IEstado {
    //acções comuns a cada uma dos estados:RC,andar1,andar2...
    //interface geral
    IEstado sobe();
    IEstado desce();
}
package me_me_elevador.logica;

public abstract class Piso implements IEstado {
    //classe para implementação default, sem alterar o estado
    //serve para simplifcar todas as outras
    @Override
    public IEstado sobe() {
        return this;
    }

    @Override
    public IEstado desce() {
        return this;
    }
}
package me_me_elevador.logica;

public class RC extends Piso{

    @Override
    public IEstado sobe() {
        //altero de estado
        return new Andar1();
    }

    @Override
    public IEstado desce() {
        //fico no mesmo estado
        return this; 
    }
}
package me_me_elevador.util;

import java.util.Scanner;

public class IUUtil {
    // v1
      public static int getOpcao(String question, String... options) {
        System.out.println(question);
        char[] ops = new char[options.length];
        for (int i = 0; i < options.length; i++) {
            char o = '\0';
            int c = 0;
            while (c < options[i].length()) {
                o = Character.toUpperCase(options[i].charAt(c));
                for (int j = 0; j < i; j++) {
                    if (ops[j] == o) {
                        o = '\0';
                        break;
                    }
                }
                if (o != '\0') {
                    break;
                }
                c++;
            }
            if (c >= options[i].length()) {
                return -1;
            }
            ops[i] = o;
            if (i > 0) {
                System.out.print(", ");
            }
            if (c > 0) {
                System.out.print(options[i].substring(0, c));
            }
            System.out.print("(" + ops[i] + ")" + options[i].substring(c + 1));
        }
        System.out.println();
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.print("Option: ");
            char o = Character.toUpperCase(sc.nextLine().charAt(0));
            for (int i = 0; i < ops.length; i++) {
                if (o == ops[i]) {
                    return i;
                }
            }
        }
    }
}

No interface IEstado, são colocados todas as ações dos estados, mesmo que não façam sentido em alguns dos estados.
A class Piso, faz a implementação default de alguns dos estados para que não tenhamos que estar a repetir código nos diferentes estados.

Tags : , ,

Programação avançada – capitulo 8

Num máquina de estados existem os seguintes conceitos:
estados (por exemplo: “sem moedas”, “com moedas”, “em manutenção”, ..),
acções (por exemplo: “insere moeda”, “retira moeda”, “roda manípulo”, “roda manipulo”,…),
tem reacções (de ignorar, ou de alterar o seu estado e executar acções (que por sua vez podem ou não gerar outras acções)).

Assim uma aplicação tem:
contexto ou entidade (entidade cujo contexto depende do seu estado),
eventos (podem acontecer acções que fazem desencadear eventos),
e estados (é a situação que é assumida aquando de eventos e traduz o resultado do comportamento da entidade).

A máquina de estados orientada a objectos
A entidade maquina de estados, tem funções que correspondem ao processamento dos eventos a que reage. O processamento dos eventos depende do estado em que a entidade se encontra. Quando se pretende que o código das funções da entidade que correspondem ao processamento de eventos não envolva instruções if ou switch dependentes do estado:

  1. define-se uma hierarquia de classes que representa os estados possíveis e contém o conhecimento acerca do processamento de eventos em cada estado (incluindo mudanças de estado)
  2. a entidade, em cada momento, tem uma referência para um objecto que representa o estado concreto em que se encontra
  3. as funções da entidade que correspondem a processamento de eventos que dependem do estado, delegam para o objecto que representa o estado corrente, o processamento dos eventos.

O contexto tem uma referência para um objecto que representa o estado (concreto) em que se encontra. Os possíveis estados concretos fazem parte de uma hierarquia que tem por base um tipo abstracto, IEstado.
O comportamento da entidade (o seu contexto) é delegado nesse objecto (estado concreto):
reacção aos eventos
acções a executar
mudanças de estado

Assim surge a entidade ou contexto, o estado e os estados concretos, e que se podem resumir da seguinte forma:
A entidade ou contexto:
define o interface necessário de acordo com as suas responsabilidades
mantém um membro que representa o estado concreto em que se encontra
tem uma referencia para o IEstado (tipo da base da hierarquia que representa os estados possíveis) que refere o objecto que representa o estado concreto em que se encontra
tem métodos que representam o processamento de eventos. A entidade delega o processamento de eventos (que pode variar conforme o seu estado) no objecto que representa o estado corrente

O estado (IEstado):
define o interface para encapsular o comportamento da entidade que pode variar conforme o seu estado concreto

Os Estados concretos, que são classes derivadas da classe EstadoAdapter (que implementa o interface IEstado):
cada classe derivada, representando um estado concreto, implementa o comportamento que lhe e associado.

Tags : , , ,