codigo para juego de azar

46
8 5

Upload: alto-nativo

Post on 28-Nov-2015

67 views

Category:

Documents


10 download

TRANSCRIPT

Solución al Problema de MasterMind utilizando Algoritmos Genéticos

Roberto Loaeza Valerio

6 de Agosto de 2007

Resumen

En este documento se presenta la implementación de algoritmos gené-ticos para descubrir información que permita jugar y ganar en el juegoMasterMind. Este juego tiene un número máximo de jugadas (diez en estecaso) antes de fallar y para generar una jugada se tienen 85 posibles se-cuencias lo cual vuelve al juego muy complicado. Sin embargo se mostraránresultados que muestran que al utilizar algoritmos genéticos se puede ganaren un maximo de 6 jugadas.

1. Introducción

MasterMind es un juego de meza para dos jugadores donde uno gene-ra un código y otro intenta descifrarlo, inventado en 1970 por MordecaiMeirowitz.El juego consta básicamente de:

Un tablero para ir �jando jugadas y cali�caciones como se muestra enla �gura 1.

Un conjunto de 8 colores con el cual se genera tanto el código comoel intento(jugada).

Un conjunto adicional de colores para cali�car, blanco y negro (susigni�cado se detallará más adelante).

Un conjunto de acciones de�nidas para los jugadores.

Las acciones que pueden realizar los jugadores se listan a continuación:

Generador de código (CodeMaker):

• Genera una secuencia (código) de cinco colores a partir del con-junto de colores originales como se muestra en la �gura 2.

• Cali�ca cada intento del CodeBraker en base a su código y setienen dos casos:

◦ Si el color en una posición es el mismo en ambos (código eintento) se cali�ca con una bolita negra, estas son acumu-lativas, es decir si hay tres colores en la misma posición enambas secuencias se cali�ca con tres bolitas negras.

◦ Si un color se encuentra en ambos (código e intento) pero endiferente posición se cali�ca con una bolita blanca, estas sonacumulativas, es decir si hay tres colores iguales en ambassecuencias pero en diferentes posiciones se cali�ca con tresbolitas blancas.

Rompedor de código (CodeBraker):

• Genera una secuencia (intento) de cinco colores a partir del con-junto de colores inicial como se muestra en la �gura 2, y se la daal CodeMaker para que este la cali�que.

El CodeBraker tiene un número máximo de intentos para descifrar lasecuencia del CodeMaker.

1

Figura 1: Tablero de MasterMind

Como las jugadas se generan a partir del conjunto de colores (de ochoelementos) y se tienen cinco de ellos en cada intento, existen entonces85 (32768) secuencias posibles para cada intento, sería muy poco viablegenerar una jugada aleatoriamente y presentarsela al CodeMaker por loque para tener éxito en este juego se debe de seguir patrones basados enla respuesta que proporciona el CodeMaker.

Para poder seguir un patron primero debemos tener nuestra propia fun-ción de evaluación (que simulará ser el CodeMaker) y a partir del primerintento cada nueva secuencia deberá ser consistente con todas las anteriorespara ser candidata a intento/jugada.

Figura 2: Generador de códigos

Teniendo en cuenta que se debe seguir patrones y se tiene un númeromáximo de intentos, una técnica de resolverlo de forma muy ilustrativason los algoritmos genéticos aplicando los siguientes operadores geneticos:cruza, mutación circular y transposición.La implementación de algoritmos genéticos se realizó en Java y para una

mayor portabilidad la interfaz grá�ca de usuario (IGU) se realizó en Java+ Ewe VM.

2. Implementación

Como la solución esta basada algoritmos genéticos es necesario contarcon los siguientes métodos:

Crear Población.

Fitness (consistencia).

Seleccionar un individuo.

Cali�car un individuo.

Operadores Genéticos (cruza, mutación circular, transposición, hiper-mutación).

La implementación se dividio en dos paquetes: ga y masterMind; donde gacontiene las clases necesarias para implementar las funciones mencionadasanteriormente y por su parte masterMind es la interfaz grá�ca de usuario.

2

El código fuente se lista en los apendices A y B respectivamente paraambos paquetes.

2.1. Paquete ga

En este paquete se conforma por tres clases que se describen a continua-ción.

2.1.1. MasterMindBase

Es el núcleo de la implementación y cuenta con:

La representacion de los coloresSe hizo mediante un arrego de char: char colores[] = {'0', '1', '2', '3','4', '5', '6', '7' } donde cada número representa un color especí�co.

Longitud de la combinacionSe de�nio igual a cinco: static int L = 5.

Crear combinación aleatoriaEsta se genera a partir del arreglo de colores y es de longitud L, lageneración es aleatoria.

Cantidad de poblaciónSe de�nio igual a 200: int nPob = 200, pero puede ser modi�cadomendiante las opciones de la IGU.

PoblaciónSe almacenan en un arreglo bidimensional: char[][] poblacion.

Historia de jugadasSe almacenan en un arreglo bidimencional: char[][] historia;

Numero de intentos antes de perderSe de�nio igual a diez: int J = 10, pero puede ser modi�cado mediantelas opciones de la IGU.

Porcentaje de mutacion (crossover, mutacion circular, transposicion)Estos porcentajes se �jaron de la siguiente forma: 40, 20, 40 respec-tivamente. Estos pueden ser modi�cados mediante las opciones de laIGU.

Cali�cacion de una jugada con respecto al código secretoSe realiza en dos fases: primero se reviza por colores iguales en mismaposición (código y jugada), y �nalmente se reviza por colores igualesen posiciones diferentes.

Fitness, es la consistencia de un individuo de la población con res-pecto a la historia de intentos. Se calcula mediante[Merelo-Guervos]:

Fitness =n∑

i=1

−[Abs

(Pnb− hnbi

)+ Abs

(Pnw − hnwi

)](1)

Quicksort. Algoritmo de ordenamiento, se utiliza para ordenar la po-blación de forma decreciente en base al �tness.

2.1.2. MasterMindOperadoresGeneticos

MasterMindOperadoresGeneticos, implementa:

CruzaDos padres se eligen en la cruza y una porción de cada uno se inter-cambia para generar dos nuevos hijos, como se muestra en la �gura 3.Su código se lista a continuación.La porción que se intercambiara es generada al azar mediante dosnúmeros aleatorios.

Mutacion CircularEn la mutación circular un padre se elige aleatoriamente y se inter-cambia un cromosoma (también elegido aleatoriamente) por el valorsiguiente. O si éste es el último valor, se sustituye por el primerocorrespondiente. En la �gura 4 se puede apreciar este operador (don-de los valores para un cromosoma son { 0, 1, 2, 3, 4, 5, 6, 7 }).

TransposicionEn la operación genética de transposición, un padre se elige aleato-riamente y se intercambian aleatoriamente todos sus cromosomas porvalores que ya contiene, es decir, sólo se �revuelve� su código. Esteoperador se ilustra en la �gura 5.

3

HipermutacionEsta operación se realiza cuando la población a pasado el número má-ximo de generaciones sin encontrar un candidato consistente y consis-te en reiniciar la población, es decir: la población se vuelve a generaraleatoriamente.

Figura 3: Cruza

Figura 4: Mutación circular

La porción de individuos a la que se le aplica cada uno de los operadoresgeneticos es heredada de MasterMindBase por lo tanto puede ser facilmentemodi�cada mediante la IGU.Además de contar con la implementación propia también contiene todas

las implementaciones de MasterMindBase

2.1.3. MasterMind

Esta clase implementa las siguientes funciones:

Figura 5: Transposición

JugarEsta función se utilizó para mostrar resultados sin interfaz grá�ca.

JugarOP(Tablero, codeMaker, codeBraker)Esta función permite jugar MasterMind en las siguientes modalidades:

• CodeMaker = Humano y CodeBraker = Humano

• CodeMaker = Humano y CodeBraker = PC

• CodeMaker = PC y CodeBraker = Humano

• CodeMaker = PC y CodeBraker = PC

Además de contar con la implementación propia también contiene todaslas implementaciones de MasterMindOperadoresGeneticos

2.2. Paquete masteMind

Este paquete contiene las siguientes clases

2.2.1. MasterMindGUI

Es el núcleo de la interfaz grá�ca. Contiene un menú para acceder alas opciones e iniciar juegos nuevos. Esta interfaz se puede observar en la�gura 1.

2.2.2. GenerarCodigo

Esta clase permite interactuar al usuario para que este genere un códigoa partir del conjunto de colores como se muestra en la �gura 2.

4

2.2.3. Jugada

Es la interfaz para manipular el conjunto de colores y generar una se-cuencia.

2.2.4. Cali�cación

Permite al usuario interactuar y muestra una interfaz donde el usuariopuede cali�car como se muestra en la �gura 6.

Figura 6: Cali�cando una jugada

2.2.5. Cali�cador

Es la interfaz para manipular el conjunto de colores (negro y blanco)para generar una cali�cación.

2.2.6. Opciones

Permmite al usuario modi�car los valores con los que trabajara la apli-cación. Como se muestra en la �gura 7.

2.2.7. Tablero

Implementa un tablero para �jar las jugadas y cali�caciones. Esta inter-faz se puede observar en la �gura 1.

Figura 7: Modi�cando valores

3. Resultados

A continuación se muestran algunas pruebas realizadas a la implemen-tación. La con�guración utilizada se muestra en la tabla 1 y los resultadosobtenidos en 500 corridas se muestra en la tabla 2.

Población 200Número máximo de Intentos 10

Número de generaciones antes de hipermutación 15Porcentaje de población que recibirá el operador de cruza 40

Porcentaje de población que recibirá el operador de transposición 40Porcentaje de población que recibirá el operador de mutación circular 20

Número máximo de hipermutaciones 200

Tabla 1: Con�guración de Prueba

5

Mejor Tiempo de un Juego 1 milisengundoPeor Tiempo de un Juego 819 milisegundos

Mejor Jugada (intentos para ganar) 3Peor Jugada (intentos para ganar) 9

Promedio de Juegos ganados 100% de 500 juegosTiempo total 20824 milisegundos

Promedio de jugadas (intentos para ganar) 5.8

Tabla 2: Resultados de Prueba

4. Conclusiones

Se realizó satisfactoriamente la implementación de algoritmos genéti-cos para resolver el juego de MasterMind.

Se observó que el potencial de los algoritmos genéticos es enorme, yaque de tener 85 (32768) posibles secuencias por jugada y un máximode 10 jugadas, se logra ganar al 100% en 5.8 jugadas WoW!!.

La implementación adicional de Ewe le da un nuevo alcance a lasaplicaciones java, ya que se puede ejecutar en casi cualquier dispositivocomputacional.

Referencias

[wiki] http://es.wikipedia.org/wiki/Mastermind.

[Merelo-Guervos] J. J. Merelo-Guervós, P. Castillo y V. M. Rivas. �Fin-dind a needle in a haystack using hints and evolutionarycomputation: the case of evolutionary MasterMind�. El-sevier, pags. 170-179. 2006.

6

APENDICE A: Paquete ga

ga.MasterMindBase.java

package ga;

import ewe.util.Random;

/**

* MasterMindBase, contiene:

* <br>** La representacion de los colores

* <br>** Longitud de la combinacion

* <br>** Historia de jugadas

* <br>** Numero de intentos antes de perder

* <br>** Cantidad de poblacion

* <br>** Porcentaje de mutacion (crossover, mutacion circular, transposicion)

* <br>** Calificacion de una jugada con respecto al codigo secreto

* <br>** Crear combinacion aleatoria

* @author Roberto Loaeza Valerio

*

*/

public class MasterMindBase {

/**

* Nombre de colores

*/

char colores[] = {'0', '1', '2', '3', '4', '5', '6', '7'};

/**

* Codigo Secreto

*/

private char[] codigo;

/**

* Cantidad de colores disponibles

*/

private int N = 8;

/**

* Caracteres adicionales al codigo: D, W, B.

*/

7

private int cAux = 3;

/**

* Longitud de combinacion

*/

public static int L = 5;

/**

* Cantidad de poblacion

*/

public int nPob = 400;

/**

* Maximo numero de jugadas

*/

public int J = 10;

/**

* Numero de generaciones sin tener una combinacion consistente antes de hacer Hipermutacion

*/

public int nH = 15;

/**

* Porcentaje de cruza

*/

public int nC =40;

/**

* Porcentaje de transposicion

*/

public int nT = 20;

/**

* Porcentaje de mutacion circular

*/

public int nM =40;

/**

* Numero maximo de hipermutaciones

*/

public int nR = 200;

/**

* Jugadas Realizadas

*/

8

public int nJ=0;

/**

* Historia de jugadas realizadas

*/

public char[][] historia;

/**

* Poblacion

*/

private static char[][] poblacion;

/**

* Aleatorio

*/

public Random r = new Random();

/**

* Crea una combinacion

* @return Nueva combinacion

*/

private char[] crearCombinacion() {

char[] ret = new char[L+cAux];

for(int i=0; i<(L+cAux); i++)

ret[i]=i<L?colores[r.nextInt(N)]:ret[0];

return ret;

}

/**

* Es contenido un caracter C en un arreglo S, entre la posicion 0 y N

* @param c Caracter

* @param S Arreglo de caracteres

* @param n Ultima posicion a buscar

* @return True si C es contenido en S, en caso contrario False

*/

public boolean contiene(char c, char[] S, int n) {

int i=0;

while(i<=n)

9

if(c==S[i++])

return true;

return false;

}

/**

* Crea una combinacion sin colores repetidos

* @return Combinacion sin colores repetidos

*/

public char[] crearCombinacionUniq(){

char[] ret = new char[L+cAux];

int i=0;

while(i<L) {

ret[i]=colores[r.nextInt(N)];

i+=existeEn(ret, ret[i], i)?0:1;

}

ret[i++]=ret[0];

ret[i++]=ret[0];

ret[i++]=ret[0];

return ret;

}

/**

* Obtiene la distancia entre la jugada y el codigo secreto

* @param i indice de la combinacion

* @return distancia entre la jugada y el codigo secreto

*/

private int getFitness(int i) {

return poblacion[i][L+0]-48;

}

/**

* Obtiene la cantidad de blancas (color existente pero fuera de su lugar)

* @param c Combinacion

* @return Cantidad de blancas

*/

public int getW(char[] c) {

return c[L+1]-48;

}

10

/**

* Obtiene la cantidad de negras (color existente en su lugar)

* @param c Combinacion

* @return Cantidad de negras

*/

public int getB(char c[]) {

return c[L+2]-48;

}

/**

* Fija la distancia entre la combinacion y el codigo

* @param i Indice de la combinacion

* @param w Distancia entre la combinacion y el codigo

*/

public void setFitness(int i, int w) {

poblacion[i][L+0] = (char)(48+w);

}

/**

* Fija la cantidad de blancas a una combinacion

* @param i Indice de la combinacion

* @param w Cantidad de blancas

*/

public void setW(int i, int w) {

poblacion[i][L+1] = (char)(48+w);

}

/**

* Fija la cantidad de negras a una combinacion

* @param i Indice de la combinacion

* @param w Cantidad de negras

*/

public void setB(int i, int w) {

poblacion[i][L+2] = (char)(48+w);

}

/**

* Clona un arreglo de tipo char

* @param A Arreglo fuente

* @return Clon de A

*/

11

public char[] clone(char[] A) {

char[] ret =new char[A.length];

for(int i=0; i<A.length;i++)

ret[i] = A[i];

return ret;

}

/**

* Crea una poblacion entera

* @param cantidad Cantidad de la poblacion

*/

public void crearPoblacion(int cantidad) {

poblacion = new char[cantidad][];

for(int i=0; i<cantidad; i++) {

poblacion[i] = crearCombinacionUniq();

}

}

/**

* Imprime la poblacion

*

*/

public void imprimirPoblacion() {

for(int i=0; i<poblacion.length; i++) {

System.out.println(i+" -> "+String.valueOf(poblacion[i]));

}

}

/**

* Crea el codigo secreto

*

*/

public void crearCodigo(){

codigo = crearCombinacion();

}

/**

* Obtiene el codigo secreto

* @return codigo secreto

12

*/

public char[] getCodigo() {

return codigo;

}

/**

* Genera un codigo secreto (manual)

* @param nuevoCodigo Codigo secreto

*/

public void setCodigo(char[] nuevoCodigo) {

codigo = nuevoCodigo;

//System.out.println(historia[0]);

//D(codigo, 0);

//historia[0] = getIndividuo(0);

//System.out.println(historia[0]);

}

/**

* Obtiene un individuo de la poblacion

* @param i Indice de la poblacion

* @return Individuo i

*/

public static char[] getIndividuo(int i) {

return poblacion[i];

}

/**

* Fija un individuo en la poblacion

* @param i Indice de la poblacion

* @param nuevoIndividuo Nuevo Individuo para el indice I

*/

public void setIndividuo(int i, char[] nuevoIndividuo) {

poblacion[i] = nuevoIndividuo;

}

/**

* Agrega una combinacion al historial de jugadas

* @param combinacion combinacion a agregar

* @return true si aun no se ha llegado al maximo de jugadas, caso contrario false

*/

13

public boolean agregarCombinacionHistoria(char [] combinacion) {

if(nJ<J) {

historia[nJ++] = clone(combinacion);

return true;

} else

return false;

}

/**

* Obtiene la ultima combinacion agregada a la historia

* @return combinacion

*/

public char[] sacarUltimaCombinacionHistoria() {

return historia[nJ-1];

}

/**

* Obtiene la historia de jugadas

* @param i Indice de la jugada

* @return Combinacion Jugada

*/

public char[] getHistoria(int i) {

return historia[i];

}

/**

* Crea una instancia de MasterMindBase

* @param np # de poblacion

* @param nj # maximo de jugadas

* @param nh # de generaciones antes de hipermutacion

* @param nc % de cruza

* @param nt % de transposicion

* @param nm % de mutacion circular

* @param nr # de hipermutaciones antes de game over

*/

public MasterMindBase(int np, int nj, int nh, int nc, int nt, int nm, int nr) {

nPob = np;

J = nj;

14

nH = nh;

nC = nc;

nT = nt;

nM = nm;

nR = nr;

crearCodigo();

crearPoblacion(nPob);

historia= new char[J][];

D(getCodigo(), 0);

agregarCombinacionHistoria(getIndividuo(0));

}

/**

* Crea una instancia de MasterMindBase

*

*/

public MasterMindBase() {

crearCodigo();

crearPoblacion(nPob);

historia= new char[J][];

D(getCodigo(), 0);

agregarCombinacionHistoria(getIndividuo(0));

}

/**

* QuickSort

* @param izq izquierda

* @param der derecha

*/

public void qsm( int izq, int der) {

int i = izq;

int j = der;

int pivote = getFitness( (izq + der) / 2);

do {

while (getFitness(i) < pivote) {

i++;

}

15

while (getFitness(j) > pivote) {

j--;

}

if (i <= j) {

char[] t = getIndividuo(i);

setIndividuo(i, getIndividuo(j));

setIndividuo(j, t);

i++;

j--;

}

} while (i <= j);

if (izq < j) {

qsm(izq, j);

}

if (i < der) {

qsm(i, der);

}

}

/**

* Ordenamiento usando quicksort

*

*/

public void sort(){

qsm(0,nPob-1);

}

/**

* Ordenamiento usando burbuja

*

*/

public void sort2() {

for(int i = 0; i< nPob-1; i++ ) {

for(int j= i+1; j<nPob; j++) {

if(getFitness(i)>getFitness(j)) {

char[] t = getIndividuo(i);

16

setIndividuo(i, getIndividuo(j));

setIndividuo(j, t);

}

}

}

}

/**

* Elimina y cuenta las posiciones repetidas de una combinacion comparada con otra

* @param A Combinacion a comparar

* @param B Combinacion Principal

* @return Combinacion sin colores en comun (en la misma posicion y el mismo color)

*/

private char[] D2(char[] A, char[] B) {

char[] ret = new char[A.length];

for(int i=0; i<L; i++) {

if(A[i]==B[i]) {

ret[i] = ' ';

B[L+1]++;

}

else

ret[i]=A[i];

}

return ret;

}

/**

* Cuenta el numero de colores existenes pero fuera de su posicion

* @param A Combinacion sin colores en su lugar

* @param B Combinacion Principal

*/

private void D3(char[] A, char[] B) {

for(int i=0; i<L; i++) {

if(A[i]!=' ') {

for(int j=0; j<L; j++) {

if(B[i]==A[j]) {

A[j] = '*';

B[L+2]++;

17

break;

}

}

}

}

}

/**

* Calcula la cantidad de Blancas y/o Negras entre dos combinaciones

* @param pi Combinacion Nueva

* @param pj Combinacion de la poblacion

*/

public void D(char[] pi, int pj) {

setB(pj, 0);

setW(pj, 0);

D3(D2(pi, getIndividuo(pj)), getIndividuo(pj));

}

/**

* Imprime la pila de jugadas (historia)

*

*/

public void impHistoria() {

for(int i=0; i<nJ; i++)

System.out.println(i+" -> "+String.valueOf(getHistoria(i)).substring(0,5) );

}

/**

* Valor absoluto de un numero entero

* @param a Numero

* @return Absoluto de a

*/

private int abs(int a) {

return a<0?(a*(-1)):a;

}

/**

* Calcula y fija el fitness (distancia) entre la nueva generacion y la historia

* @return True si existe una combinacion que cumpla con la consistencia, en caso contrario false

*/

public boolean fitness() {

18

int suma;

boolean ret = false;

for(int i=0; i<nPob; i++ ) {

suma =0;

for(int j=0; j<nJ; j++) {

D(getHistoria(j), i);

suma += abs( getW(getHistoria(j)) - getW(getIndividuo(i)) )+

abs( getB(getHistoria(j)) - getB(getIndividuo(i)) );

}

setFitness(i, suma);

if(suma==0) ret = true;

}

return ret;

}

/**

* Existe un caracter entre 0 y n de un arreglo

* @param source Arreglo fuente

* @param f Caracter buscado

* @param n Limite de la busqueda

* @return True si existe el caracter en la fuente, en caso contrario false

*/

public static boolean existeEn(char[] source, char f, int n) {

for(int i=0; i<n; i++)

if(source[i]==f)

return true;

return false;

}

/**

* Test de MasterMind

* @param args

*/

public static void main(String[] args) {

long t1 = new java.util.Date().getTime();

long t2 = 0;

long t3 =0;

MasterMind g;

19

double n=0;

double k=0;

long mejorTiempo = 0;

long peorTiempo = 0;

int peorJugada = 0;

int mejorJugada=0;

for(int i=0; i<500; i++) {

g = new MasterMind(400, 10, 15, 40, 40, 20, 200);

t2 = new java.util.Date().getTime();

if(g.jugar()) {

//System.out.println(i+" Ganaste\n\t" + String.valueOf(g.getCodigo()).substring(0,L) +"\n\t"+String.valueOf(g.getHistoria(g.nJ-1)).substring(0,L));

n+=g.nJ;

k++;

if(i==0) {

mejorJugada= peorJugada= g.nJ;

}

else {

if(mejorJugada>(g.nJ))

mejorJugada = g.nJ;

if(peorJugada<(g.nJ))

peorJugada=g.nJ;

}

}

else {

// System.out.println(i+" Perdiste");

}

t3 = new java.util.Date().getTime();

if(i==0) {

mejorTiempo = peorTiempo = t3-t2;

}

else {

if(mejorTiempo>(t3-t2))

mejorTiempo = t3-t2;

if(peorTiempo<(t3-t2))

peorTiempo=t3-t2;

20

}

}

System.out.println("Cantidad Ganada = "+k);

System.out.println("Promedio de ganar = "+(n/k));

System.out.println("\nTiempo transcurrido ="+(new java.util.Date().getTime()-t1) );

System.out.println("Peor Tiempo\t= "+peorTiempo);

System.out.println("Mejor Tiempo\t= "+mejorTiempo);

System.out.println("Peor Jugada\t= "+peorJugada);

System.out.println("Mejor Jugada\t= "+mejorJugada);

}

}

21

ga.MasterMindOperadoresGeneticos.java

package ga;

/**

* MasterMindOperadoresGeneticos, implementa: <br>

* 1.- Cruza <br>

* 2.- Mutacion Circular <br>

* 3.- Transposicion <br>

* 4.- Hipermutacion <br>

* @author Roberto Loaeza Valerio

*

*/

public class MasterMindOperadoresGeneticos extends MasterMindBase{

/**

* Devuelve el siguiente color

* @param color Color actual

* @return Colo siguiente

*/

private char sigColor(char color) {

return color==colores[colores.length-1]?'0':(char)(color+1);

}

/**

* Mutacion Circular

* @param individuo Id del individuo

* @return El mismo individuo con un cromosoma mutado

*/

public char[] mutacionCircular(int individuo) {

char[] ret = clone(getIndividuo(individuo));

int x = r.nextInt(L);

ret[x] = sigColor(ret[x]);

return ret;

}

/**

* Intercambia P[a] por P[b]

* @param P Arreglo P

22

* @param a posicion a

* @param b posicion b

*/

private void swap(char[] P, int a, int b) {

char t = P[a];

P[a] = P[b];

P[b] = t;

}

/**

* Tranposicion

* @param individuo Id del individuo

* @return Un nuevo individuo con su contenido transpuesto

*/

public char[] transposicion(int individuo) {

char[] ret = clone(getIndividuo(individuo));

for(int i=0; i<L; i++)

swap(ret, i, r.nextInt(L));

return ret;

}

/**

* CrossOver A con B

* @param A Padre A

* @param B Padre B

* @param pi inicio del rango

* @param pj fin del rango

* @return Un hijo con [A0, A1, ... Api] + [Api+1, Api+2, ... Apj] + [Apj+1, Apj+2, ... An]

*/

private char[] crossOver(char[] A, char[] B, int pi, int pj) {

char[] ret = new char[A.length];

for(int i=0; i<ret.length; i++)

ret[i] = ( (i>=pi)&&(i<=pj))?B[i]:A[i];

return ret;

}

/**

23

* Cruza dos padres

* @param A Padre A

* @param B Padre B

* @return 2 Hijos con caracteristicas de sus padres

*/

public char[][] cruza(int A, int B) {

int r1 = r.nextInt(L/2);

int r2 = (L/2)+r.nextInt(L/2);

r2= (r1+r2)==L?r2-1:r2;

return new char[][] {crossOver(getIndividuo(A), getIndividuo(B), r1, r2),

crossOver(getIndividuo(B), getIndividuo(A), r1, r2)};

}

/**

* Crea una nueva poblacion (elimina la actual)

*/

public void hiperMutacion() {

crearPoblacion(nPob);

}

/**

* Muta la mitad de la poblacion con los porcentajes definidos en las variables

* nC(crossover), nT(transposicion), nM(mutacion circular).

*/

public void Mutar() {

int n = (nPob/2);

double[] prob = {

nC/100, /* crossover*/

nT/100, /* transposition */

nM/100 /* circular mutation */

};

char r[][] = new char[2][];

for(int i=0; i<n;i++ ) {

if(i<(prob[0]*n)) {

r = cruza(i, i+1);

setIndividuo(nPob-i-1, r[0]);

24

setIndividuo(nPob-(++i)-1, r[1]);

}

else if(i<(prob[0]*n)+(prob[1]*n))

setIndividuo(nPob-i-1, transposicion(i));

else

setIndividuo(nPob-i-1, mutacionCircular(i));

}

}

public MasterMindOperadoresGeneticos() {

super();

}

/**

* Crea una instancia de MasterMindOperadoresGenticos

* @param np # de poblacion

* @param nj # maximo de jugadas

* @param nh # de generaciones antes de hipermutacion

* @param nc % de cruza

* @param nt % de transposicion

* @param nm % de mutacion circular

* @param nr # de hipermutaciones antes de game over

*/

public MasterMindOperadoresGeneticos(int np, int nj, int nh, int nc, int nt, int nm, int nr) {

super(np, nj, nh, nc, nt, nm, nr);

}

}

25

ga.MasterMind

package ga;

import ewe.ui.Control;

/**

* MasterMind, con N = 8 y L = 5.

* @author Roberto Loaeza Valerio

*

*/

public class MasterMind extends MasterMindOperadoresGeneticos{

/**

* Si el codeMaker es humano y no califica bien, cheater es True en caso contrario false.

*/

public boolean cheater=false;

/**

* Juega MasterMind con modalidades <br>

* codeMaker = PC codeBraker = PC <br>

* codeMaker = PC codeBraker = Humano <br>

* codeMaker = Humano codeBraker = PC <br>

* codeMaker = Humano codeBraker = Humano <br>

* @param t Tablero donde se mostraran las jugadas/calificaciones

* @param codeMaker 0 = PC, 1 = Humano

* @param codeBraker 0 = PC, 1 = Humano

* @return True si se ha logrado ganar, en caso contrario False

*/

public boolean jugarOP(Tablero t, int codeMaker, int codeBraker ) {

int i=0, j=0; int k =0;

boolean win = false;

GenerarCodigo g2;

if((codeBraker==0)&&(codeMaker==0)) {

t.addBalls(getHistoria(0), 0, 5);

t.addMiniBalls(new int[] { getB(getHistoria(0)), getW(getHistoria(0))}, 0);

t.refresh();

26

}

else {

nJ--;

}

while((k<J)&&(i<nR)) {

if(j==nH) {

hiperMutacion();

j=0;

i++;

}

if(codeBraker==0) {

if(fitness()) {

if(codeMaker==0) {

sort();

D(getCodigo(), 0);

}

else {

if(!codeMakerCalif(null))

break;

}

agregarJugada(t);

k++;

j=0;

i=0;

}

if(this.getW(this.sacarUltimaCombinacionHistoria())==(L)) {

win = true;

break;

}else {

j++;

sort();

Mutar();

}

}

else {

g2 = new GenerarCodigo();

27

if( ShowMB(g2, "Nueva Combinacion", 240, 130)==MessageBox.IDCANCEL) {

break;

}

if(codeMaker==0) {

setIndividuo(0, g2.getCodigo());

D(getCodigo(), 0);

}

else {

if(!codeMakerCalif(g2.getCodigo()))

break;

}

agregarJugada(t);

k++;

if(this.getW(this.sacarUltimaCombinacionHistoria())==(L)) {

win = true;

break;

}

}

}

if(codeMaker==1)

cheater = isCheater();

return win;

}

/**

* Agrega la siguiente jugada al tablero

* @param t Tablero

*/

private void agregarJugada(Tablero t) {

agregarCombinacionHistoria(getIndividuo(0));

t.addBalls(getHistoria(nJ-1), nJ-1, 5);

t.addMiniBalls(new int[] { getB(getHistoria(nJ-1)), getW(getHistoria(nJ-1))}, nJ-1);

t.refresh();

28

}

/**

* Crea una instancia para calificar un codigo

* @param codigo Codigo a calificar

* @return True si fue calificado, en caso contrario False

*/

private boolean codeMakerCalif(char[] codigo) {

Calificador g3;

if(codigo!=null)

setIndividuo(0, codigo);

g3 = new Calificador(getIndividuo(0));

if(ShowMB(g3, "Calificacion", 240, 180)==MessageBox.IDCANCEL) {

return false;

}

setB(0, g3.getB());

setW(0, g3.getW());

return true;

}

/**

* Solicita el codigo secreto y comprueba si el calificador hizo trampa

* @return True para trampa, en caso contrario False

*/

private boolean isCheater() {

GenerarCodigo g2= new GenerarCodigo();

if(ShowMB(g2 , "Codigo Secreto", 240, 130)!=MessageBox.IDCANCEL) {

setCodigo(g2.getCodigo());

for(int i=0; i< nJ; i++) {

setIndividuo(0,clone(getHistoria(i)));

D(getCodigo(), 0);

if((getB(getIndividuo(0))!=getB(getHistoria(i)))||(getW(getIndividuo(0))!=getW(getHistoria(i))) ) {

return true;

}

}

}

return false;

29

}

/**

* Test

* @return True si se ha logrado ganar, en caso contrario False

*/

public boolean jugar() {

int i=0, j=0; int k =0;

boolean win = false;

while((k<J)&&(i<nR)) {

if(j==nH) {

//this.crearPoblacion(nPob);

hiperMutacion();

j=0;

i++;

}

if(fitness()) {

sort();

D(getCodigo(), 0);

agregarCombinacionHistoria(getIndividuo(0));

k++;

j=0;

i=0;

}

if(this.getW(this.sacarUltimaCombinacionHistoria())==(L)) {

win = true;

break;

}else {

j++;

sort();

Mutar();

}

}

return win;

}

30

public MasterMind() {

super();

}

/**

* Crea una instancia de MasterMindBase

* @param np # de poblacion

* @param nj # maximo de jugadas

* @param nh # de generaciones antes de hipermutacion

* @param nc % de cruza

* @param nt % de transposicion

* @param nm % de mutacion circular

* @param nr # de hipermutaciones antes de game over

*/

public MasterMind(int np, int nj, int nh, int nc, int nt, int nm, int nr) {

super(np, nj, nh, nc, nt, nm, nr);

}

/**

* Muestra un MessageBox con contenido ob

* @param ob Objeto a mostrar en el MessageBox

* @param titulo Titulo del MessageBox

* @param ancho Ancho del MessageBox

* @param alto Alto del MessageBox

* @return MBOK o MBCANCEL

*/

private int ShowMB(Control ob, String titulo, int ancho, int alto) {

MessageBox mb = new MessageBox(titulo, "",MessageBox.MBOKCANCEL);

mb.doBeep=false;

mb.addLast(ob);

mb.setPreferredSize(ancho, alto);

return mb.execute();

}

}

31

APENDICE B: Paquete masterMind

masterMind.MasterMindGUI.java

package masterMind;

import ewe.fx.Color;

public class MasterMindGUI extends Form{

char[] colores = {'0', '1', '2', '3', '4', '5', '6', '7'};

private MasterMind g;

private boolean win;

private SingleContainer contenedor = new SingleContainer();

// 470 70 40

// 300 70 25

private int ancho = 230, alto = 470, n =(alto-70)/40;

private int np=400, nj=10, nh=15, nc=40, nt=40, nm=20, nr= 200, codeMaker = 0, codeBraker = 0;

private HtmlDisplay hd = new HtmlDisplay(12,20);

Dimension dimensionTablero;

private Tablero tablero = new Tablero(alto-30, n);

public void nuevo() {

g = new MasterMind(np, nj, nh, nc, nt, nm, nr);

win =g.jugarOP(tablero, codeMaker, codeBraker);

tablero.addBalls(g.getCodigo(), n, 5);

tablero.refresh();

String historial = win?"<h1 align=\"center\">

<font color=\"#0099FF\"> YaY ....</font></h1>":"<h1 align=\"center\">

<font color=\"#0099FF\">Buu ....</font></h1>";

if(g.cheater)

historial +="<h1 align=\"center\"><br> Cheater!!! <br></h1>";

historial +="<h2> Codigo secreto = "+String.valueOf(g.getCodigo()).substring(0, 5)+"</h2>";

for(int i=0; i<g.nJ;i++) {

32

historial +="<br> "+i+" -> "+String.valueOf(g.getHistoria(i)).substring(0, 5);

historial +=" ["+g.getB(g.getHistoria(i))+", "+g.getW(g.getHistoria(i))+" ]";

}

hd.setHtml(historial);

}

public MasterMindGUI () {

setPreferredSize(ancho, alto);

title = "MasterMind";

addLast(LoadMenus()).setCell(VCONTRACT);

contenedor.setControl(new Tablero(alto-30, n));

addLast(contenedor);

}

private MenuBar LoadMenus() {

MenuBar mb = new MenuBar();

Menu m = new Menu();

MenuItem mSeparator =new MenuItem();

mSeparator.modifiers = MenuItem.Separator;

m.addItem(new MenuItem("Nuevo ", "imgs/iconos/Nuevo.png", Color.White));

m.addItem(mSeparator);

m.addItem(new MenuItem("Salir ", "imgs/iconos/Salir.png", Color.White));

mb.addMenu(m, "Archivo");

m= new Menu();

m.addItem(new MenuItem("Ver Historial ", "imgs/iconos/opciones.png", Color.White));

m.addItem(new MenuItem("Opciones ", "imgs/iconos/opciones.png", Color.White));

mb.addMenu(m, "Herramientas");

m= new Menu();

m.addItem(new MenuItem("Acerca de ", "imgs/iconos/AcercaDe.png", Color.White));

m.addItem(new MenuItem("Tips ", "imgs/iconos/Tips.png", Color.White));

mb.addMenu(m, "Ayuda");

return mb;

}

public boolean handleAction(String action) {

if(action.equals("Salir ")) {

33

exit(1);

}

else if(action.equals("Ver Historial ")) {

msgHistorial();

}

else if(action.equals("Opciones ")) {

Opciones op = new Opciones(np, nj, nh, nc, nt, nm, nr, codeMaker, codeBraker);

msgAyuda(op, "Opciones");

np = Integer.valueOf(op.nPoblacion.getText());

nj = Integer.valueOf(op.nJugadas.getText());

nh = Integer.valueOf(op.nHipermutacion.getText());

nc = Integer.valueOf(op.nCruza.getText());

nt= Integer.valueOf(op.nTransposicion.getText());

nm= Integer.valueOf(op.nMutacionCircular.getText());

nr= Integer.valueOf(op.nReset.getText());

codeMaker = op.codeMaker.selectedIndex;

codeBraker = op.codeBraker.selectedIndex;

}

else if(action.equals("Nuevo ")) {

tablero =new Tablero(alto-30, n);

contenedor.setControl(tablero, true);

nuevo();

msgHistorial();

}

else if(action.equals("Acerca de "))

{

HtmlDisplay hd = new HtmlDisplay(12,20);

hd.setHtml( "<h1 align=\"center\"><font color=\"#0099FF\">MasterMind</font></h1><br>"+

"Fue escrito por <b>Roberto Loaeza Valerio</b> (2007)"+

", sin embargo el software siempre puede ser mejorado, para esto usted (el usuario) "+

"debe informar cuando algo no funcione como debiera o cuando pueda ser mejorado "+

"enviando un reporte.");

hd.modify(DisplayOnly,0);

msgAyuda(hd, "Acerca de");

34

}

else if(action.equals("Tips "))

{

HtmlDisplay hd = new HtmlDisplay(12,20);

hd.setHtml( "<h1 align=\"center\"><font color=\"#0099FF\">mMasterMind</font></h1><br>"+

"En proceso..... "+

"<br><br><h1 align=\"right\">Roberto Loaeza Valerio(2007)</h1>");

hd.modify(DisplayOnly,0);

msgAyuda(hd, "Acerca de");

}

return super.handleAction(action);

}

private void msgHistorial() {

hd.modify(DisplayOnly,0);

msgAyuda(new HtmlViewer(hd, HtmlViewer.DISPLAY_NO_STATUS_BAR|HtmlViewer.DISPLAY_NO_TOOL_BUTTONS|HtmlViewer.DISPLAY_NO_TABS), "Historial");

}

private void msgAyuda(Control ob, String titulo) {

MessageBox mb = new MessageBox(titulo, "",MessageBox.MBOK);

mb.doBeep=false;

mb.addLast(ob);

mb.execute(getFrame(), Gui.CENTER_FRAME);

}

}

masterMind.Cali�cacion.java

package masterMind;

import ewe.fx.Color;

public class Calificacion extends InteractivePanel{

final int incy = 40;

final int incx = 35;

35

private int n = 5, m= 2;

public char[] codigo= {'2', '2', '2', '2', '2'};

AniImage[] b = new AniImage[n];

AniImage[] c = new AniImage[m];

void crearColores() {

Image cols =null;

for(int i=0;i<m;i++) {

switch(i) {

case 0: cols =new Image("imgs/negrag.png"); break;

case 1: cols =new Image("imgs/blancag.png"); break;

case 2: cols =new Image("imgs/vacia2.png"); break;

}

cols.transparent = Color.White;

c[i] = new AniImage(cols);

c[i].properties |= AniImage.IsMoveable;

}

}

public void addCodeGuess(char[] guess) {

Image cols ;

AniImage ai;

for(int i=0; i<5; i++) {

cols =new Image("imgs/"+guess[i]+".png");

cols.transparent = Color.White;

ai = new AniImage(cols);

ai.location.x = 15+(43*i);

ai.location.y = 15;

addImage(ai);

}

refresh();

}

36

public Calificacion(char[] code)

{

backGround= ewe.fx.Color.White;

borderWidth = 2; borderStyle = Canvas.EDGE_SUNKEN;

addCodeGuess(code);

touching = new ImageList();

for(int i=0; i<n; i++) {

b[i] = new AniImage(new mImage("imgs/vacia2.png",Color.White));

b[i].move(15+(i*44), 50);

addImage(b[i]);

touching.add(b[i]);

}

crearColores();

for(int i=0; i<m; i++){

c[i].move(15+(i*25), 100);

addImage(c[i]);

}

}

public int cual(AniImage A) {

for(int i=0;i<m; i++)

if(A==c[i])

return i;

return 0;

}

public void droppedOn(ImageDragContext dc)

{

int c = cual(dc.image);

for(int i=0; i<n; i++) {

if (dc.draggingOver == b[i]){

b[i].change(dc.image);

37

dc.image.move(15+(25*c), 100);

codigo[i] = (char)(48+c);

b[i].refresh();

}

}

}

}

38

masterMind.Cali�cador.java

package masterMind;

import ewe.ui.Form;

public class Calificador extends Form{

Calificacion t ;

public Calificador(char[] guess) {

setPreferredSize(290, 290);

t = new Calificacion(guess);

addLast(t);

}

public int getB () {

int b=0;

for(int i=0; i< t.codigo.length; i++)

if(t.codigo[i]=='1')

b++;

return b;

}

public int getW () {

int b=0;

for(int i=0; i< t.codigo.length; i++)

if(t.codigo[i]=='0')

b++;

return b;

}

public char[] getCodigo() {

return t.codigo;

}

}

39

masterMind.GeneradorCodigo.java

package masterMind;

import ewe.ui.Form;

public class GenerarCodigo extends Form{

Jugada t = new Jugada();

public GenerarCodigo () {

setPreferredSize(230, 90);

addLast(t);

}

public char[] getCodigo() {

return (String.valueOf(t.codigo)+"000").toCharArray();

}

}

masterMind.Jugada.java

package masterMind;

import ewe.fx.Color;

public class Jugada extends InteractivePanel{

final int incy = 40;

final int incx = 35;

private int n =5, m =8;

public char[] codigo= {'0', '0', '0', '0', '0'};

AniImage[] b = new AniImage[n];

AniImage[] c = new AniImage[m];

void crearColores() {

Image cols ;

for(int i=0; i<m;i++) {

40

cols =new Image("imgs/"+i+".png");

cols.transparent = Color.White;

c[i] = new AniImage(cols);

c[i].properties |= AniImage.IsMoveable;

}

}

public Jugada( )

{

backGround= ewe.fx.Color.White;

borderWidth = 2; borderStyle = Canvas.EDGE_SUNKEN;

touching = new ImageList();

for(int i=0;i<n; i++) {

b[i] = new AniImage(new mImage("imgs/vacia2.png",Color.White));

b[i].move(15+(i*44), 20);

addImage(b[i]);

touching.add(b[i]);

}

crearColores();

for(int i=0; i<m; i++ ) {

c[i].move(15+(i*25), 50);

addImage(c[i]);

}

}

public int cual(AniImage A) {

for(int i=0; i<m; i++)

if(A==c[i])

return i;

return 0;

}

41

public void droppedOn(ImageDragContext dc)

{

int c = cual(dc.image);

for(int i=0; i<n; i++) {

if (dc.draggingOver == b[i]){

b[i].change(dc.image);

dc.image.move(15+(25*c), 50);

codigo[i] = (char)(48+c);

b[i].refresh();

break;

}

}

}

}

42

masterMind.Opciones.java

* Elaborado por: Roberto Loaeza Valerio.

package masterMind;

import ewe.ui.CellConstants;

/**

* Datos generales del proyecto

* @author Roberto Loaeza Valerio

*

*/

public class Opciones extends Editor {

public mInput nJugadas, nPoblacion, nHipermutacion, nCruza, nTransposicion, nMutacionCircular, nReset;

public mChoice codeMaker, codeBraker;

public Opciones(int np, int nj, int nh, int nc, int nt, int nm, int nr, int cMaker, int cBraker) {

InputStack is = new InputStack();

is.inputLength = 5;

nPoblacion = new mInput(String.valueOf(np));

nJugadas = new mInput(String.valueOf(nj));

nHipermutacion = new mInput(String.valueOf(nh));

nCruza = new mInput(String.valueOf(nc));

nTransposicion = new mInput(String.valueOf(nt));

nMutacionCircular = new mInput(String.valueOf(nm));

nReset = new mInput(String.valueOf(nr));

codeMaker = new mChoice("PC|Humano", cMaker);

codeBraker= new mChoice("PC|Humano", cBraker);

is.add(codeMaker, "CodeMaker:");

is.add(codeBraker, "CodeBraker:");

is.add(nPoblacion, "Poblacion:");

is.add(nJugadas, "Maximo de jugadas:");

is.add(nReset, "N de reinicios:");

is.add(nHipermutacion, "G. antes de HiperM:");

43

is.add(nCruza, "% Cruza:");

is.add(nTransposicion, "% Transposicion:");

is.add(nMutacionCircular, "% Mutacion Circular:");

addLast(is,CellConstants.HSTRETCH,CellConstants.FILL);

}

}

44

masterMind.Tablero.java

package masterMind;

import ewe.fx.Color;

public class Tablero extends InteractivePanel{

// 40

// 26

final int incy = 40;

// 35

// 28

final int incx = 35;

private int alto;

public void addBalls(char[] c, int l, int n) {

Image cols ;

for(int i=0; i<n; i++) {

cols =new Image("imgs/"+c[i]+"_.png");

cols.transparent = Color.White;

AniImage ai = new AniImage(cols);

ai.location.x = 10+(incx*i);

ai.location.y = alto-incy*l;

addImage(ai);

}

refresh();

}

public void addMiniBalls(int[] bw, int l) {

Image cols ;

for(int i=0; i<bw[0]+bw[1]; i++) {

cols =i<bw[0]?new Image("imgs/blanca.png"):new Image("imgs/negra.png");

cols.transparent = Color.White;

AniImage ai = new AniImage(cols);

// 180 20 180 20

// 150 15 150 15

/*

*/

45

ai.location.x = i<3?180+((incx-20)*i):180+((incx-20)*(i-3));

ai.location.y = i<3?alto+2-incy*l:alto+15-incy*l;

addImage(ai);

}

refresh();

}

void addHoles(int n, int l) {

AniImage hole;

for(int i=0; i<n; i++) {

hole = new AniImage(new mImage("imgs/vacia.png",Color.White));

hole.move(10+(incx*i),alto-incy*l);

addImage(hole);

}

refresh();

}

public Tablero( int alto, int n)

{

this.alto = alto-30;

backGround= ewe.fx.Color.White;

borderWidth = 2; borderStyle = Canvas.EDGE_SUNKEN;

for(int i=0;i<n; i++)

addHoles(5,i);

}

}

46