Publicado por: hdstryOwrld el Mar 11 2010, 04:55 AM
Si lo sé hace mucho tiempo que no escribia pero bien ahora con mi poco tiempo vengo acá a traerles un ejemplo de simulación de inteligencia artificial, es un código en C# que maneja en práctica lo que se conocen como maquinas de estados finitos, la explicación y la documentación viene perfecta dentro del código fuente que incluyo en adjunto, espero les sea de utilidad. Cualquier duda ya saben esto a sus órdenes.
Clase CMaquina:
CÓDIGO
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MEF
{
class CMaquina
{
/// <summary>
/// Estructura que posee los elementos que conforman los objetos que recogera el robot
/// </summary>
public struct S_objeto
{
public bool Activo; //¿El objeto se encuentra activo?
public int x, y; //Coordenadas del objeto
};
/// <summary>
/// Enumeración que posee los estados que pueden ocurrir veasé tabla de transiciones
/// </summary>
public enum estados
{
BUSQUEDA,
NBUSQUEDA,
IRBATERIA,
RECARGAR,
MUERTO,
ALEATORIO
};
private int state;
public estados strEstado;
/// <summary>
/// Representa el estado en el que se encuentra el robot
/// </summary>
public int Estado
{
get
{
return (int)state;
}
set
{
state = (int)value;
}
}
/// <summary>
/// Representa la coordenada eje x de la posición del robot
/// </summary>
public int x
{
get;
set;
}
/// <summary>
/// Representa la coordenada eje x de la posición del robot
/// </summary>
public int y
{
get;
set;
}
/// <summary>
/// Contiene las instancias de los objetos
/// </summary>
public S_objeto[] objetos;
//Número de baterias a crear
public S_objeto baterias;
//Indice del elemento que buscamos [Inicialmente ninguno]
private int index = -1;
//Energía actual del robot
private int energia = 400;
/// <summary>
/// Constructor de la clase que crea las instancias de los objetos
/// </summary>
/// <param name="nObjetos">número de objetos a crear</param>
public CMaquina(int nObjetos)
{
objetos = new S_objeto[(int)nObjetos];
Estado = (int)estados.NBUSQUEDA; //Inicialmente comenzamos buscando el objeto
//Coordenadas del robot
x = 320;
y = 240;
}
public void Inicializar()
{
Random random = new Random();
//Recorremos todos los objetos
for (int i = 0; i < objetos.Length; i++)
{
//Colocamos las coordenadas de los objetos
objetos[i].x = random.Next(0, 639);
objetos[i].y = random.Next(0, 479);
//Lo indicamos activos
objetos[i].Activo = true;
}
//Colocamos la batería
baterias.x = random.Next(0, 639);
baterias.y = random.Next(0, 479);
baterias.Activo = true;
}
/// <summary>
/// Esta función es el núcleo central del proceso a la que llamara el timer cuando genere su evento
/// </summary>
public void control()
{
switch (Estado)
{
case (int)estados.BUSQUEDA:
Busqueda();//Se lleva a cabo la operación
//Verificamos si existe transición
if (x == objetos[index].x && y == objetos[index].y)
{
//Se encontro un nuevo objeto abra que desactivarlo
objetos[index].Activo = false;
//Cambiamos de estado
Estado = (int)estados.NBUSQUEDA;
}
else if (energia < 400)
{
//Chequeamos la condición de transisión
Estado = (int)estados.IRBATERIA;
}
break;
case (int)estados.NBUSQUEDA:
NBusqueda();
if (index == -1)
{
//Ya no hay más objetos pasamos al estado aleatorio
Estado = (int)estados.ALEATORIO;
}
else
{
//A buscar
Estado = (int)estados.BUSQUEDA;
}
break;
case (int)estados.IRBATERIA:
IrBateria();
if (baterias.x == x && baterias.y == y)
{
//Encontro la bateria hay que recargar
Estado = (int)estados.RECARGAR;
}
else if (energia == 0)
{
//Acabo el programa
Estado = (int)estados.MUERTO;
}
break;
case (int)estados.RECARGAR:
Recargar();
Estado = (int)estados.NBUSQUEDA;
break;
case (int)estados.ALEATORIO:
Aleatorio();
if (energia < 400)
{
Estado = (int)estados.IRBATERIA;
}
else if (energia == 0)
{
Estado = (int)estados.MUERTO;
}
break;
case (int)estados.MUERTO:
Muerto();
//no hay más transiciones
break;
}
strEstado = (estados)Estado;
}
/// <summary>
/// Realiza las operaciones del estado búsqueda
/// </summary>
private void Busqueda()
{
//Lógica del estado búsqueda
//Nos acercamos al objeto
if (x < objetos[index].x)
{
x++;
}
else if (x > objetos[index].x)
{
x--;
}
if (y < objetos[index].y)
{
y++;
}
else if (y > objetos[index].y)
{
y--;
}
//A cada paso disminuimos la energía
energia--;
}
/// <summary>
/// Realiza las operaciones del estado nueva búsqueda
/// </summary>
private void NBusqueda()
{
//Lógica del estado nueva búsqueda
//Hay objeto?
index=-1; //Damos por hecho que no
for (int i = 0; i < objetos.Length; i++)
{
if (objetos[i].Activo)
{
//Si hay objeto activo... a por el
index = i;
}
}
}
/// <summary>
/// Realiza las operaciones del estado ir a bateria
/// </summary>
private void IrBateria()
{
//Lógica del estado ir por batería
if (x < baterias.x)
{
x++;
}
else if (x > baterias.x)
{
x--;
}
if (y < baterias.y)
{
y++;
}
else if (y > baterias.y)
{
y--;
}
//Disminuimos la energía
energia--;
}
/// <summary>
/// Recargar la bateria
/// </summary>
private void Recargar()
{
//Lógica del estado recargar
energia = 1000;
System.Threading.Thread.Sleep(500);
}
/// <summary>
/// Entra en el estado de aleatorio
/// </summary>
private void Aleatorio()
{
//Lógica del estado aleatorio
//Creamos un objeto para generar valores aleatorios
Random random = new Random();
int nx = random.Next(0, 3);
int ny = random.Next(0, 3);
//Modificamos la posición al azar
x += nx - 1;
y += nx - 1;
energia--;
}
/// <summary>
/// Ya el objeto muere y finaliza el programa
/// </summary>
private void Muerto()
{
//Lógica del estado muerto
}
}
}
Código del formulario
CÓDIGO
namespace MEF
{
partial class frmMain
{
/// <summary>
/// Variable del diseñador requerida.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Limpiar los recursos que se estén utilizando.
/// </summary>
/// <param name="disposing">true si los recursos administrados se deben eliminar; false en caso contrario, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Código generado por el Diseñador de Windows Forms
/// <summary>
/// Método necesario para admitir el Diseñador. No se puede modificar
/// el contenido del método con el editor de código.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
this.archivoToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.salirToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.iniciarToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.iniciarToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.pararToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.tmrCerebro = new System.Windows.Forms.Timer(this.components);
this.menuStrip1.SuspendLayout();
this.SuspendLayout();
//
// menuStrip1
//
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.archivoToolStripMenuItem,
this.iniciarToolStripMenuItem});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(692, 24);
this.menuStrip1.TabIndex = 0;
this.menuStrip1.Text = "menuStrip1";
//
// archivoToolStripMenuItem
//
this.archivoToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.salirToolStripMenuItem});
this.archivoToolStripMenuItem.Name = "archivoToolStripMenuItem";
this.archivoToolStripMenuItem.Size = new System.Drawing.Size(55, 20);
this.archivoToolStripMenuItem.Text = "&Archivo";
//
// salirToolStripMenuItem
//
this.salirToolStripMenuItem.Name = "salirToolStripMenuItem";
this.salirToolStripMenuItem.Size = new System.Drawing.Size(105, 22);
this.salirToolStripMenuItem.Text = "&Salir";
this.salirToolStripMenuItem.Click += new System.EventHandler(this.salirToolStripMenuItem_Click);
//
// iniciarToolStripMenuItem
//
this.iniciarToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.iniciarToolStripMenuItem1,
this.pararToolStripMenuItem});
this.iniciarToolStripMenuItem.Name = "iniciarToolStripMenuItem";
this.iniciarToolStripMenuItem.Size = new System.Drawing.Size(66, 20);
this.iniciarToolStripMenuItem.Text = "Aplicación";
//
// iniciarToolStripMenuItem1
//
this.iniciarToolStripMenuItem1.Name = "iniciarToolStripMenuItem1";
this.iniciarToolStripMenuItem1.Size = new System.Drawing.Size(152, 22);
this.iniciarToolStripMenuItem1.Text = "Iniciar";
this.iniciarToolStripMenuItem1.Click += new System.EventHandler(this.iniciarToolStripMenuItem1_Click);
//
// pararToolStripMenuItem
//
this.pararToolStripMenuItem.Name = "pararToolStripMenuItem";
this.pararToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.pararToolStripMenuItem.Text = "Parar";
this.pararToolStripMenuItem.Click += new System.EventHandler(this.pararToolStripMenuItem_Click);
//
// tmrCerebro
//
this.tmrCerebro.Interval = 5;
this.tmrCerebro.Tick += new System.EventHandler(this.tmrCerebro_Tick);
//
// frmMain
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(692, 516);
this.Controls.Add(this.menuStrip1);
this.MainMenuStrip = this.menuStrip1;
this.Name = "frmMain";
this.Text = "Maquina de estados finitos";
this.Paint += new System.Windows.Forms.PaintEventHandler(this.frmMain_Paint);
this.menuStrip1.ResumeLayout(false);
this.menuStrip1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.MenuStrip menuStrip1;
private System.Windows.Forms.ToolStripMenuItem archivoToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem salirToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem iniciarToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem iniciarToolStripMenuItem1;
private System.Windows.Forms.ToolStripMenuItem pararToolStripMenuItem;
private System.Windows.Forms.Timer tmrCerebro;
}
}
Y los archivos adjuntos con explicación detallada dentro de la carpeta documentación.
Publicado por: hdstryOwrld el Mar 11 2010, 05:22 AM
A y acá les dejo el video del funcionamiento de la aplicación notese que cuando el pequeño robot (cuadrito de color verde) se queda sin batería (cuadrito color rojo) va a llenar su combustible , y mientras allá objetos (Cuadrito color morado) el sigue atrapandolos.