O que são Maquinas de Estado Finito? (Finite State Machines) – FSM



Original Source Here

Vamos de código

Uma coisa que é bacana para assimilar esse conceito é tentar criar algo usando essa ideia, mas totalmente fora da caixa. Poderíamos criar um componente em React, mas vamos de fora pra dentro assim você entenderá o que é e como usar.

Vamos criar o NPC que citei acima, com os estados definidos e uma maquina de estado para gerenciar isso.

Primeiro vamos definir constantes com nossos estados, assim fica mais fácil reutilizar

const ESTADO_PARADO = 'parado';
const ESTADO_PATRULHANDO = 'patrulhando';
const ESTADO_PROCURANDO_INIMIGO = 'procurando';
const ESTADO_ATACANDO = 'atacando';
const ESTADO_MORTO = 'morto';

Vamos criar um objeto para gerenciar a maquina de estado chamado “Guardiao” esse objeto será nossa entidade NPC.

class Guardiao {  constructor() {
this.estado_atual = ESTADO_PARADO;
this.vida = 100;
this.alvo = null;
this.pode_patrulhar = true;
}
}

Como ele acabou de existir, definiremos ele com o estado inicial de ”PARADO”

Agora vamos a construção base da nossa maquina de estado.

Vamos definir uma bifurcação que decide o que fazer para cada estado definido, então criamos a função maquinaDeEstado

maquinaDeEstado = () => {  if (this.vida <= 0) this.mudaDeEstado(ESTADO_MORTO);  switch (this.estado_atual) {    case ESTADO_PATRULHANDO:
this.processa_patrulhando();
break;
case ESTADO_PROCURANDO_INIMIGO:
this.processa_procurando();
break;
case ESTADO_ATACANDO:
this.processa_atacando();
break;
case ESTADO_MORTO:
this.processa_morto();
break;
case ESTADO_PARADO:
default:
this.processa_parado();
}};

O que fizemos foi, criar switch que irá chamar a devida função de acordo com cada estado.

Observe que acrescentamos apenas uma condição fora do switch para garantir que quando ele morrer o estado atual seja sempre MORTO. Meio óbvio mas precisamos dizer isso a nossa maquina de estado

if (this.vida <= 0) this.mudaDeEstado(ESTADO_MORTO);

Para cada um desses estados vamos criar uma função responsável por ele:

Estado Parado

Esse estado o guardião não fará muita coisa, apenas verificará se ja tem alvo válido para ir até ele e se tiver autorização para patrulhar mudar para o estado de patrulha.

processa_parado = () => {  // muda de estado quando encontra um alvo
if (this.verificaAlvoExisteEstaVivo())
this.mudaDeEstado(ESTADO_PROCURANDO_INIMIGO);
// se puder patrulhar muda para o estado de patrulha
if (this.pode_patrulhar) this.mudaDeEstado(ESTADO_PATRULHANDO);
};

Estado patrulhando

O guardião verifica se tem inimigos ao redor. E caso encontrado, o guardião irá para o estado de se aproximar dele. Caso a autorização de patrulhar seja revogada, o guardião volta ao estado inicial.

processa_patrulhando = () => {  // simulamos aqui uma procura por alvos ao redor
this.verificaTemInimigosAoRedor();
// se o alvo foi encontrado e tiver vivo vamos atras dele
if (this.verificaAlvoExisteEstaVivo()) {
this.mudaDeEstado(ESTADO_PROCURANDO_INIMIGO);
return;
} this.caminhaPraLaEPraCa();
// se por algum acaso ele não puder mais patrulhar,
// voltamos a ficar parado
if (!this.pode_patrulhar)
this.mudaDeEstado(ESTADO_PARADO);
};

Estado Procurando Inimigo

Verificar se o alvo do guardião que foi encontrado na patrulha não está morto ou sumiu, e se for válido, o guardião vai se aproximar dele até uma distancia valida para atacar.

processa_procurando = () => {  // se o alvo sumir ou morrer, volta ao estado inicial
if (!this.verificaAlvoExisteEstaVivo()) {
this.mudaDeEstado(ESTADO_PARADO);
return;
}
// se aproxima do alvo
this.caminhaAteOAlvo();
// se tiver certeza que pode atacar, muda para o estado atacando
if (this.verificaPossoAtacarOAlvo()) {
this.mudaDeEstado(ESTADO_ATACANDO);
return;
}
};

Estado atacando

Verificaremos se o alvo do guardião ainda é valido, e caso positivo o guardião ataca o alvo, se ele sumir ou morrer, o guardião volta ao estado inicial. Caso o alvo se afaste, o guardião precisa se aproximar novamente.

processa_atacando = () => {
// quer dizer que a missão foi cumprida e podemos voltar ao estado inicial
if (!this.verificaAlvoExisteEstaVivo()) {
this.mudaDeEstado(ESTADO_PARADO);
return;
}
this.ataque(); // se por alguma razão o alvo se afastou. precisamos nos aproximar novamente do alvo.
if (this.verificaPossoAtacarOAlvo()) {
this.mudaDeEstado(ESTADO_PROCURANDO_INIMIGO);
return;
}
};

Estado Morto

Esse estado só garantimos que o guardião vai levantar novamente em caso de recuperação de vida

processa_morto = () => {   // se a vida aumentar, levanta o guardião
if (this.verificaEstouVivo()) this.mudaDeEstado(ESTADO_PARADO);
};

Estados definidos e maquina pronta

Como é possível ver, cada uma das funções cuida do estado atual, decidindo ser irá para outro estado ou não de acordo com determinadas condicionais.

E é isso que define a maquina de estado, não importa o que ela seja, não importa o que ela faça, ela cuida de mudar de um estado para outro de acordo com o comportamento ao redor.

Agora vamos ao código completo de como deve ficar. Lembrando que é apenas um pseudo-código que pode ser executado para entender melhor o funcionamento.

AI/ML

Trending AI/ML Article Identified & Digested via Granola by Ramsey Elbasheer; a Machine-Driven RSS Bot

%d bloggers like this: