Fecha 16/12/2018
RESUMEN:
ABSTRACT:
This project investigates and analyzes a solution strategy for the game "Mastermind" that
uses a discrete evolutionary algorithm with application of discrete genetic operators, order
operators and custom operators. The concepts corresponding to intelligent systems, evolutionary
computation and genetic algorithms are presented. It also shows the model of the game and the
strategy to solve it.
Tabla De Contenidos
Lista De Ilustraciones ................................................................................................................. 5
Capítulo I. Descripción del Proyecto ......................................................................................... 6
1.1. Introducción .............................................................................................................. 6
1.2. Objetivos del Proyecto .............................................................................................. 7
1.2.1. Objetivo General ................................................................................................... 7
1.2.2. Objetivos Específicos ............................................................................................ 7
1.3. Justificación del Proyecto ......................................................................................... 7
1.4. Alcance del Proyecto ................................................................................................ 7
Capítulo II. Marco Teórico ........................................................................................................ 8
2.1 Inteligencia Artificial .................................................................................................... 8
2.1.1. Tipos De Inteligencia Artificial ............................................................................... 8
2.1.2. Aplicaciones Prácticas De La Inteligencia Artificial ............................................... 8
2.1.3. Ventajas y Desventajas de la Inteligencia Artificial .............................................. 10
2.2 Sistemas Inteligentes .................................................................................................. 10
2.2.1. Capacidades requeridas .......................................................................................... 10
2.3 Computación Evolutiva .............................................................................................. 12
2.3.1. ¿Cómo representamos a los individuos? ................................................................ 15
2.3.2. ¿Cómo se reproducen y mutan los individuos? ...................................................... 15
2.3.3. ¿Qué es eso de que un "individuo es suficientemente bueno"? ............................. 16
2.3.4. Aplicaciones ........................................................................................................... 17
2.4 Algoritmos Genéticos ................................................................................................. 17
2.4.1. Métodos de representación ..................................................................................... 19
2.4.2. Métodos de selección ............................................................................................. 20
2.4.3. Métodos de cambio ................................................................................................ 21
2.4.4. Ventajas y Desventajas de los algoritmos genéticos .............................................. 22
2.4.5. Algunos ejemplos específicos de AG .................................................................... 23
2.5 Mastemind .................................................................................................................. 31
2.5.1. Elementos Que Componen El Juego ...................................................................... 32
2.5.2. Como Se Juega ....................................................................................................... 32
2.6. Metodologías ................................................................................................................. 33
2.6.1. Metodología en Cascada ........................................................................................ 33
2.6.2. Método de Prototipos ............................................................................................. 34
2.6.3. Modelo Incremental o Iterativo y Creciente .......................................................... 36
Capítulo III. Marco Practico .................................................................................................... 38
3.1. Desarrollo del Proyecto ................................................................................................. 38
3.1.1. Administración del Proyecto .................................................................................. 38
3.2. Análisis del Sistema ................................................................................................ 38
3.2.1. Requisitos No Funcionales .................................................................................. 39
3.2.2. Requisitos Funcionales ........................................................................................ 39
3.3. Diseño del Sistema .................................................................................................. 41
3.3.1. Diagrama de flujo de la estructura base de un algoritmo genético. .................... 41
3.3.2. Diseño de la Solución del Juego Mastermind mediante Algoritmos Geneticos . 42
3.3.3. Como resolver el Juego mediante Computación Evolutiva ................................ 44
3.3.4. Periodo de Iteración – Primera Fase Prototipo.................................................... 46
Lista De Ilustraciones
1.1. Introducción
La Computación Evolutiva engloba un amplio conjunto de técnicas de resolución de
problemas complejos, basadas en la emulación de procesos naturales de evolución. La principal
aportación de la Computación Evolutiva a la metodología de resolución de problemas, consiste
en el uso de mecanismos de selección de soluciones potenciales y de construcción de nuevos
candidatos por recombinación de características de otros ya presentes, de modo parecido a como
ocurre en la evolución de los organismos naturales. Entre esas técnicas destacan los Algoritmos
Genéticos y la Programación Evolutiva.
La Programación Evolutiva es una técnica de Computación Evolutiva útil para incorporar
conocimiento específico a los Algoritmos Genéticos y de esta forma mejorar la eficiencia de
éstos, ya que en los Algoritmos Genéticos se utilizan en gran medida datos pseudoaleatorios que
pueden llevar a una eficiencia muy pobre (e incluso no encontrar soluciones al problema en
cuestión). Pero estos datos pseudoaleatorios son los que dan genericidad a los Algoritmos
Genéticos, de forma que se pueden utilizar en muchos problemas de optimización; a veces, según
el problema en cuestión, puede que no se encuentre una solución óptima por los métodos
tradicionales (quizás por no estar bien condicionados) mientras que los algoritmos genéticos son
capaces de encontrarla. De esta forma, la Programación Evolutiva engloba la genericidad de los
Algoritmos Genéticos para encontrar soluciones e incorpora conocimiento específico para
generar eficiencia (encontrar más y mejores soluciones).
Por otro parte, la programación de juegos está convirtiéndose hoy en día en un creciente
campo donde se investigan y aplican tanto técnicas gráficas como complicados algoritmos que
provienen de campos tales como la Inteligencia Artificial y la Música Interactiva.
Con respecto a la algoritmia, en la programación de juegos se utilizan frecuentemente técnicas
de optimización para resolver numerosos problemas que se plantean, así como muchas otras
técnicas avanzadas y que no siempre se reconocen como tales: en realidad, todavía hay personas
que piensan que la programación de juegos es, como lo era antaño, una programación “sucia”
con muchos trucos para mejorar la velocidad, y sin uso apenas de algoritmos de organización.
Hoy en día las cosas han cambiado (con la mejora y avance de las computadoras, más
potentes, y de los lenguajes de programación y API´s, interfaces de programación de
aplicaciones) y estamos ante uno de los campos más enormemente ampliados y comercializados:
el mercado de los videojuegos.
Los avances en IA ya están impulsando el uso del big data debido a su habilidad para procesar
ingentes cantidades de datos y proporcionar ventajas comunicacionales, comerciales y
empresariales que la han llevado a posicionarse como la tecnología esencial de las próximas
décadas. Transporte, educación, sanidad, cultura... ningún sector se resistirá a sus encantos.
Desventajas
Por ser software, requieren de constantes actualizaciones (mantenimiento).
Realizar estos sistemas expertos requiere de mucho tiempo y dinero.
Crear máquinas que sean autosuficientes y puedan ir desplazando a la raza humana.
El uso irracional y exagerado de esta tecnología podría conllevar a la dominación de
las máquinas sobre el hombre, como también llegar a depender mucho de ellas.
El hombre se siente menos importante cuando una máquina o un sistema “lo supera”.
Hasta ahora hemos visto a grandes rasgos en que se basa la CE y el Pseudocódigo de los
algoritmos evolutivos, pero ¿Cómo representamos a los individuos?, ¿Cómo se reproducen y
mutan los individuos? y ¿Qué es eso de que un "individuo es suficientemente bueno”? Pues
vamos a responder a estas preguntas:
A grandes rasgos es así como funciona la reproducción humana, ya que uno al nacer hereda
unas características de la madre y otras del padre. Como se ve no se tiene porque heredar en
partes iguales las características de los dos progenitores.
Por último, en lo referente a la generación de nuevo individuos, existe la posibilidad de que
"Mute" algún gen; es decir, que sin ninguna "lógica" (aunque supongo que biológicamente la
tendrá) un determinado elemento del cromosoma cambie de valor, por ejemplo, al valor
complementario:
Ilustración 6 Mutación
como solución el individuo que mejor resultado nos haya dado con la función de
fitness.
La segunda estrategia se utiliza cuando sabemos el umbral de calidad que queremos
alcanzar para la solución del problema. En este caso se iran ejecutando generaciones
(una por una) y tras cada generación se evaluarán todos los individuos con la función
de fitness y si alguno cumple un determinado umbral de calidad, se parará de ejecutar
el algoritmo, al haber alcanzado una buena solución.
2.3.4. Aplicaciones
La Computación evolutiva constituye una de las áreas más activas de la llamada “inteligencia
computacional”, que agrupa además las redes neuronales y los sistemas difusos (del Inglés fuzzy
systems). Estas técnicas han logrado un gran número de aplicaciones exitosas en la industria y el
comercio. Los algoritmos evolutivos se han utilizado también como herramientas de modelaje y
resolución de problemas en las ciencias naturales.
Aunque a algunos les puede parecer asombroso y anti intuitivo, los algoritmos genéticos han
demostrado ser una estrategia enormemente poderosa y exitosa para resolver problemas,
demostrando de manera espectacular el poder de los principios evolutivos. Se han utilizado
algoritmos genéticos en una amplia variedad de campos para desarrollar soluciones a problemas
tan difíciles o más difíciles que los abordados por los diseñadores humanos. Además, las
soluciones que consiguen son a menudo más eficientes, más elegantes o más complejas que las
que un humano produciría.
este método, los cambios aleatorios pueden generarse cambiado el operador, alterando
el valor de un cierto nodo del árbol, o sustituyendo un subárbol por otro.
y un 1,5%, que son ``probabilidades razonables de detección y falsa alarma'' (p. 21). Esta red
evolucionada igualó las prestaciones de otra red desarrollada mediante recocido simulado, y
superó consistentemente a redes entrenadas mediante propagación hacia atrás, las cuales ``se
atascaban repetidamente en conjuntos de pesos subóptimos que no producían resultados
satisfactorios''. En contraste, ambos métodos estocásticos demostraron su capacidad para superar
estos óptimos locales y producir redes más pequeñas, efectivas y robustas; pero los autores
sugieren que el algoritmo evolutivo, a diferencia del recocido simulado, opera sobre una
población, y por tanto se beneficia de la información global sobre el espacio de búsqueda,
conduciendo potencialmente hacia un rendimiento mayor a la larga.
Ingeniería aeroespacial
Obayashi et al. 2000 utilizaron un algoritmo genético de múltiples objetivos para diseñar la
forma del ala de un avión supersónico. Hay tres consideraciones principales que determinan la
configuración del ala -minimizar la resistencia aerodinámica a velocidades de vuelo
supersónicas, minimizar la resistencia a velocidades subsónicas y minimizar la carga
aerodinámica (la fuerza que tiende a doblar el ala). Estos objetivos son mutuamente exclusivos, y
optimizarlos todos simultáneamente requiere realizar contrapartidas.
Astronomía y astrofísica
Charbonneau 1995 sugiere la utilidad de los AGs para problemas de astrofísica, aplicándolos
a tres problemas de ejemplo: obtener la curva de rotación de una galaxia basándose en las
velocidades rotacionales observadas de sus componentes, determinar el periodo de pulsación de
una estrella variable basándose en series de datos temporales, y sacar los valores de los
parámetros críticos de un modelo magnetohidrodinámico del viento solar. Son tres difíciles
problemas no lineales y multidimensionales.
El algoritmo genético de Charbonneau, PIKAIA, utiliza selección generacional y proporcional
a la aptitud, junto con elitismo, para asegurar que el mejor individuo se copia una vez hacia la
siguiente generación sin ninguna modificación. PIKAIA tiene un ritmo de cruzamiento de 0,65 y
un ritmo de mutación variable que se pone a 0,003 inicialmente y luego aumenta gradualmente,
mientras la población se aproxima a la convergencia, para mantener la variabilidad en el acervo
genético.
Química
Un pulso láser ultracorto de alta energía puede romper moléculas complejas en moléculas más
sencillas, un proceso con aplicaciones importantes en la química orgánica y la microelectrónica.
Los productos específicos de una reacción así pueden controlarse modulando la fase del pulso
láser. Sin embargo, para moléculas grandes, obtener la forma del pulso deseado de manera
analítica es demasiado difícil: los cálculos son demasiado complejos y las características
relevantes (las superficies de energía potencial de las moléculas) no se conocen con suficiente
precisión.
Assion et al. 1998 resolvieron este problema utilizando un algoritmo evolutivo para diseñar la
forma del pulso. En lugar de introducir información compleja, específica del problema, sobre las
características cuánticas de las moléculas iniciales, para diseñar el pulso conforme a las
especificaciones, el AE dispara un pulso, mide las proporciones de las moléculas producto
resultantes, muta aleatoriamente las características del rayo con la esperanza de conseguir que
estas proporciones se acerquen a la salida deseada, y el proceso se repite. (En lugar de afinar
directamente las características del rayo láser, el AG de los autores representa a los individuos
como un conjunto de 128 números, en el que cada número es un valor de voltaje que controla el
índice de refracción de uno de los pixeles del modulador láser. De nuevo, no se necesita un
conocimiento específico del problema sobre las propiedades del láser o de los productos de la
reacción). Los autores afirman que su algoritmo, cuando se aplica a dos sustancias de muestra,
``encuentra automáticamente la mejor configuración... no importa lo complicada que sea la
respuesta molecular'', demostrando un ``control coherente automatizado de los productos que son
químicamente diferentes uno del otro y de la molécula padre''.
Ingeniería eléctrica
Una matriz de puertas programable en campo (Field Programmable Gate Array, o FPGA), es
un tipo especial de placa de circuito con una matriz de celdas lógicas, cada una de las cuales
puede actuar como cualquier tipo de puerta lógica, interconectado con conexiones flexibles que
pueden conectar celdas. Estas dos funciones se controlan por software, así que, simplemente
cargando un programa especial en la placa, puede alterarse al vuelo para realizar las funciones de
cualquier dispositivo de hardware de la amplia variedad existente.
El Dr. Adrian Thompson ha explotado este dispositivo, en conjunción con los principios de la
evolución, para producir un prototipo de circuito reconocedor de voz que puede distinguir y
responder a órdenes habladas utilizando sólo 37 puertas lógicas -una tarea que se habría
considerado imposible para cualquier ingeniero humano. Generó cadenas aleatorias de bits de
ceros y unos y las utilizó como configuraciones de la FPGA, seleccionando los individuos más
aptos de cada generación, reproduciéndolos y mutándolos aleatoriamente, intercambiando
secciones de su código y pasándolo hacia la siguiente ronda de selección. Su objetivo era
evolucionar un dispositivo que pudiera en principio discriminar entre tonos de frecuencias
distintas (1 y 10 kilohercios), y luego distinguir entre las palabras habladas ``go'' (adelante) y
``stop'' (para).
Mercados financieros
Mahfoud y Mani 1996 utilizaron un algoritmo genético para predecir el rendimiento futuro de
1.600 acciones ofertadas públicamente. Concretamente, al AG se le asignó la tarea de predecir el
beneficio relativo de cada acción, definido como el beneficio de esa acción menos el beneficio
medio de las 1.600 acciones a lo largo del periodo de tiempo en cuestión, 12 semanas (un cuarto
del calendario) en el futuro. Como entrada, al AG se le proporcionaron datos históricos de cada
acción en forma de una lista de 15 atributos, como la relación precio-beneficio y el ritmo de
crecimiento, medidos en varios puntos del tiempo pasado; se le pidió al AG que evolucionara un
conjunto de reglas si/entonces para clasificar cada acción y proporcionar, como salida, una
recomendación sobre qué hacer con respecto a la acción (comprar, vender o ninguna predicción)
y un pronóstico numérico del beneficio relativo. Los resultados del AG fueron comparados con
los de un sistema establecido, basado en una red neuronal, que los autores habían estado
utilizando para pronosticar los precios de las acciones y administrar las carteras de valores
durante tres años. Por supuesto, el mercado de valores es un sistema extremadamente ruidoso y
no lineal, y ningún mecanismo predictivo puede ser correcto el 100% del tiempo; el reto consiste
en encontrar un predictor que sea preciso más de la mitad de las veces.
Juegos
Una de las demostraciones más novedosas y persuasivas de la potencia de los algoritmos
genéticos la presentaron Chellapilla y Fogel 2001, que utilizaron un AG para evolucionar redes
neuronales que pudieran jugar a las damas. Los autores afirman que una de las mayores
Ingeniería de materiales
Giro, Cyrillo y Galvão 2002 utilizaron algoritmos genéticos para diseñar polímeros
conductores de electricidad basados en el carbono, conocicos como polianilinas. Estos
polímeros, un tipo de material sintético inventado recientemente, tienen ``grandes aplicaciones
tecnológicas potenciales'' y podrían abrir la puerta a ``nuevos fenómenos físicos fundamentales''
(p. 170). Sin embargo, debido a su alta reactividad, los átomos de carbono pueden formar un
número virtualmente infinito de estructuras, haciendo que la búsqueda de nuevas moléculas con
propiedades interesantes sea del todo imposible. En este artículo, los autores aplican un enfoque
basado en AGs a la tarea de diseñar moléculas nuevas con propiedades especificadas a priori,
comenzando con una población de candidatos iniciales generada aleatoriamente. Concluyen que
su metodología puede ser una ``herramienta muy efectiva'' (p. 174) para guiar a los
investigadores en la búsqueda de nuevos compuestos y es lo suficientemente general para que
pueda extenderse al diseño de nuevos materiales que pertenezcan virtualmente a cualquier tipo
de molécula.
Matemáticas y algoritmia
Aunque algunas de las aplicaciones más prometedoras y las demostraciones más convincentes
de la potencia de los AGs se encuentran en el campo de la ingeniería de diseño, también son
relevantes en problemas ``puramente'' matemáticos. Haupt y Haupt 1998 describen el uso de
AGs para resolver ecuaciones de derivadas parciales no lineales de alto orden, normalmente
encontrando los valores para los que las ecuaciones se hacen cero, y dan como ejemplo una
solución casi perfecta para los coeficientes de la ecuación de quinto orden conocida como Super
Korteweg-de Vries.
Ejército y cumplimiento de la ley
Kewley y Embrechts 2002 utilizaron algoritmos genéticos para evolucionar planes tácticos
para las batallas militares. Los autores señalan que ``planear una batalla militar táctica es una
tarea compleja multidimensoinal que a menudo atormenta a los profesionales experimentados'',
no sólo porque este tipo de decisiones a menudo se toman bajo condiciones de mucho estrés,
sino también porque hasta los planes más sencillos requieren tomar en cuenta un gran número de
variables y consecuencias: minimizar las bajas amigas, maximizar las bajas enemigas, controlar
el terreno deseado, conservar recursos, etcétera. Los planificadores humanos tienen dificultades
al tratar con las complejidades de esta tarea y a menudo deben recurrir a métodos ``rápidos y
sucios'', como hacer lo que funcionase la última vez.
Para superar estas dificultades, los autores del artículo citado desarrollaron un algoritmo
genético para automatizar la creación de planes de batalla, en conjunción con un programa
gráfico de simulación de batallas. El comandante introduce el resultado deseado y el AG
evoluciona automáticamente un plan de batalla; en la simulación utilizada, se tomaron en cuenta
factores como la topografía del terreno, la cobertura vegetal, la velocidad del movimiento de
tropas, y la precisión en los disparos. En este experimento también se utilizó la coevolución para
mejorar la calidad de las soliciones: los planes de batalla de las fuerzas enemigas evolucionaron
simultáneamente con los planes amigos, forzando al AG a corregir cualquier debilidad de su plan
que pudiese explotar el enemigo. Para medir la calidad de las soluciones producidas por el AG,
se compararon con planes de batalla para el mismo escenario producidos por un grupo de
``expertos militares experimentados... considerados muy capaces de desarrollar planes de acción
para el tamaño de las fuerzas utilizadas en este experimento''. Estos avezados expertos
desarrollaron su propio plan y, cuando la solución del AG estuvo acabada, se les dio la
oportunidad de examinarla y modificarla como vieran conveniente. Finalmente, todos los planes
se ejecutaron varias veces en el simulador para determinar su calidad media.
Robótica
El torneo internacional RoboCup es un proyecto para promocionar el avance de la robótica, la
inteligencia artificial y los campos relacionados, proporcionando un problema estándar con el
que probar las nuevas tecnologías -concretamente, es un campeonato anual de fútbol entre
equipos de robots autónomos. (El objetivo fijado es desarrollar un equipo de robots humanoides
que puedan vencer al equipo humano de fútbol que sea campeón del mundo en 2050;
actualmente, la mayoría de los equipos de robots participantes funcionan con ruedas). Los
programas que controlan a los miembros del equipo robótico deben exhibir un comportamiento
complejo, decidiendo cuándo bloquear, cuándo tirar, cómo moverse, cuándo pasar la pelota a un
compañero, cómo coordinar la defensa y el ataque, etcétera. En la liga simulada de 1997, David
Andre y Astro Teller inscribieron a un equipo llamado Darwin United cuyos programas de
control habían sido desarrollados automáticamente desde cero mediante programación genética,
muy difícil y no hay tendencias de diseño bien establecidas''; como resultado, hoy existen varios
tipos de turbina distintos y no hay acuerdo sobre cuál es la óptima, si alguna lo es.
Deben tomarse en cuenta objetivos mutuamente exclusivos como la producción máxima de
energía anual y el coste mínimo de la energía.
En este artículo se utilizó un algoritmo evolutivo multiobjetivo para encontrar el mejor
conjunto de contrapartidas entre estos objetivos, construyendo palas de molino con una
configuración óptima de características como la velocidad de la punta de la pala, la razón
buje/punta, y la distribución de cuerda y giro. Al final, al AG consiguió encontrar soluciones
competitivas con los diseños comerciales, además de dilucidar más claramente los márgenes
entre los que se puede aumentar la producción anual de energía sin producir diseños demasiado
caros.
2.5 Mastemind
Mastermind (Español "Mente maestra") es un juego de mesa, de ingenio y reflexión, para dos
jugadores. Mastermind es actualmente una marca comercial propiedad de Pressman Toys; el
origen puede derivar de un juego tradicional inglés denominado Toros y vacas, se jugaba sobre
papel: los "toros" equivalían a las fichas negras, y las "vacas" a las blancas.
Ilustración 10 Mastermind
2.6. Metodologías
2.6.1. Metodología en Cascada
El modelo de desarrollo de Software en cascada, es una metodología de la programación
muy antigua. Si bien su creador nunca lo menciona como metodología en cascada, el
funcionamiento y lineamiento de los procesos de la planeación, son exactamente iguales.
Básicamente, el estilo del modelo en cascada, es que no podrás avanzar a la siguiente fase, si la
anterior no se encuentra totalmente terminada, pues no tiene por qué haber vuelta atrás. Vamos a
ver cuáles son las fases de desarrollo de software del modelo en cascada, para que te puedas dar
una idea.
1. Análisis de Requisitos. El primer nivel del modelo cascada, es el análisis de requisitos.
Básicamente lo que se documenta aquí, son los objetivos de lo que el software debe hacer
al terminar el desarrollo, sin entrar en detalles de la parte interna, los cuales se verán
durante el proceso. Sin embargo, es importante señalar que una vez avanzado el paso de
análisis, no puede haber vuelta atrás, pues la metodología para el diseño de software con
la cual se trabaja no lo permitirá.
2. Diseño del Sistema. Todo lo que conlleva el armado de un diseño para el sistema que
vayas a utilizar, es lo que continua después del análisis de requisitos. Aquí se elaborará lo
que es la estructura del sistema y se determinarán las especificaciones para cada una de las
partes del sistema que se planea desarrollar. Siendo del mismo modo, una fase a la cual ya
no se podrá volver después de haber bajado al nivel 3.
3. Diseño del Programa. En este punto, aún no ingresamos a lo que es la escritura de
código, sin embargo, ya se realizan los algoritmos que se van a utilizar en la
programación. Si bien recuerdas, un algoritmo no necesariamente es código, simplemente
tomas una hoja de papel y escribes el algoritmo que vas a utilizar. Esto es precisamente lo
que se realiza en el paso número 3.
4. Codificación. Seguramente como programador, esta es la parte que estabas esperando,
pues ahora es momento de empezar a escribir todo el código que será necesario para el
desarrollo del software. Para este punto, la velocidad y el tiempo que se requiera,
dependerá mucho del lenguaje de programación que vayas a utilizar. Pues algunos
lenguajes de programación permiten utilizar componente, bibliotecas e incluso algunas
funciones para reutilizar código, las cuales podrán acelerar el proceso de codificación en
gran manera.
5. Ejecución de Pruebas. La codificación ha terminado y ahora es momento de verificar
que nuestro sistema es realmente funciona, antes de que el cliente empiece a utilizarlo.
Este es precisamente el objetivo de la fase 5 de pruebas. Aquí es recomendable que
intentes mover lo más que se pueda tu software, con el objetivo de dañarlo
intencionalmente, de este modo, si supera las pruebas de daño realizadas por tí, entonces
estará listo para el usuario final.
6. Verificación. Después de haber realizado una gran cantidad de pruebas en la Fase 5,
debemos migrar a la verificación. Esta fase consiste en la ejecución del Software por parte
del usuario final. Si la fase cinco se realizó correcta y profundamente, el software no
tendrá ningún tipo de problema y el usuario final quedará satisfecho con el resultado.
7. Mantenimiento. Seguramente te has dado cuenta, de que las aplicaciones o el software
actual, constantemente se está actualizando. Esto se debe principalmente a que se le da
mantenimiento al software, se solucionan errores, se quitan algunos bugs, se añaden
funcionalidades, todo después de que el usuario final ya lo ha probado y utilizado en su
fase final. Esta es posiblemente una de las fases más tediosas del modelo de desarrollo de
software, pues debes estar atento a los comentarios de los usuarios, para ver qué cosas son
las que no funcionan correctamente y a las cuales hay que darles mantenimiento.
distintas, entonces lo que hacemos es crear un prototipo base y entorno al mostrarlo a nuestros
clientes para que de ahí se empiecen a desarrollar las demás funciones.
Mejor vamos a ver cuáles son las etapas de desarrollo de software por las cuales tendrás que
pasar, en caso de utilizar la metodología de prototipos.
1. Planeación. A diferencia de otras metodologías, la planeación debe ser muy rápida, en
esta fase no puedes demorarte mucho, pues recuerda que solamente será un prototipo por
el momento.
2. Modelado. Nuevamente, una fase que deberá ser suficientemente rápida como para que
no nos quite nada de tiempo. Hacer el modelado será simple y te sigo recordando que
solamente es un prototipo, al menos por ahora.
3. Elaboración del Prototipo. Ya que contamos con la planeación de lo que vamos a
realizar y el modelado rápido, entonces es momento de elaborar el prototipo. Para esta
instancia, ya no te diré que lo debes hacer rápido, puesto que te tomará el tiempo que
tenga sea necesario elaborarlo, recuerda que este ya se muestra al cliente, así que ya es una
fase importante.
4. Desarrollo. Posterior a contar con el prototipo elaborado y mostrado al cliente, es
momento de comenzar el desarrollo. Este te tomará una gran cantidad de tiempo,
dependiendo del tamaño del proyecto y el lenguaje de programación que se vaya a utilizar.
5. Entrega y Retroalimentación. Una de las cosas con las que cuenta el modelo de
prototipos, es que una vez entregado el proyecto, debemos darle al cliente cierta
retroalimentación sobre cómo utilizarlo y ciertamente es una fase que se encuentra dentro
de las etapas de desarrollo de software esta metodología.
6. Comunicación con el Cliente. Es importante que una vez entregado el proyecto,
tengamos cierta comunicación con el cliente, básicamente para que nos indique si el
proyecto es correcto o si desea agregarle ciertas funciones, nuestra metodología lo
permite. Si fuera en modo cascada, entonces sería algo realmente imposible de hacer.
7. Entrega del Producto Final. Por último, solamente quedará entregar el sistema elaborado
mediante esta metodología. Aquí tendrás la ventaja de que el código es reutilizable, para
que así con el prototipo ya puedas simplemente empezar de nuevo y con una buena base
de código que te acelerará el proceso.
3. Lista de Control. Es importante que conforme se vaya realizando cada iteración, se vaya
llevando un control del mismo en una lista. Como si fuera un programa que recibe
actualizaciones constantemente. Cada una de las actualizaciones o iteraciones deberá ser
documentada y de ser posible, guardada en sus respectivas versiones, para que sea sencillo
volver atrás, en caso de que una iteración no sea exitosa o el usuario ya no la requiera.
Identificador NF-02
Nombre Rendimiento
Descripción Se deberá optimizar dentro de lo posible el coste de ejecución de cada
una de las evoluciones, así como la ejecución completa del programa,
que finaliza con la obtención de la mejor solución.
Identificador NF-03
Nombre Lenguaje de programación
Descripción Se utilizará como lenguaje de programación Java, utilizando como
mínimo la versión de kit de desarrollo JDK 1.5
Identificador F-01
Nombre Configuración
Descripción Toda configuración del sistema se podrá realizar de forma rápida y a
través de un único fichero de configuración. Podrá ser mediante un
fichero de texto.
Identificador F-02
Nombre Ficheros externos
Descripción El sistema debe obtener los datos, tanto para los datos de pruebas o
entrenamiento y test, de ficheros externos en texto plano. Cada
individuo estará en líneas separadas por un retorno. Las
características de cada individuo deberán estar separadas mediante
comas, tabulaciones o espacios.
Identificador F-03
Nombre Fichero único
Descripción El sistema debe ser capaz de usar el mismo fichero tanto para
entrenamiento como para test, pudiendo usar la validación cruzada
definiendo el número de particiones si se trata de un único fichero para
todo.
Identificador F-04
Nombre Número de vecinos
Descripción El número de vecinos a evaluar utilizado por el algoritmo de búsqueda
debe ser configurable.
Identificador F-05
Nombre Evolución de la matriz
Descripción El sistema deberá permitir evolucionar la matriz con la que se optimiza
la fórmula del cálculo de la distancia en el algoritmo de búsqueda
de tres formas distintas:
- Completa: todos los elementos de la matriz formarán parte del
cromosoma del individuo a evolucionar.
- Simétrica: Sólo la diagonal y la parte superior formará parte del
cromosoma del individuo a evolucionar.
- Diagonal: Sólo la diagonal de la matriz formará parte del
cromosoma del individuo a evolucionar, el resto de los
elementos de la matriz serán 0.
Identificador F-06
Nombre Número de evoluciones
Descripción El número total de evoluciones o generaciones del algoritmo genético
se debe poder configurar para cada ejecución.
Identificador F-07
Nombre Desviación de la mutación
Descripción La desviación del operador de mutación debe ser configurable en cada
ejecución.
Identificador F-08
Nombre Tamaño de la población
Descripción El tamaño de la población total para el algoritmo genético debe ser
configurable.
a) Representación de la Población
La población está compuesta por:
• El componente fundamental de la población es un puntero al tipo población,
que es un vector de punteros al conjunto de individuos.
typedef vector<TIndividuo*> TPoblacion;
• Junto con el puntero al vector de punteros a individuos, el conjunto de
propuestas es la otra parte importante de la población. Todas las propuestas
que se hacen quedan almacenadas y ordenadas con respecto a los criterios
establecidos, en un vector de TPropuestas, que es una clase creada para
almacenar el código de la propuesta junto con el número de casillas bien
colocadas y de casillas, que sin estar bien colocadas, si están en la combinación
original.
• Además de las dos variables anteriores, se encuentran las típicas variables: la
posición en la que se encuentra el mejor individuo, el tamaño de la población,
el tamaño del elitismo, porcentaje de cruce, de mutación…,todos estos son
parámetros que se incluyen en una clase TParámetros dentro de población y
que se configuran fácilmente.
b) Generación de la Población.
• Generar la población llama a generar cada uno de los individuos y después de
crearlos se meten de manera adecuada en el vector población.
• Señalar que cada 10 iteraciones sin que se encuentra la solución hemos
tomado la determinación de renovar la población. Esto lo hemos hecho porque
puede que la población generada al inicio no nos aporte nada positivo, incluso
después de mutar, cruzar…..
c) Representación de los individuos.
• Vamos a detenernos en describir cada individuo generado. Un individuo tiene
como parte fundamental el código que lo distingue. Dicho código se almacena
en un puntero a una clase TCodigo, clase que a su vez define un tipo
numerado con todos los posibles valores para los componentes de una posible
combinación (blanco, negro, verde, azul y rojo). Un individuo, por lo tanto, no
es ni más ni menos que una combinación de colores, la que lo determina y
también es importante llevar una variable que nos indique lo que se parece el
nuevo individuo a las propuestas utilizadas.
typedef enum {blanco,negro,rojo,verde,azul,ninguno1,ninguno2}TColores;
vector<TColores>* codigo; /*Un puntero a un vector de colores*/
• Los valores ninguno1 y ninguno2 nos sirven, únicamente y exclusivamente,
para poder hacer comparaciones entre distintas combinaciones (para más
detalle ir al código).
d) Generación de los Individuos.
• La generación de los individuos no tiene nada que reseñar. Lo único que se
hace es establecer de manera aleatoria la combinación de colores que va a
representar a dicho individuo.
e) Función de Adaptación
• Es bastante importante elegir de manera adecuada la función de adaptación
para que las soluciones, en modo de propuestas, converjan de manera
adecuada a la combinación secreta. Son muchas las funciones de adaptación
que hemos probado, eso sí, siempre teniendo en cuenta las pistas que el
usuario nos ha dado con anterioridad.
• Está claro que de algún modo, hay que tener en cuenta las propuestas que se
han realizado y lo buenas que han sido estas. Para ello, el vector de propuestas
con el que contamos se ordena atendiendo al número de casillas bien puestas y
en el lugar correcto. Esto quiere decir que al final no hemos optado por tener
en cuenta las casillas que coinciden con las casillas de la combinación secreta,
pero no están en el mismo lugar (vimos que no aportaban una mayor velocidad
de convergencia). También hemos ignorado, por razones obvias, posibles
combinaciones repetidas. La función de adaptación utilizada tiene la siguiente
forma:
Ilustración 12 Prototipo MM
Ilustración 17 IA Mastermind
Ilustración 18UML IA
Ilustración 19 common
Ilustración 20 GUI
Ilustración 21 Game
package ai;
import common.*;
import game.ControlInterface;
import java.util.ArrayList;
/**
* Un algoritmo de resolución genética.
* Esta implementación es una versión ligeramente modificada de la del documento:
* <a href="https://lirias.kuleuven.be/bitstream/123456789/164803/1/KBI_0806.pdf">
* Soluciones eficientes para Mastermind usando algoritmos genéticos </a>
* <br/> Para más información sobre algoritmos genéticos ver:
* <a href="http://en.wikipedia.org/wiki/Genetic_algorithm">
* Algoritmo genético en Wikipedia </a>
*/
public class GeneticSolver implements SolvingAlgorithm {
/**
* Tamaño de la población dentro de una generación.
*/
private final int POPULATION_SIZE = 2000;
/**
* Número de generaciones. Si no se encontró ningún código factible después de todas las
* generaciones, una nueva conjetura con nuevas generaciones y poblaciones será
* hecha.
*/
private final int GENERATION_SIZE = 500;
/**
* Max. Cantidad de códigos factibles. Los códigos factibles son buenas conjeturas. Si el
* max. Se encuentran códigos viables, el solucionador se detiene y da un giro con
* Un código factible elegido al azar.
*
* @ver #addToFeasibleCodes ()
*/
private final int FEASIBLE_CODES_MAX = 1;
private ControlInterface ci;
private int width;
private int colorQuant;
private boolean doubleColors;
private Row[] population = new Row[POPULATION_SIZE];
private int[] fitness = new int[POPULATION_SIZE];
private int[] blacks;
private int[] whites;
/**
* Inicializa la IA con la configuración del motor Mastermind.
*
* @param ci Una interfaz de control que la IA utilizará para
* interactuar con un juego.
*/
public GeneticSolver(ControlInterface ci) {
this.ci = ci;
width = ci.getSettingWidth();
colorQuant = ci.getSettingColQuant();
doubleColors = ci.getSettingDoubleCol();
population = new Row[POPULATION_SIZE];
fitness = new int[POPULATION_SIZE];
blacks = new int[ci.getSettingMaxTries()];
whites = new int[ci.getSettingMaxTries()];
initResults();
}
/**
* Inicialice los arrays "negros" y "blancos" con valores del
* GameField. Las matrices "negros" y "blancos" son necesarios para acelerar
* el procesamiento.
*/
public void initResults() {
for (int i = 0; i < ci.getActiveRowNumber(); i++) {
blacks[i] = ci.getResultRow(i)
.containsColor(Color.Black);
whites[i] = ci.getResultRow(i)
.containsColor(Color.White);
}
}
/**
* Hacer una conjetura completa en el motor de Mastermind.
* Esto incluye para generar una conjetura, pasarla al motor.
* y hacer un turno de juego completo.
*
* @return -1 = El juego terminó y el código no se rompió. <br />
* 1 = El juego terminó un código se rompió. <br />
* 0 = Solo un turno normal o el juego ya terminó.
* @ver ControlInterface # turno ()
*/
/**
* Crea nuevas generaciones hasta que se encuentren suficientes códigos elegibles.
*
* @return Una conjetura elegible.
*
* @see #initPopulation ()
* @see #calcFitness ()
* @see #sortFeasibleByFitness (int [], common.Row [])
* @ver #evolvePopulation ()
* @ver #addToFeasibleCodes ()
*/
public Row generateGuess() {
Row guess = new Row(width);
boolean doCalc;
// ¿Primero adivinar?
if (ci.getActiveRowNumber() == 0) {
return generateRndGuess();
}
do {
int genNumber = 0;
doCalc = true;
initPopulation();
calcFitness();
sortFeasibleByFitness(fitness, population);
/**
* Evolucionar la población usando cruzamiento, mutación, permutación e
* inversión.
* 0.5 probabilidad para xOver1 y xOver2
* después del cruce
* 0.03 probabilidad de mutación
* 0.03 posibilidad de permutación
* 0.02 posibilidad de inversión.
*
* <a href="http://en.wikipedia.org/wiki/Genetic_algorithm#Reproduction">
* Reproducción </a>
*
* @see # xOver1 (common.Row [], int, int)
* @see # xOver2 (common.Row [], int, int)
* @see #mutation (common.Row [], int)
* @see #permutation (common.Row [], int)
* @see #inversion (common.Row [], int)
*/
private void evolvePopulation() {
Row[] newPopulation = new Row[POPULATION_SIZE];
for (int i = 0; i < POPULATION_SIZE; i++) {
newPopulation[i] = new Row(width);
}
for (int i = 0; i < POPULATION_SIZE; i += 2) {
if ((int) (Math.random() * 2) == 0) {
xOver1(newPopulation, i, i + 1);
} else {
xOver2(newPopulation, i, i + 1);
}
}
doubleToRnd(newPopulation);
population = newPopulation;
}
/**
* Un código c es elegible o factible si resulta en los mismos valores para
* Xk e Yk para todas las conjeturas k que se han jugado hasta esa etapa,
* Si c era el código secreto. <br />
* X es el número de coincidencias exactas. Y es el número de conjeturas que son
* El color correcto pero en la posición incorrecta.
*
* @return False si factibleCodes está lleno. De lo contrario es cierto.
*/
private boolean addToFeasibleCodes() {
outer:
for (int i = 0; i < POPULATION_SIZE; i++) {
for (int j = 0; j < ci.getActiveRowNumber(); j++) {
int[] result = compare(population[i],
ci.getGameFieldRow(j));
return true;
}
/**
* Sustituye elementos dobles en newpopulation.
*
* @param newPopulation La matriz de población que se manipulará.
*/
private void doubleToRnd(Row[] newPopulation) {
for (int i = 0; i < POPULATION_SIZE; i++) {
if (lookForSame(newPopulation, i) == true) {
newPopulation[i] = generateRndGuess();
}
}
}
/**
* Busque las filas que son iguales a la fila en popPos en newPopulation.
*
* @param newPopulation La matriz de población que se buscará.
* @param popPos La posición de la fila dentro de la matriz de población que
* serán comparados.
* @return true si se encuentra una fila igual. falso si no se encuentra una fila igual.
*/
private boolean lookForSame(Row[] newPopulation, int popPos) {
for (int i = 0; i < POPULATION_SIZE; i++) {
if (population[popPos].equals(newPopulation[popPos]) == true) {
return true;
}
}
return false;
}
/**
* Mutación. Reemplaza el color de una posición elegida al azar por un azar
* otro color.
*
* @param newPopulation La matriz de población que se manipulará.
* @param popPos La posición de la fila dentro de la matriz de población que
* sera cambiado.
*/
private void mutation(Row[] newPopulation, int popPos) {
newPopulation[popPos].setColorAtPos((int) (Math.random() * width),
Color.values()[(int) (Math.random() * colorQuant)]);
}
/**
* Permutación. Los colores de dos posiciones aleatorias se cambian.
*
* @param newPopulation La matriz de población que se manipulará.
* @param popPos La posición de la fila dentro de la matriz de población que
* sera cambiado.
*/
private void permutation(Row[] newPopulation, int popPos) {
int pos1 = (int) (Math.random() * width);
int pos2 = (int) (Math.random() * width);
Color tmp = newPopulation[popPos].getColorAtPos(pos1);
newPopulation[popPos].setColorAtPos(pos1,
newPopulation[popPos].getColorAtPos(pos2));
newPopulation[popPos].setColorAtPos(pos2, tmp);
}
/**
* Inversión. Se seleccionan aleatoriamente dos posiciones, y la secuencia de colores.
* Entre estas posiciones se invierte.
*
* @param newPopulation La matriz de población que se manipulará.
* @param popPos La posición de la fila dentro de la matriz de población que
* sera cambiado.
*/
private void inversion(Row[] newPopulation, int popPos) {
int pos1 = (int) (Math.random() * width);
int pos2 = (int) (Math.random() * width);
/**
* Cruce de un punto. Un único punto de cruce en el organismo de ambos padres.
* Se seleccionan cadenas. Todos los datos más allá de ese punto en cualquier cadena de
organismos.
* Se intercambia entre los dos organismos progenitores. Los organismos resultantes son
* los niños.
*
* <a href="http://en.wikipedia.org/wiki/Crossover_%28genetic_algorithm%29#One-
point_crossover">
* Un punto de cruce </a>
*
* @param newPopulation La matriz de población que se manipulará.
* @param child1Pos La posición de una fila dentro de la matriz de población que
* sera cambiado.
* @param child2Pos La posición de una fila dentro de la matriz de población que
* sera cambiado.
*/
private void xOver1(Row[] newPopulation, int child1Pos, int child2Pos) {
int mother = getParentPos();
int father = getParentPos();
int sep = ((int) (Math.random() * width)) + 1;
/**
* Cruce de dos puntos. Se seleccionan dos puntos en el organismo parental.
* cuerdas. Todo entre los dos puntos se intercambia entre los padres.
* Organismos, prestando dos organismos infantiles.
*
* <a href="http://en.wikipedia.org/wiki/Crossover_%28genetic_algorithm%29#Two-
point_crossover">
* Cruce de dos puntos </a>
*
* @param newPopulation La matriz de población que se manipulará.
/**
* Getter para una buena posición de los padres en la población.
* En este caso se utiliza el de la quinta parte de la mejor población.
* Es importante que solo los padres con un buen valor físico estén acostumbrados a
* Generar la siguiente generación.
*
* @return Una posición en el primer quinto de la matriz de población
* sucesivamente aumentando.
*/
/**
* Calcula la condición física de cada fila en la población.
* Un valor de aptitud y el elemento correspondiente de la matriz de población
* Ambos tienen el mismo índice en sus matrices respectivas.
*
* Debe parecerse a la función como se describe en el documento:
* <a href="https://lirias.kuleuven.be/bitstream/123456789/164803/1/KBI_0806.pdf">
* Soluciones eficientes para Mastermind usando algoritmos genéticos </a>
* en la página 6.
*/
private void calcFitness() {
int xtmp;
int ytmp;
for (int i = 0; i < POPULATION_SIZE; i++) {
xtmp = 0;
ytmp = 0;
for (int j = 0; j < ci.getActiveRowNumber(); j++) {
int[] result = compare(
population[i], ci.getGameFieldRow(j));
xtmp += Math.abs(result[0] - blacks[j]);// + ancho * j;
ytmp += Math.abs(result[1] - whites[j]);// + ancho * j;
}
fitness[i] = (xtmp + ytmp);
}
}
/**
* Compara dos filas.
* el resultado [0] se incrementa si un valor igual (color) se encuentra en una posición
igual.
* el resultado [1] se incrementa si un valor igual es una posición diferente.
* resultado [0] son las clavijas negras.
* resultado [1] son las clavijas blancas.
* <a
href="http://en.wikipedia.org/wiki/Mastermind_%28board_game%29#Gameplay_and_rules">
outer:
for (int i = 0; i < width; i++) {
if (code[i] != null) {
for (int j = 0; j < width; j++) {
if (code[i] == secret[j]) {
result[1]++;
secret[j] = null;
continue outer;
}
}
}
}
return result;
}
/**
* Inicializa la población con filas aleatorias.
* factibleCodes se purgan.
*/
private void initPopulation() {
// Inicia poblacion con conjeturas al azar.
int i = 0;
feasibleCodes.clear();
/**
* Genera una fila con colores aleatorios.
* Genera una fila con la configuración de ancho actual. Los colores disponibles son
* determinado por la configuración de colorQuant. Si la configuración de doble color
* es falso, solo se establecen diferentes colores. <br />
* <b> Advertencia: </b> el uso de esta función puede llevar hasta
* varios minutos, especialmente si ha configurado un ancho alto,
* Muchos colores o cuando ejecutas el juego en una computadora lenta.
* Esto no es un error, solo un efecto secundario del complejo
* algoritmo que la IA está utilizando.
*
* @return A Row con colores aleatorios.
*/
private Row generateRndGuess() {
Row guess = new Row(width);
// Preparar valores para ajustar colorQuant-rule
Color[] values = new Color[colorQuant];
Color[] all = Color.values();
System.arraycopy(all, 0, values, 0, colorQuant);
// Hacer la generación de código real ...
int i = 0;
while (i < width) {
Color now = values[(int) (Math.random() * colorQuant)];
if (guess.containsColor(now) > 0) {
if (doubleColors == true) {
guess.setColorAtPos(i++, now);
}
} else {
guess.setColorAtPos(i++, now);
}
}
return guess;
}
/**
* Este es un Quicksort que clasifica los Arreglos de fitness y pop según los criterios
* En el gimnasio.fitness-array.
*
* @param fitness Una matriz int.
/**
* Función auxiliar para la ordenación recursiva.
*
* @param fitness Una matriz int.
* @param pop Una matriz de Filas.
* @param low El límite inferior.
* @param up El límite superior.
*/
private void sort(int[] fitness, Row[] pop, int low, int up) {
int p = (low + up) / 2;
if (up > low) {
//Feld zerlegen
int pn = divide(fitness, pop, low, up, p);
//und sortieren
sort(fitness, pop, low, pn - 1);
sort(fitness, pop, pn + 1, up);
}
}
/**
* Función auxiliar para partición.
*
* @param fitness Una matriz int.
* @param pop Una matriz de Filas.
* @param low El límite inferior.
* @param up El límite superior.
* @param pivot La posición del elemento Pivot.
* @return La nueva posición del elemento Pivot.
*/
private int divide(int[] fitness, Row[] pop, int low, int up, int pivot) {
int pn = low;
int pv = fitness[pivot];
swap(fitness, pivot, up);
swap(pop, pivot, up);
for (int i = low; i < up; i++) {
/**
* Función auxiliar para intercambiar dos elementos de una matriz int.
*
* @param fitness Una matriz int.
* @param a Posición del primer elemento.
* @param b Posición del segundo elemento.
*/
private void swap(int[] fitness, int a, int b) {
int tmp = fitness[a];
fitness[a] = fitness[b];
fitness[b] = tmp;
}
/**
* Función auxiliar para intercambiar dos elementos de una matriz de Filas.
*
* @param pop Una matriz de Filas.
* @param a Posición del primer elemento.
* @param b Posición del segundo elemento.
*/
private void swap(Row[] pop, int a, int b) {
Row tmp = pop[a];
pop[a] = pop[b];
pop[b] = tmp;
}
/**
* Prueba de velocidad.
*
* Repeticiones @param Repeticiones de resolver un juego.
*/
public void geneticSolverTest(int repetitions){
long start = System.currentTimeMillis();
long durationLongest = 0;
long durationShortest = 4000000;
int gamewon = 0;
int gamelost = 0;
double guess = 0;
do {
game = makeGuess();
guess++;
} while (game == 0);
if (game == 1) {
gamewon++;
} else {
gamelost++;
}
System.out.println("##################\nResultados de referencia:");
System.out.println("Repeticiones: " + repetitions);
System.out.println("Duracion en ms: " + duration);
System.out.println("Duracion en s: " + (duration/1000f));
System.out.println("Duracion en m: "+ (duration/1000f/60));
System.out.println("Tiempo promedio de resolución en ms: "
+ (duration/repetitions));
System.out.println("Tiempo medio de resolución en s: "
+ (duration/1000f/repetitions));
System.out.println("Más corto en ms: "+ durationShortest);
System.out.println("Más largo en ms: "+ durationLongest);
System.out.println("Más corto en s: "+ durationShortest/1000f);
Conclusiones
En este trabajo solo se presentó la parte de Marco Teórico del Proyecto y los Objetivos a
desarrollarse, en el marco teórico vimos lo que es la inteligencia artificial y las ventajas y
desventajas que nos brindan en la actualidad, y conocimos varios dispositivos que hoy en día
gozan de IA. Como hemos podido ver a lo largo del documento los algoritmos genéticos son
actualmente una fuerte fuente de resolución de problemas complejos al realizar su ejecución en
paralelo pudiendo así obtener diferentes soluciones a problemas.
Sin embargo, como se ha podido observar, no hay ninguna estrategia que sea siempre
invencible, sino que hay un conjunto de estrategias que suelen dar buenos resultados. Así pues,
habrá que ajustar los parámetros de acción en función de cada problema a modelar para obtener
una solución que se adapte mejor a unas determinadas condiciones. Sin embargo, en una
situación real puede suceder que no se conozcan los parámetros iniciales o que no se sepa la
duración del algoritmo. Por lo tanto, habrá que elegir con sumo cuidado los parámetros iniciales.
Bibliografía y Referencias
Bibliografía
[1] D. E. Knuth, “The computer as master mind,” Journal of Recreational
Mathematics, vol. 9, pp. 1–6, 1976-77.
[2] L. Berghman, D. Goossens, and R. Leus, “Efficient solutions for mastermind
using genetic algorithms,” Computers & operations research, vol. 36, no. 6, pp. 1880–
1885, 2009.
[3] A. Singley, “Heuristic solution methods for the 1-dimensional and 2- dimensional
mastermind problem,” Ph.D. dissertation, UNIVERSITY OF FLORIDA, 2005.
[4] J. Merelo-Guervós, P. Castillo, and V. Rivas, “Finding a needle in a haystack using
hints and evolutionary computation: the case of evolutionary mastermind,” Applied
Soft Computing, vol. 6, no. 2, pp. 170–179, 2006.
[5] J. H. Holland, Adaptation in Natural and Artificial Systems, 1st ed. Ann Arbor,
Michigan: University of Michigan Press, 1975.
[6] D. E. Goldberg, Genetic Algorithms in Search, Optimization and Machine
Learning.
Referencias
[1] http://es.wikipedia.org/wiki/Algoritmo_gen%C3%A9tico
[2] http://www.redcientifica.com/doc/doc199904260011.html
[3] http://geneura.ugr.es/~jmerelo/ie/ags.htm
[4] http://www.lsi.upc.es/~iea/transpas/9_geneticos/index.htm
[5] http://casa.ccp.servidores.net/genetico.html
[6] http://homepage.sunrise.ch/homepage/pglaus/gentore.htm#A
[7] http://the-geek.org/docs/algen/
[8] http://www.rennard.org/alife/english/gavgb.html