Mastermind: ¡Hola Michael, Quiero jugar a un juego!

Por Andrés Ibáñez Núñez y Eduardo de Lorenzo Poza.

Este programa es la segunda parte del juego Master Mind. Si en la versión anterior tenías que adivinar un número que se pensaba el ordenador ahora se han intercambiado los papeles. ¡El ordenador adivinará el número que tú pienses! Inteligencia artificial: el futuro es hoy.


#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

/** Declaración de variables globales */

/* Conjunto de todos los posibles números de cuatro cifras distintas del 0 al 5 */
int G[360][4];
/* Conjunto de todas las posibles comparaciones entre dos elementos de G */
int H[11][2] = {{2, 0}, {2, 1}, {2, 2}, {3, 0}, {3, 1}, {3, 2}, {3, 3}, {4, 0}, {4, 1}, {4, 2}, {4, 4}};
/* Conjunto de "nominados". Los elementos G[i] que dejan de ser posibles candidatos al
 * número que buscamos pasan a tener S[i]=-1, aunque valdría cualquier valor distinto de i
 */
int S[360];

/** Declaración de funciones */

/* Procedimiento para asignar al array G los 360 números de 4 cifras distintas del 0 al 5
 * PRE: ---
 * POST: G queda definido
 */
void asignarG() {
    int aux[4] = {0};
    for (int n=0, i=0; n<10000; n++) { aux[3] = n%10; aux[2] = (n%100 - aux[3])/10; aux[1] = (n%1000 - aux[3] - aux[2])/100; aux[0] = (n - aux[3] - aux[2]- aux[1])/1000; if (aux[0]>=0 && aux[0]<=5 && aux[1]>=0 && aux[1]<=5 && aux[2]>=0 && aux[2]<=5 && aux[3]>=0 && aux[3]<=5 &&
            (aux[0] != aux[1]) && (aux[0] != aux[2]) && (aux[0] != aux[3]) && (aux[1] != aux[2]) && (aux[1] != aux[3]) && (aux[2] != aux[3])) {

            G[i][0] = aux[0];
            G[i][1] = aux[1];
            G[i][2] = aux[2];
            G[i][3] = aux[3];
            i++;
        }
    }
}

/* Función que compara dos valores y devuelve 1 si son iguales y 0 si no lo son
 * PRE: ---
 * POST: igual(x,y) = 0 si x!=y
 *                  = 1 si x==y
 */
int igual(int x, int y) {
    if (x==y) return 1;
    else return 0;
}

/* Función que compara dos elementos de G. Devuelve la comparación como dos números que
 * se almacenan en el último argumento. El primer número indica el número de cifras en
 * común; mientras que el segundo número indica el número de cifras comunes que están en
 * la misma posición.
 * PRE: Los dos primeros argumentos son los números a comparar y el último en el que se
 *      va a almacenar la respuesta.
 * POST: respuesta[0] = número de cifras en común
 *       respuesta[1] = número de cifras en la misma posición
 */
void comparacion(int a[4], int b[4], int respuesta[2]) {
    respuesta[0] = 0; respuesta[1] = 0;
    for (int i=0; i<4; i++) {
        for (int j=0; j<4; j++) {
            respuesta[0] = respuesta[0] + igual(a[i], b[j]);
        }
    }

    for (int i=0; i<4; i++) {
        respuesta[1] = respuesta[1] + igual(a[i], b[i]);
    }
}

/* Función que determina qué elemento de H es el argumento y devuelve el índice de H en el
 * que se encuentra dicho elemento. Servirá para clasificar las comparaciones.
 * PRE: El argumento debe encontrarse entre los valores de H. Esto lo garantiza el programa,
 *      ya que el usuario nunca accede a esta función.
 * POST: La función devuelve el subíndice i (de H[i]) que coincide con el argumento.
 */
int compararConH(int a[2]) {
    for (int i=0; i<11; i++) {
        if (a[0]==H[i][0] && a[1]==H[i][1]) return i;
    }
}

/* Función que compara un elemento de G con todos los elementos de G que quedan en S. Cada
 * comparación devuelve un elemento de H, y la función mantiene un registro de cuántas veces
 * se ha obtenido cada valor de H. El programa utiliza el método minimax, por lo que queremos
 * quedarnos con el peor de los casos: que nos respondieran el elemento de H que más opciones
 * nos deja, o lo que es lo mismo, el que menos elementos elimina de S. La función devuelve 360
 * menos el número de opciones que quedan (a este valor le llamamos puntuación del elemento de
 * G), de manera que el que menos opciones deja es el que mayor puntuación tiene.
 * PRE: El argumento debe encontrarse entre los valores de G. Esto lo garantiza el programa,
 *      ya que el usuario nunca accede a esta función.
 * POST: La función devuelve la puntuación del elemento de G. Es un valor meramente comparativo
 */
int compararConS(int A[4]) {
    /* Variable para almacenar la comparación de A con cada elemento de S */
    int Comparacion[2];
    /* Variable que lleva el registro de la veces que aparece cada valor de H */
    int nCoincidencias[11] = {0};

    for (int i=0; i<360; i++) {
        if (S[i]==i) {
            comparacion(A, G[i], Comparacion);
            for (int i=0; i<11; i++) {
                if (compararConH(Comparacion)==i) nCoincidencias[i]++;
            }
        }
    }

    /* La puntuación de A es 360 menos el mayor nCoincidencias */
    int mayorNC = nCoincidencias[0];
    for (int i=0; i<11; i++) { if (nCoincidencias[i] > mayorNC) mayorNC = nCoincidencias[i];
    }
    int puntuacionA = 360 - mayorNC;

    return puntuacionA;
}

/** Programa principal */

int main() {

    int indicePregunta = 0;
    int respuesta[2];
    bool finalizado = false;

    asignarG();
    /* Asignar S */
    for (int i=0; i<360; i++) {
        S[i] = i;
    }

    cout << "Hola, humano. Disculpa mi ortografia. Mi creador no me ense¤o a usar acentos." << endl
         << "Sin  embargo,  si  aprendi  de  el  un  juego  muy  divertido.  Se  llama... " << endl << endl
         << "==========================MASTERMIND=============================            " << endl << endl
         << "Quiza ya hayas jugado antes, pero de todos modos te lo ense¤are:             " << endl
         << "Tu piensas un numero de cuatro cifras distintas del 0 al 5. En cada turno    " << endl
         << "yo intentare adivinar cual es ese numero. Para conseguirlo necesitare        " << endl
         << "unicamente que me digas, de entre los numeros que yo he dicho:               " << endl << endl
         << "         - Cuantos estan tambien en tu numero                                " << endl
         << "         - Cuantos estan en la posicion correcta                             " << endl << endl
         << "Vamos a empezar, de todos modos no vas a durar mucho:                        " << endl << endl;

    while (!finalizado) {
        cout << "Creo que tu numero es el\t\t\t";
        for (int i=0; i<4; i++) {
            cout << G[indicePregunta][i] << " ";
        }
        cout << endl << endl;
        cout << "De esos numeros, en el tuyo hay:\t\t"; cin >> respuesta[0];
        cout << "De los cuales en su posicion correcta estan:\t"; cin >> respuesta[1];
        cout << endl;

        if (respuesta[1]==4) finalizado = true;
        else {
            cout << "Nadie es perfecto, voy a probar otra vez." << endl;
            int posibleRespuesta[2];
            int menorNumeroEliminados[360];

            for (int i=0; i<360; i++) {
                comparacion(G[indicePregunta], G[i], posibleRespuesta);

                if (!(posibleRespuesta[0]==respuesta[0] && posibleRespuesta[1]==respuesta[1])) {
                    S[i] = -1;
                }
            }

            /* Si yo preguntara ahora G[i perteneciente a S] y me respondieran H[j], ¿cuántos elementos de S desaparecerían? */
            for (int i=0; i<360; i++) menorNumeroEliminados[i] = compararConS(G[i]);

            /* Queremos quedarnos con el que tenga el mayor "menorNumeroEliminados" */
            int indiceSiguientePregunta = 0;
            for (int i=0; i<360; i++) {
                if (menorNumeroEliminados[indiceSiguientePregunta] == menorNumeroEliminados[i] && S[i] == i) indiceSiguientePregunta = i;
                else if (menorNumeroEliminados[indiceSiguientePregunta] < menorNumeroEliminados[i]) indiceSiguientePregunta = i;
            }

            indicePregunta = indiceSiguientePregunta;
        }
    }

    system("CLS");
    cout << endl << endl << endl << endl
         << "\tNo eres rival para mi. Solo he estado jugando contigo." << endl
         << "\tDesde un principio sabia que tu numero era, en efecto el" << endl << endl << "\t\t\t\t";
    for (int i=0; i<4; i++) {
        cout << G[indicePregunta][i] << " ";
    }
    cout << endl << endl;
    cout << "\tNo te preocupes, ya ganaras en otra ocasion.";
    cout << endl << endl << endl << endl << endl << endl << endl << endl << endl << endl << endl << "\t\t\t\t\t\t\t\t(En realidad no)";
    system("PAUSE");
}

Anuncios
Esta entrada fue publicada en Informática e Internet. Guarda el enlace permanente.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s