El juego de las 21 cartas

Este proyecto es uno de los que están en mi lista de mis proyectos de los que me siento orgulloso, y aparecen en la lista debido a la dificultad de los requisitos durante su desarrollo. Particularmente el tiempo, ya que se refiere a un proyecto desarrollado en sólo 6 horas.

Pantalla principal

El contexto del desarrollo

Este proyecto fue presentado originalmente en la Caravana de Proyectos de TI, en ITSOEH, como una demostración de lo que se podía realizar en el lenguaje de programación Java. Sin embargo, esta no fue la idea original. La idea original era realizar una presentación del mismo juego, pero realizado en Matlab. ¿El problema? Fueron varios en realidad, pero los que causaron la decisión de mejorar la idea, fueron que el código no había sido codificado por ningún participante de la caravana y la lenta respuesta del sistema en Matlab.

Un servidor era el responsable de todo un equipo dedicado a presentar la parte lógica matemática en el evento, así que decidí buscar adaptar el código original para hacerlo más eficiente. Pero el código era un desastre.

Así que, llegando a casa ese día, mi prioridad fue buscar la forma de mejorar el funcionamiento de todo el modelo. ¿La solución? Programarlo desde 0 en Java. Y así pasó. Las siguientes 6 horas, entre las 17:00hrs y las 23:00hrs, mi trabajo fue re-codificar todo.

El juego

El juego de las 21 cartas, se refiere a un acto de magia, donde el mago reparte sobre la mesa 21 cartas cara arriba dejándolas en tres montones, le pide al espectador que piense una carta, y de una forma sorprendente, el Mago la adivina.

Todo se resume en la forma en que se acomodan las cartas en los tres montones, siendo que la dinámica mencionada se repite por tres veces, y resultando siempre como carta elegida la carta 11 del mazo final.

Para ejecutar el truco de magia, existen cientos de páginas en internet que indican cómo realizarlo.

El código

En el código fuente del proyecto, que se encuentra bajo licencia GNU para software libre, encontramos cuatro clases, dos formularios, y 21 imágenes de cartas de la clásica baraja española.

Para esta entrada, abordaré únicamente en frm_Main.java, dado que las otras tres clases son: la que presenta a la imagen elegida, y los datos para las imágenes y para la imágen elegida.

Lo primero que podemos observar en el código, es que lo que visualizamos en nuestro tablero de 21 cartas está conformado por un arreglo bidimensional, con las posiciones de las 21 cartas del tablero.

private int[][] inicial = new int[][]{
    {1, 4, 7, 10, 13, 16, 19},
    {2, 5, 8, 11, 14, 17, 20}, 
    {3, 6, 9, 12, 15, 18, 21}
};

El siguiente método, realiza el llenado de toda nuestra pantalla, de manera secuencial, no cíclica. Esto se debe a la necesidad de agilizar el proceso de desarrollo, y lograr un código funcional.

private void llenar(int images[][]) {
    pnl_1.removeAll();
    ...
    Imagen img = new Imagen(String.valueOf(images[0][0]));
    pnl_1.add(img);
    pnl_1.repaint();
    ...
}

El siguiente método, nos muestra la columna elegida por el usuario (este paso se comprenderá mejor si previamente se ha leído cómo se realiza el truco).

private int getSelected() {
    if (rbt_Fila1.isSelected()) {
        return 1;
    } else if (rbt_Fila2.isSelected()) {
        return 2;
    } else {
        return 3;
    }
}

El siguiente método se explicará en múltiples partes. La primer parte, como es observable, pretende invertir el orden del arreglo con la carta elegida.

private void realizar_vuelta() {
    num_vuelta++;
    int select = getSelected();
    int[][] ordena = new int[3][7];
    for (int i = 0; i < 3; i++) {
        int k = 0;
        for (int j = 6; j >= 0; j--) {
            ordena[i][k] = inicial[i][j];
            k++;
        }
    }

Seguidamente, se ordenan los tres montones de cartas, de acuerdo con las reglas del truco.

if (select == 1) {
    inicial[0] = ordena[1];
    inicial[1] = ordena[0];
    inicial[2] = ordena[2];
} else if (select == 2) {
    inicial[0] = ordena[2];
    inicial[1] = ordena[1];
    inicial[2] = ordena[0];
} else if (select == 3) {
    inicial[0] = ordena[1];
    inicial[1] = ordena[2];
    inicial[2] = ordena[0];
}

Para los curiosos de los algoritmos raros, a continuación se muestra una forma poco convencional de invertir un arreglo:

int[] cartas_barajeadas = new int[27];
int guia = 0;

for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 7; j++) {
        cartas_barajeadas[guia] = inicial[i][j];
        guia++;
    }
}

guia = 0;
for (int i = 0; i < 7; i++) {
    for (int j = 0; j < 3; j++) {
        inicial[j][i] = cartas_barajeadas[guia];
        guia++;
    }
}

Y para finalizar este bloque de código, observamos cómo se llena el arreglo con la nueva combinación, y, en caso de ser ya la tercer partida, se reinicia.

llenar(inicial);
if (num_vuelta == 3) {
    frm_ImagenElegida.main(new String[{String.valueOf(cartas_barajeadas[10])});
    inicial = new int[][]{{1, 4, 7, 10, 13, 16, 19}, {2, 5, 8, 11, 14, 17, 20}, {3, 6, 9, 12, 15, 18, 21}};
    num_vuelta=0;
    llenar(inicial);
}

Los métodos siguientes no son relevantes de mención, al ser autogenerado por el formulario al que está enlazado, o por no tener código realmente importante.

Los retos del desarrollo

Para este desarrollo, puedo decir que principalmente fueron dos: El primero de ellos, fue, como ya lo he mencionado, el tiempo, al ser un proyecto de un par de horas. Pero el segundo, y más importante, fue el desconocimiento de la forma en que se debían tratar las imágenes en Java. Sin embargo, puedo decir que fue un desarrollo totalmente funcional para la presentación realizada, y me siento feliz del resultado.