Proyecto avanzado en PSeInt: crear un juego de Truco argentino con SubProcesos


En este proyecto vamos a crear un juego de Truco argentino en PSeInt para un jugador contra la computadora. Además de ser un juego divertido, es un ejercicio excelente para practicar Funciones, SubProcesos, vectores, números aleatorios, condicionales, ciclos y manejo de estados.

La idea es que el programa sea entendible incluso para alguien que nunca jugó al Truco. Por eso primero veremos las reglas que vamos a implementar y recién después construiremos el juego.

¿Qué versión del Truco vamos a programar?

El Truco argentino tiene muchas variantes. Para que el proyecto sea completo pero manejable, implementaremos:

  • 1 jugador contra la computadora;
  • mazo español de 40 cartas;
  • 3 cartas para cada jugador;
  • partida a 15 puntos;
  • Envido;
  • Truco;
  • Retruco;
  • Vale Cuatro;
  • reglas de parda;
  • alternancia de quién es mano;
  • mezcla aleatoria del mazo antes de cada mano.

Para esta primera versión dejaremos afuera Flor, Real Envido, Falta Envido y partidas de 2 contra 2. Son excelentes mejoras para agregar después.

Reglas básicas del Truco

El objetivo

El objetivo es ser el primero en llegar a 15 puntos. Cada mano permite ganar puntos mediante el Envido y mediante el Truco.

El mazo

Se utiliza un mazo español de 40 cartas. Los palos son:

  • Espada;
  • Basto;
  • Oro;
  • Copa.

En cada palo existen las cartas 1, 2, 3, 4, 5, 6, 7, 10, 11 y 12. No se utilizan 8 ni 9.

Reparto

Al comienzo de cada mano se mezclan las 40 cartas y se reparten 3 cartas a cada jugador. Una carta nunca puede repetirse porque primero mezclamos el mazo completo y luego tomamos las seis primeras posiciones.

Jerarquía de las cartas en el Truco

Una de las particularidades del Truco es que el valor numérico de una carta no determina directamente su fuerza. La jerarquía, de mayor a menor, es:

  1. 1 de Espada;
  2. 1 de Basto;
  3. 7 de Espada;
  4. 7 de Oro;
  5. todos los 3;
  6. todos los 2;
  7. 1 de Oro y 1 de Copa;
  8. todos los 12;
  9. todos los 11;
  10. todos los 10;
  11. 7 de Copa y 7 de Basto;
  12. todos los 6;
  13. todos los 5;
  14. todos los 4.

Para simplificar las comparaciones, nuestra función ValorTruco() transforma cada carta en un valor interno. Cuanto mayor sea ese valor, más fuerte será la carta.

¿Cómo se gana una mano?

Cada mano puede tener hasta tres vueltas. En cada vuelta ambos jugadores tiran una carta.

Normalmente gana la mano quien gana dos vueltas. Sin embargo, existen empates llamados pardas:

  • si la primera vuelta empata, quien gane la segunda gana la mano;
  • si alguien gana la primera y la segunda empata, gana quien había ganado la primera;
  • si cada jugador gana una de las dos primeras, la tercera decide;
  • si la tercera empata después de que cada uno ganó una vuelta, gana quien ganó la primera;
  • si todas las vueltas empatan, gana quien era mano.

Ser mano significa jugar primero al comienzo de esa mano. En nuestro programa esta condición alternará después de cada mano.

El Envido

El Envido compara combinaciones de cartas del mismo palo. Para calcularlo:

  • si tenemos dos cartas del mismo palo, sumamos sus valores y agregamos 20;
  • las figuras 10, 11 y 12 valen 0 para el Envido;
  • si no tenemos dos cartas del mismo palo, vale la carta numérica más alta entre 1 y 7;
  • si hay empate, gana quien es mano.

Ejemplos:

6 de Oro + 7 de Oro = 33 de Envido
1 de Copa + 12 de Copa = 21 de Envido
7 de Espada + 4 de Oro + 12 de Basto = 7 de Envido

En esta versión usamos solamente Envido: si es aceptado vale 2 puntos; si el rival no quiere, quien lo cantó recibe 1 punto.

Truco, Retruco y Vale Cuatro

La mano comienza valiendo 1 punto. Durante el juego puede aumentarse su valor:

  • Truco: la mano pasa a valer 2 puntos;
  • Retruco: pasa a valer 3 puntos;
  • Vale Cuatro: pasa a valer 4 puntos.

El rival puede aceptar o rechazar. Si rechaza, quien realizó el último canto gana el valor que tenía la mano antes de aumentar. Por ejemplo, rechazar un Truco entrega 1 punto; rechazar un Retruco entrega 2; rechazar un Vale Cuatro entrega 3.

Después de que un canto es aceptado, solamente el rival de quien realizó ese canto puede subir nuevamente la apuesta.

Representar las cartas con números

Internamente representaremos cada carta con un número del 1 al 40. Diez posiciones pertenecen a cada palo. Luego usaremos funciones para transformar ese número interno en el número y palo que ve el jugador.

Esto permite trabajar con un único vector:

Dimension mazo[40];

Para i <- 1 Hasta 40 Hacer
    mazo[i] <- i;
FinPara

Mezclar el mazo con Fisher-Yates

No conviene generar seis números aleatorios independientes porque podríamos obtener una carta repetida. En cambio, creamos las 40 cartas y mezclamos sus posiciones.

Usaremos una variante del algoritmo Fisher-Yates. En cada paso intercambiaremos una carta con una posición aleatoria de la parte del vector que todavía no fue procesada.

SubProceso MezclarMazo(mazo Por Referencia)
    Definir i, posicionAleatoria, auxiliar Como Entero;

    Para i <- 40 Hasta 2 Con Paso -1 Hacer
        posicionAleatoria <- Aleatorio(1,i);

        auxiliar <- mazo[i];
        mazo[i] <- mazo[posicionAleatoria];
        mazo[posicionAleatoria] <- auxiliar;
    FinPara
FinSubProceso

Después de mezclar, las cartas mazo[1] a mazo[3] pueden ir al jugador y mazo[4] a mazo[6] a la computadora.

Código completo del juego

Funcion numero <- NumeroCarta(carta)
    Definir posicion Como Entero;

    posicion <- carta - Trunc((carta - 1) / 10) * 10;

    Si posicion <= 7 Entonces
        numero <- posicion;
    SiNo
        numero <- posicion + 2;
    FinSi
FinFuncion


Funcion palo <- PaloCarta(carta)
    Definir codigo Como Entero;
    Definir palo Como Cadena;

    codigo <- Trunc((carta - 1) / 10) + 1;

    Segun codigo Hacer
        1:
            palo <- "Espada";
        2:
            palo <- "Basto";
        3:
            palo <- "Oro";
        4:
            palo <- "Copa";
    FinSegun
FinFuncion


Funcion valor <- ValorTruco(carta)
    Definir numero Como Entero;
    Definir palo Como Cadena;

    numero <- NumeroCarta(carta);
    palo <- PaloCarta(carta);

    Si numero = 1 Y palo = "Espada" Entonces
        valor <- 14;
    SiNo
        Si numero = 1 Y palo = "Basto" Entonces
            valor <- 13;
        SiNo
            Si numero = 7 Y palo = "Espada" Entonces
                valor <- 12;
            SiNo
                Si numero = 7 Y palo = "Oro" Entonces
                    valor <- 11;
                SiNo
                    Segun numero Hacer
                        3:
                            valor <- 10;
                        2:
                            valor <- 9;
                        1:
                            valor <- 8;
                        12:
                            valor <- 7;
                        11:
                            valor <- 6;
                        10:
                            valor <- 5;
                        7:
                            valor <- 4;
                        6:
                            valor <- 3;
                        5:
                            valor <- 2;
                        4:
                            valor <- 1;
                    FinSegun
                FinSi
            FinSi
        FinSi
    FinSi
FinFuncion


Funcion valor <- ValorEnvidoCarta(carta)
    Definir numero Como Entero;

    numero <- NumeroCarta(carta);

    Si numero >= 10 Entonces
        valor <- 0;
    SiNo
        valor <- numero;
    FinSi
FinFuncion


Funcion envido <- CalcularEnvido(mano)
    Definir v1, v2, v3, candidato Como Entero;
    Definir p1, p2, p3 Como Cadena;

    v1 <- ValorEnvidoCarta(mano[1]);
    v2 <- ValorEnvidoCarta(mano[2]);
    v3 <- ValorEnvidoCarta(mano[3]);

    p1 <- PaloCarta(mano[1]);
    p2 <- PaloCarta(mano[2]);
    p3 <- PaloCarta(mano[3]);

    envido <- v1;

    Si v2 > envido Entonces
        envido <- v2;
    FinSi

    Si v3 > envido Entonces
        envido <- v3;
    FinSi

    Si p1 = p2 Entonces
        candidato <- 20 + v1 + v2;

        Si candidato > envido Entonces
            envido <- candidato;
        FinSi
    FinSi

    Si p1 = p3 Entonces
        candidato <- 20 + v1 + v3;

        Si candidato > envido Entonces
            envido <- candidato;
        FinSi
    FinSi

    Si p2 = p3 Entonces
        candidato <- 20 + v2 + v3;

        Si candidato > envido Entonces
            envido <- candidato;
        FinSi
    FinSi
FinFuncion


Funcion ganador <- CompararCartas(cartaJugador, cartaCPU)
    Definir valorJugador, valorCPU Como Entero;

    valorJugador <- ValorTruco(cartaJugador);
    valorCPU <- ValorTruco(cartaCPU);

    Si valorJugador > valorCPU Entonces
        ganador <- 1;
    SiNo
        Si valorCPU > valorJugador Entonces
            ganador <- 2;
        SiNo
            ganador <- 0;
        FinSi
    FinSi
FinFuncion


Funcion nombre <- NombreCanto(nuevoValor)
    Definir nombre Como Cadena;

    Segun nuevoValor Hacer
        2:
            nombre <- "TRUCO";
        3:
            nombre <- "RETRUCO";
        4:
            nombre <- "VALE CUATRO";
    FinSegun
FinFuncion


SubProceso CrearMazo(mazo Por Referencia)
    Definir i Como Entero;

    Para i <- 1 Hasta 40 Hacer
        mazo[i] <- i;
    FinPara
FinSubProceso


SubProceso MezclarMazo(mazo Por Referencia)
    Definir i, posicionAleatoria, auxiliar Como Entero;

    Para i <- 40 Hasta 2 Con Paso -1 Hacer
        posicionAleatoria <- Aleatorio(1,i);

        auxiliar <- mazo[i];
        mazo[i] <- mazo[posicionAleatoria];
        mazo[posicionAleatoria] <- auxiliar;
    FinPara
FinSubProceso


SubProceso Repartir(mazo, manoJugador Por Referencia, manoCPU Por Referencia)
    manoJugador[1] <- mazo[1];
    manoJugador[2] <- mazo[2];
    manoJugador[3] <- mazo[3];

    manoCPU[1] <- mazo[4];
    manoCPU[2] <- mazo[5];
    manoCPU[3] <- mazo[6];
FinSubProceso


SubProceso MostrarCarta(carta)
    Escribir Sin Saltar NumeroCarta(carta), " de ", PaloCarta(carta);
FinSubProceso


SubProceso MostrarMano(manoJugador, usadaJugador)
    Definir i Como Entero;

    Escribir "";
    Escribir "Tus cartas:";

    Para i <- 1 Hasta 3 Hacer
        Si NO usadaJugador[i] Entonces
            Escribir Sin Saltar i, ". ";
            MostrarCarta(manoJugador[i]);
            Escribir "";
        FinSi
    FinPara
FinSubProceso


Funcion posicion <- ElegirCartaJugador(manoJugador, usadaJugador)
    Repetir
        MostrarMano(manoJugador, usadaJugador);
        Escribir "Elegí la posición de la carta que querés jugar:";
        Leer posicion;
    Hasta Que posicion >= 1 Y posicion <= 3 Y NO usadaJugador[posicion]
FinFuncion


Funcion posicion <- ElegirCartaCPU(usadaCPU)
    Repetir
        posicion <- Aleatorio(1,3);
    Hasta Que NO usadaCPU[posicion]
FinFuncion


Funcion aceptar <- CPUAceptaTruco(manoCPU)
    Definir i, mejorCarta, probabilidad Como Entero;

    mejorCarta <- 0;

    Para i <- 1 Hasta 3 Hacer
        Si ValorTruco(manoCPU[i]) > mejorCarta Entonces
            mejorCarta <- ValorTruco(manoCPU[i]);
        FinSi
    FinPara

    probabilidad <- Aleatorio(1,100);

    Si mejorCarta >= 11 Entonces
        aceptar <- probabilidad <= 85;
    SiNo
        Si mejorCarta >= 8 Entonces
            aceptar <- probabilidad <= 65;
        SiNo
            aceptar <- probabilidad <= 40;
        FinSi
    FinSi
FinFuncion


SubProceso GestionarEnvido(manoJugador, manoCPU, mano, puntosJugador Por Referencia, puntosCPU Por Referencia)
    Definir opcion, envidoJugador, envidoCPU, probabilidad Como Entero;
    Definir acepta, cantado Como Logico;

    cantado <- Falso;
    envidoJugador <- CalcularEnvido(manoJugador);
    envidoCPU <- CalcularEnvido(manoCPU);

    Escribir "";
    Escribir "¿Querés cantar ENVIDO?";
    Escribir "1. Sí";
    Escribir "2. No";
    Leer opcion;

    Si opcion = 1 Entonces
        cantado <- Verdadero;

        probabilidad <- Aleatorio(1,100);

        Si envidoCPU >= 27 Entonces
            acepta <- Verdadero;
        SiNo
            acepta <- probabilidad <= 55;
        FinSi

        Si acepta Entonces
            Escribir "La computadora dice: ¡QUIERO!";
        SiNo
            Escribir "La computadora dice: NO QUIERO.";
            puntosJugador <- puntosJugador + 1;
        FinSi
    SiNo
        Si envidoCPU >= 27 O Aleatorio(1,100) <= 25 Entonces
            cantado <- Verdadero;

            Escribir "La computadora canta: ¡ENVIDO!";
            Escribir "1. Quiero";
            Escribir "2. No quiero";
            Leer opcion;

            Si opcion = 1 Entonces
                acepta <- Verdadero;
            SiNo
                acepta <- Falso;
                puntosCPU <- puntosCPU + 1;
            FinSi
        SiNo
            acepta <- Falso;
        FinSi
    FinSi

    Si cantado Y acepta Entonces
        Escribir "Tu Envido: ", envidoJugador;
        Escribir "Envido de la computadora: ", envidoCPU;

        Si envidoJugador > envidoCPU Entonces
            puntosJugador <- puntosJugador + 2;
            Escribir "Ganaste el Envido.";
        SiNo
            Si envidoCPU > envidoJugador Entonces
                puntosCPU <- puntosCPU + 2;
                Escribir "La computadora ganó el Envido.";
            SiNo
                Si mano = 1 Entonces
                    puntosJugador <- puntosJugador + 2;
                    Escribir "Empate de Envido: ganás por ser mano.";
                SiNo
                    puntosCPU <- puntosCPU + 2;
                    Escribir "Empate de Envido: gana la computadora por ser mano.";
                FinSi
            FinSi
        FinSi

        Esperar Tecla;
    FinSi
FinSubProceso


SubProceso IntentarCantoJugador(manoCPU, apuestaTruco Por Referencia, ultimoCantor Por Referencia, puntosJugador Por Referencia, manoTerminada Por Referencia)
    Definir nuevoValor Como Entero;

    nuevoValor <- apuestaTruco + 1;

    Escribir "Cantás: ¡", NombreCanto(nuevoValor), "!";

    Si CPUAceptaTruco(manoCPU) Entonces
        Escribir "La computadora dice: ¡QUIERO!";
        apuestaTruco <- nuevoValor;
        ultimoCantor <- 1;
    SiNo
        Escribir "La computadora dice: NO QUIERO.";
        puntosJugador <- puntosJugador + apuestaTruco;
        manoTerminada <- Verdadero;
    FinSi
FinSubProceso


SubProceso IntentarCantoCPU(apuestaTruco Por Referencia, ultimoCantor Por Referencia, puntosCPU Por Referencia, manoTerminada Por Referencia)
    Definir nuevoValor, opcion Como Entero;

    nuevoValor <- apuestaTruco + 1;

    Escribir "La computadora canta: ¡", NombreCanto(nuevoValor), "!";
    Escribir "1. Quiero";
    Escribir "2. No quiero";
    Leer opcion;

    Si opcion = 1 Entonces
        apuestaTruco <- nuevoValor;
        ultimoCantor <- 2;
    SiNo
        puntosCPU <- puntosCPU + apuestaTruco;
        manoTerminada <- Verdadero;
    FinSi
FinSubProceso


Funcion ganador <- ResolverDespuesDeDos(g1, g2)
    ganador <- -1;

    Si g1 = 0 Y g2 <> 0 Entonces
        ganador <- g2;
    FinSi

    Si g1 <> 0 Y g2 = 0 Entonces
        ganador <- g1;
    FinSi

    Si g1 <> 0 Y g1 = g2 Entonces
        ganador <- g1;
    FinSi
FinFuncion


Funcion ganador <- ResolverConTercera(g1, g2, g3, mano)
    Si g1 = 0 Y g2 = 0 Entonces
        Si g3 = 0 Entonces
            ganador <- mano;
        SiNo
            ganador <- g3;
        FinSi
    SiNo
        Si g1 <> 0 Y g2 <> 0 Y g1 <> g2 Entonces
            Si g3 = 0 Entonces
                ganador <- g1;
            SiNo
                ganador <- g3;
            FinSi
        SiNo
            ganador <- ResolverDespuesDeDos(g1,g2);
        FinSi
    FinSi
FinFuncion


Proceso Truco_Argentino
    Definir mazo, manoJugador, manoCPU Como Entero;
    Definir usadaJugador, usadaCPU Como Logico;
    Definir puntosJugador, puntosCPU, mano Como Entero;
    Definir apuestaTruco, ultimoCantor, vuelta, lider Como Entero;
    Definir posJugador, posCPU, cartaJugador, cartaCPU Como Entero;
    Definir g1, g2, g3, ganadorVuelta, ganadorMano Como Entero;
    Definir opcion, i Como Entero;
    Definir manoTerminada Como Logico;

    Dimension mazo[40];
    Dimension manoJugador[3];
    Dimension manoCPU[3];
    Dimension usadaJugador[3];
    Dimension usadaCPU[3];

    puntosJugador <- 0;
    puntosCPU <- 0;
    mano <- 1;

    Mientras puntosJugador < 15 Y puntosCPU < 15 Hacer
        CrearMazo(mazo);
        MezclarMazo(mazo);
        Repartir(mazo, manoJugador, manoCPU);

        Para i <- 1 Hasta 3 Hacer
            usadaJugador[i] <- Falso;
            usadaCPU[i] <- Falso;
        FinPara

        apuestaTruco <- 1;
        ultimoCantor <- 0;
        manoTerminada <- Falso;
        g1 <- 0;
        g2 <- 0;
        g3 <- 0;

        Limpiar Pantalla;
        Escribir "====================================";
        Escribir "          TRUCO ARGENTINO";
        Escribir "====================================";
        Escribir "Vos: ", puntosJugador, " puntos";
        Escribir "CPU: ", puntosCPU, " puntos";

        Si mano = 1 Entonces
            Escribir "Sos mano.";
        SiNo
            Escribir "La computadora es mano.";
        FinSi

        MostrarMano(manoJugador, usadaJugador);
        GestionarEnvido(manoJugador, manoCPU, mano, puntosJugador, puntosCPU);

        lider <- mano;
        vuelta <- 1;

        Mientras vuelta <= 3 Y NO manoTerminada Hacer
            Limpiar Pantalla;

            Escribir "Marcador: Vos ", puntosJugador, " - CPU ", puntosCPU;
            Escribir "Valor actual de la mano: ", apuestaTruco;
            Escribir "Vuelta ", vuelta;

            Si lider = 1 Entonces
                MostrarMano(manoJugador, usadaJugador);

                Si apuestaTruco < 4 Y (ultimoCantor = 0 O ultimoCantor = 2) Entonces
                    Escribir "1. Jugar carta";
                    Escribir "2. Cantar ", NombreCanto(apuestaTruco + 1);
                    Leer opcion;

                    Si opcion = 2 Entonces
                        IntentarCantoJugador(manoCPU, apuestaTruco, ultimoCantor, puntosJugador, manoTerminada);
                    FinSi
                FinSi

                Si NO manoTerminada Entonces
                    posJugador <- ElegirCartaJugador(manoJugador, usadaJugador);
                    cartaJugador <- manoJugador[posJugador];
                    usadaJugador[posJugador] <- Verdadero;

                    Escribir Sin Saltar "Jugaste: ";
                    MostrarCarta(cartaJugador);
                    Escribir "";

                    Si apuestaTruco < 4 Y (ultimoCantor = 0 O ultimoCantor = 1) Y Aleatorio(1,100) <= 18 Entonces
                        IntentarCantoCPU(apuestaTruco, ultimoCantor, puntosCPU, manoTerminada);
                    FinSi
                FinSi

                Si NO manoTerminada Entonces
                    posCPU <- ElegirCartaCPU(usadaCPU);
                    cartaCPU <- manoCPU[posCPU];
                    usadaCPU[posCPU] <- Verdadero;

                    Escribir Sin Saltar "CPU juega: ";
                    MostrarCarta(cartaCPU);
                    Escribir "";
                FinSi
            SiNo
                Si apuestaTruco < 4 Y (ultimoCantor = 0 O ultimoCantor = 1) Y Aleatorio(1,100) <= 18 Entonces
                    IntentarCantoCPU(apuestaTruco, ultimoCantor, puntosCPU, manoTerminada);
                FinSi

                Si NO manoTerminada Entonces
                    posCPU <- ElegirCartaCPU(usadaCPU);
                    cartaCPU <- manoCPU[posCPU];
                    usadaCPU[posCPU] <- Verdadero;

                    Escribir Sin Saltar "CPU juega: ";
                    MostrarCarta(cartaCPU);
                    Escribir "";

                    MostrarMano(manoJugador, usadaJugador);

                    Si apuestaTruco < 4 Y (ultimoCantor = 0 O ultimoCantor = 2) Entonces
                        Escribir "1. Jugar carta";
                        Escribir "2. Cantar ", NombreCanto(apuestaTruco + 1);
                        Leer opcion;

                        Si opcion = 2 Entonces
                            IntentarCantoJugador(manoCPU, apuestaTruco, ultimoCantor, puntosJugador, manoTerminada);
                        FinSi
                    FinSi
                FinSi

                Si NO manoTerminada Entonces
                    posJugador <- ElegirCartaJugador(manoJugador, usadaJugador);
                    cartaJugador <- manoJugador[posJugador];
                    usadaJugador[posJugador] <- Verdadero;

                    Escribir Sin Saltar "Jugaste: ";
                    MostrarCarta(cartaJugador);
                    Escribir "";
                FinSi
            FinSi

            Si NO manoTerminada Entonces
                ganadorVuelta <- CompararCartas(cartaJugador, cartaCPU);

                Si ganadorVuelta = 1 Entonces
                    Escribir "Ganaste la vuelta.";
                    lider <- 1;
                SiNo
                    Si ganadorVuelta = 2 Entonces
                        Escribir "La CPU ganó la vuelta.";
                        lider <- 2;
                    SiNo
                        Escribir "Parda.";
                    FinSi
                FinSi

                Si vuelta = 1 Entonces
                    g1 <- ganadorVuelta;
                FinSi

                Si vuelta = 2 Entonces
                    g2 <- ganadorVuelta;
                    ganadorMano <- ResolverDespuesDeDos(g1,g2);

                    Si ganadorMano <> -1 Entonces
                        manoTerminada <- Verdadero;
                    FinSi
                FinSi

                Si vuelta = 3 Entonces
                    g3 <- ganadorVuelta;
                    ganadorMano <- ResolverConTercera(g1,g2,g3,mano);
                    manoTerminada <- Verdadero;
                FinSi

                vuelta <- vuelta + 1;
                Esperar Tecla;
            FinSi
        FinMientras

        Si ganadorMano = 1 Entonces
            puntosJugador <- puntosJugador + apuestaTruco;
            Escribir "Ganaste la mano y sumás ", apuestaTruco, " punto(s).";
        FinSi

        Si ganadorMano = 2 Entonces
            puntosCPU <- puntosCPU + apuestaTruco;
            Escribir "La CPU ganó la mano y suma ", apuestaTruco, " punto(s).";
        FinSi

        Si mano = 1 Entonces
            mano <- 2;
        SiNo
            mano <- 1;
        FinSi

        Esperar Tecla;
    FinMientras

    Limpiar Pantalla;
    Escribir "====================================";
    Escribir "             FIN DEL JUEGO";
    Escribir "====================================";

    Si puntosJugador >= 15 Entonces
        Escribir "¡Ganaste la partida!";
    SiNo
        Escribir "La computadora ganó la partida.";
    FinSi

    Escribir "Resultado final: ", puntosJugador, " a ", puntosCPU;
FinProceso

¿Qué hace cada parte?

NumeroCarta() y PaloCarta()

Estas funciones traducen el número interno del 1 al 40 a una carta real. De esta manera el resto del programa puede trabajar con enteros sin perder una presentación comprensible para el jugador.

ValorTruco()

Convierte cada carta a un valor de fuerza. Esto evita llenar el programa de comparaciones especiales cada vez que queremos decidir quién ganó una vuelta.

CalcularEnvido()

Analiza las tres cartas de una mano. Primero obtiene el valor individual de cada una y luego compara las tres posibles parejas para verificar si comparten palo.

MezclarMazo()

Usa Aleatorio() para implementar Fisher-Yates. Como solamente cambiamos posiciones de un mazo ya existente, no hay riesgo de generar cartas repetidas.

ResolverDespuesDeDos() y ResolverConTercera()

Estas funciones concentran las reglas de las pardas. Separarlas del proceso principal hace que la lógica de quién gana una mano sea mucho más fácil de leer y modificar.

La computadora

La CPU elige cartas disponibles al azar, pero algunas decisiones tienen una pequeña lógica. Por ejemplo, es más probable que acepte un Truco si posee al menos una carta fuerte y tiende a cantar Envido cuando su puntaje es alto.

No estamos intentando construir una inteligencia artificial perfecta: queremos una computadora suficientemente impredecible como para que el juego resulte entretenido y, al mismo tiempo, mantener el código accesible.

Un detalle importante sobre el azar

Aleatorio() aparece en varias partes del proyecto:

  • mezcla del mazo;
  • selección de cartas de la CPU;
  • decisión de aceptar o rechazar ciertos cantos;
  • decisión de la computadora de cantar Truco.

Por eso dos partidas no deberían desarrollarse exactamente igual.

Ideas para mejorar el proyecto

  • agregar Real Envido y Falta Envido;
  • implementar Flor;
  • jugar a 30 puntos;
  • hacer una CPU que analice las cartas ya jugadas;
  • permitir que la computadora mienta o “farolee” con más frecuencia;
  • guardar estadísticas de partidas ganadas y perdidas;
  • crear una versión para 2 jugadores humanos;
  • crear la modalidad 2 contra 2;
  • separar todavía más la lógica en nuevos SubProcesos.

Desafío

Como primer desafío, modificá la lógica de la computadora para que no elija siempre una carta completamente al azar. Por ejemplo, podría intentar jugar una carta baja cuando ya sabe que no puede ganar una vuelta o reservar su mejor carta para más adelante.

Después agregá Real Envido y Falta Envido. Ahí vas a tener que transformar el Envido en un verdadero sistema de apuestas encadenadas, de manera similar a lo que ya hicimos con Truco, Retruco y Vale Cuatro.

¿Te sirvió este proyecto? ☕

Si este juego te resultó útil y querés apoyar a Club Programador para que podamos seguir publicando ejercicios, proyectos y guías gratuitas, podés colaborar mediante:

☕ Apoyar con Mercado Pago

🌎 Apoyar con PayPal

Cualquier aporte ayuda a seguir creando contenido gratuito para aprender programación.

Seguí aprendiendo PSeInt

Este proyecto combina prácticamente todos los conceptos que fuimos viendo en la serie. Si necesitás repasar alguno, podés volver a la guía principal:

Aprender PSeInt: guía completa y ejercicios resueltos →


Descubre más desde Club Programador

Suscríbete y recibe las últimas entradas en tu correo electrónico.

Deja un comentario

Descubre más desde Club Programador

Suscríbete ahora para seguir leyendo y obtener acceso al archivo completo.

Seguir leyendo