Category Archives: Programas

Aprender inglés, ¿¡en C++!?

Me contó SetRoot a través de un comentario que se le ocurrió hacer un programa en C++ que nos ayudará a aprender palabras en inglés, en sus propias palabras:
Se me ocurrio hacer un programa para aprender ingles y creo que los tiros tambien van por ahi corrígeme:
1 llenar 1000 palabras
2 agruparlas por alguna relacion como emociones articulos y otros(para esto quisiera usar una matriz para acceder a ella mas facil aunque 2 matrices tambien creo q me van :s con punteros y eso ,s)
3 ejecucion: con un par de cases hacer un menu que me permita lanzar 20 palabras al azar(con sran o ran creo + time) con su significado
y despues que me permita hacer un tipo de examen o test con esas mismas palabras desordenadas que cada acierto valga algo para ganar puntos y asi involucrar a los amigos y familiares

Me gustó la idea de hacer un pequeño ‘bosquejo’ de su idea porque precisamente se necesita usar el código de mi último post: Números aleatorios sin repetir en C++. Así que mi algoritmo es algo así:

  1. Crear una matriz tipo string de N filas y 2 columnas, la primera columna son las palabras en inglés; la segunda, en español.
  2. Pedir el número de palabras que el usuario quiera memorizar.
  3. Obtener ese número de palabras aleatoriamente y mostrarlas.
  4. Borrar las palabras y empezar a preguntar el significado de cada una.
  5. Comparar la respuesta del usuario con la respuesta correcta.
  6. Calcular su calificación y mostrarla.

El código es este:

#include
#include
#include
using namespace std;

int nofw;
#define N 8 // numero de pares de palabras en la matriz

bool checkrep(int n, int num[])
{
    for(int i=0; i<nofw; i++)
        if(n == num[i])
            return true;
    return false;
}

int main()
{
    srand(time(NULL));
    string ans, words[N][2] = {{"hi", "hola"}, {"house", "casa"}, {"water", "agua"},
      {"roof", "techo"}, {"chair", "silla"}, {"loudspeaker", "bocina"},
      {"screen", "pantalla"}, {"money", "dinero"}};
    int n, correct=0, wrong=0;
    cout <> nofw;
    // obtener 'nofw' palabras aleatoriamente de nuestra matriz
    int num[nofw];
    for(int i=0; i<nofw; i++)
    {
        do
            n = rand() % N;
        while(checkrep(n, num));
        num[i] = n;
        cout << words[n][0] < " << words[n][1] << endl;
    }
    cin.get(); cin.get();
    system("cls");
    // preguntar el significado de cada palabra
    for(int i=0; i<nofw; i++)
    {
        cout << words[num[i]][0] <> ans;
        if(ans == words[num[i]][1])
        {
            correct++;
            cout <> Bien :)nn";
        }
        else
        {
            wrong++;
            cout <> Mal :(nn";
        }
    }
    cout << "Tuviste un " << (float)correct / (float)nofw * 100 <<
                "% de respuestas correctas.";
    cin.get(); cin.get();
}

Como dije antes, es sólo un bosquejo, pero tal vez sea el punto de partida para un buen proyecto. Para optimizarlo creo que se deberían agregar algunas cosas:

  • Obtener los pares de palabras desde una base de datos
  • Ordenarlas por categorías
  • Que no importe si la respuesta está en mayúsculas o minúsculas
  • Mejorar la interacción con el usuario
Advertisements

Números aleatorios sin repetir en C++

Ya hemos visto cómo obtener número aleatorios en c++, pero tarde o temprano surge la necesidad de generar números aleatorios pero sin que se repitan. Podría ser útil para varias cosas como por ejemplo, ordenar de manera aleatoria elementos de una lista, formas grupos aleatorios, barajear cartas, etc. Así que en algoritmo quedaría algo así:

  1. Crear una matriz y dejarla vacía.
  2. Obtener un número aleatorio.
  3. Checar si ese número existe en la matriz. Si si, regresar al paso 2. Si no, guardar el numero en la matriz.

Así que el programa es este:

#include
#include
#include
using namespace std;

bool checkrep(int n, int num[])
{
    for(int i=0; i<10; i++)
        if(n == num[i])
            return true;
    return false;
}

int main()
{
    srand(time(NULL));
    int n, num[10];
    for(int i=0; i<10; i++)
    {
        do
            n = 1 + rand() % 10;
        while(checkrep(n, num));
        num[i] = n;
        cout << num[i] << "  ";
    }
}

Primero que nada, <cstdlib> es la forma correcta de incluir la librería <stdlib.h> en c++, igual con <ctime>.

Como ven, usamos una función bool (que retorna falso o verdadero) para checar si el número aleatorio ya existe en nuestra matriz. Si cualquiera de los números es igual a nuestro número aleatorio n, la función retorna true, por lo que el ciclo do-while desde el cual llamamos la función tendrá que repetirse una vez más y hasta que la función retorne false.

Cuando se logra salir del ciclo do-while, guardamos nuestra n en el lugar de la matriz que corresponda, lo mostramos en pantalla y continuámos con la siguiente posición de la matriz.

Otra cosa. Para decirnos si un número está repetido en la matriz, la función checkrep() necesita obviamente dos cosas, el número aleatorio y la matriz. Así que le enviámos como parámetros nuestra matriz y nuestro número aleatorio.

Devolver cambio en C++

¿Han pagado algún recibo en una máquina automática y se han preguntado cómo será el programa que les devuelve el cambio? Lo más seguro es que no, pero pues resulta que el profesor de Miguel Ángel le encargó un programa que simulara eso, en sus propias palabras:

Supón que una maquina de monedas de 10,5,2,1 y 50 centavos. Debes escribir un programa que decida cuantas monedas dará de cambio, dando prioridad las de mayor denominación. Debe recibir como entrada la cantidad de dar a cambio. Ejemplo: para $40.50 será 4 de 10, 0 de 5, 0 de 2, 0 de 1 y 1 de 50 centavos.
Cambio
Así que el primer problema se presenta con la entrada ¿cómo hacer que el usuario introduzca sólo cantidades como $50 o $43.50 y no cantidades como $23.45 o $9.70?

Lo que se me ocurrió es pedir la cantidad en una variable float (cambio), en otra variable convertir esa cantidad a tipo int (cambioint). En ese proceso se perderá la parte decimal del número, así que si la resta cambio – cambioint es igual a 0 o igual a 0.50, la cantidad que introdujo el usuario es correcta.

La otra parte es sencilla, sólo se necesita ver si la variable cambio es mayor que 10. Si si,  se le restan 10 a la variable y se aumenta un contador. Luego se hace lo mismo con las demás monedas.

Pero bueno, el programa es este:

#include
using namespace std;

int main()
{
    float cambio; int cambioint, m10=0, m5=0, m2=0, m1=0, m50c=0;
    do
    {
        cout <> cambio;
        cambioint = (int)cambio;
    }while((cambio - cambioint) != 0 && (cambio - cambioint) != 0.50);
    while(cambio != 0)
    {
        if(cambio>=10)
        {
            m10++;
            cambio-=10;
        }
        else if(cambio>=5)
        {
            m5++;
            cambio-=5;
        }
        else if(cambio>=2)
        {
            m2++;
            cambio-=2;
        }
        else if(cambio>=1)
        {
            m1++;
            cambio-=1;
        }
        else if(cambio>=0.5)
        {
            m50c++;
            cambio-=0.5;
        }
    }
    cout << m10 << ", " << m5 << ", " << m2 << ", " << m1 << ", " << m50c;
}

Solo le faltaría darle un poco de formato a la salida, pero pues ya es cuestión de gustos y ya saben, cualquier duda aquí están los comentarios abajo.

Simular una Progress Bar en C++

Una progress bar es la barrita, generalmente verde, que aparece en sistemas operativos e infinidad de programas cuando algo se está cargando. Hoy no nos vamos a meter en asuntos de cargar archivos o algo, únicamente vamos a ver el principio básico sobre el que operan estas barras.

Nuestro programa sólo pedirá una cantidad en segundos, que será el tiempo que durará en llenarse nuestra progress bar. A la ventana donde se ejecutan nuestros programas le caben 80 caracteres de largo, así que vamos a decir que nuestra progress bar tiene una resolución de 80. El único problema es saber cuánto durará cada unidad de esas 80 para que en total se acumule el tiempo indicado.

La función delay() o Sleep()

Si en su IDE pueden usar la librería conio.h, entonces van a usar la función delay(). Si no, vamos a tener que agregar la librería windows.h y usar la función Sleep() (así con mayúscula).

Ambas funciones hacen exactamente lo mismo: paran el programa durante una cierta cantidad de tiempo en milisegundos. Por ejemplo:
cout << "Hola" << endl;
Sleep(2000);
cout << "Hace dos segundos te saludé!";

Se muestra ‘Hola’, se pausa 2 segundos y se muestra ‘Hace dos segundos te saludé!’

Para los que usan conio.h, sería algo así:
printf("Holan");
delay(2000);
printf("Hace dos segundos te saludé!");

Ahora sí, para saber cuanto tiempo durará cada unidad de nuestra barra tenemos primero que convertir los segundos a milisegundos (s*1000), luego dividirlos entre la resolución de la barra (s*1000/80). Así que nuestro programa queda así:

#include
#include
using namespace std;

int main()
{
    int s;
    cout <> s;
    for(int i=0; i<=79; i++)
        cout << "_";
    for(int i=0; i<=79; i++)
    {
        cout << "=";
        Sleep(s*1000/80);
    }
}

El primer ciclo es solo por estética, para ver hasta donde va a llenar la barra. El segundo es el que imprime la barra con sus respectivas pausas.

Saber si es palíndromo o no, de forma recursiva 2da parte

Pues la idea que se me ocurrió en el otro post resultó ser más sencilla de lo que me imaginé, y ahora sí la función recursiva se ve mucho mejor, ya es mucho más que un ciclo disfrazado.

Comenté extensivamente el código, así que aquí está:

#include
#include
using namespace std;
int len, n=0;

string chk4palindrosity(string thestr)
{
    if(thestr[0] == thestr[thestr.length() - 1]) // comparar primer caracter con ultimo
    {
        n++;
        if(n == len / 2) // si el numero de veces que la comparación ha sido cierta es...
            return "Si es palindromo!"; // igual a la mitad de los caracters, es palindromo
        thestr.erase(0, 1); // borramos primer caracter
        thestr.erase(thestr.length() - 1, 1); // borramos ultimo
        return chk4palindrosity(thestr); // llamamos a la función con el string recortado
    }
    else // si una de las comparaciones no es cierta, no es palíndromo
        return "No es palindromo";
}

int main()
{
    char inputf[50]={0}, input[50], *parte;
    cout<<"Introduce un palindromo: "; cin.getline(input, 'n');

    parte = strtok(input, " ");                 //
    strcat(inputf, parte);                     //
    while((parte = strtok(NULL, " ")) != NULL) //
        strcat(inputf, parte);               // quitar espacios del array

    string thestr(inputf); // convertir array en string para facilitar operaciones
    len = thestr.length(); // obtener longuitud del string
    if(len == 1)
        cout << "Si es palindromo!";
    else
        cout << chk4palindrosity(thestr); // llamar a la funcion e imprimir lo que retorne
    cin.get();
}

Lo que hace la función recursiva es comparar el primer caracter con el último, si son iguales recortarlos y llamarse; si no, no es palíndromo. Cualquier duda ya saben que los comentarios están abiertos.

Saber si es palíndromo o no, de forma recursiva

Hace unos días me pidieron por correo un programa que nos dijera si un string es palíndromo o no, pero usando una función recursiva. Me pareció interesante aunque raro que pidieran hacerlo de forma recursiva.

Tal vez recuerden que ya había publicado aquí una forma de saber si un string es palíndromo o no, el cual he descubierto (ahora que hice este otro) que no es muy eficiente.

Bueno pues el código es este:

#include
#include
using namespace std;
char cadenaf[50]={0}; int len, n=0;

string chk4palindrosity(int c)
{
    if(cadenaf[c] == cadenaf[len-1-c])
    {
        n++;
        if(n == len/2)
            return "Si es palindromo!";
        return chk4palindrosity(c+1);
    }
    else
        return "No es palindromo";
}

int main()
{
    char cadena[50],*parte;
    cout<<"Introduce un palindromo: "; cin.getline(cadena,50,'n');

    parte = strtok(cadena," ");                 //
    strcat(cadenaf,parte);                     //
    while((parte = strtok(NULL," ")) != NULL) //
        strcat(cadenaf,parte);               // quitar espacios del string

    len = strlen(cadenaf);
    cout << chk4palindrosity(0);
    cin.get();
}

La verdad es que es la función es recursiva de puro milagro. Lo que hice fue transformar el ciclo que checaba que los caracteres fueran iguales en una función en la que se aumenta una variable cada vez que se llama a sí misma.

El código ahora es más eficiente por dos simples razones:

  1. Se detiene y da el resultado a la primera comparación de caracteres que no sean iguales. Si el primer y el último caracter no son iguales, no es palíndromo y ya no sigue analizando los demás.
  2. Sólo checa la mitad de los caracteres. Si la mitad de los caracteres corresponden a la configuración de un palíndromo, ya no hay porqué seguir analizando la otra mitad.

Tal vez una mejor manera de hacerlo sería con una función que recibiera el string a analizar, comparar el primer y último caracter: si no, no es; si si, eliminar el primer y último caracter y volver a llamar a la función. Esto hasta que el numero de comparaciones ciertas sea igual a la mitad de la longitud inicial del string. ¿Alguien se anima a hacerlo?

Imprimir determinados números primos

Sobre números primos he escrito bastantes programas y me he dado cuenta de que los profesores de programación tienen cierta fijación con ellos. Pero bueno, el programa de hoy imprime la cantidad de números primos que el usuario quiera y es interesante porque es un buen ejemplo de la utilidad de los ciclos infinitos, que ya habíamos visto antes.

Ok, el código es este:

#include
using namespace std;

int main()
{
    int cnt,i=0,ii,res,nc=0,np=0;
    cout <> cnt;
    for(;;)
    {
        i++;
        for(ii=1;ii<=i;ii++)
        {
            res=i%ii;
            if(res==0)
                nc=nc+1;
        }
        if(nc==2)
        {
            cout << i << " ";
            np++;
        }
        nc=0;
        if(np==cnt)
            break;
    }
}

Si tienen problemas para entender cómo obtuvimos los números primos, deberían darle una revisada a estos posts: Saber si es primo o no y Primos en un rango.

Lo que hicimos es que todo el programa estuviera dentro de un ciclo infinito que se detendrá cuando nuestra variable que se aumenta cada vez que obtenemos un numero primo np sea igual a la variable con la cantidad deseada de números primos cnt.

Pero recuerden que donde podemos usar un ciclo infinito, queda mucho mejor un ciclo while:

#include
using namespace std;

int main()
{
    int cnt,i=0,ii,res,nc=0,np=0;
    cout <> cnt;
    while(np!=cnt)
    {
        i++;
        for(ii=1;ii<=i;ii++)
        {
            res=i%ii;
            if(res==0)
                nc=nc+1;
        }
        if(nc==2)
        {
            cout << i << " ";
            np++;
        }
        nc=0;
    }
}

Únicamente ponemos la palabra while en lugar de for, copiamos la condición que ‘condicionaba’ (sí, lo se) el break y la pegamos dentro de los paréntesis del while pero de manera contraria (de == a != o de ).

Clasificar números en C++

Por medio de un comentario Gaby me pidió un programa que:

“Genere 10 números aleatorios del 0 al 50 y los clasifique en 2 rangos: menores que 10 y mayores que 10 pero menores que 20.”

A nosotros nos sirve para practicar el uso de números random, de matrices y de ciclos.

El programa es este:

#include
#include
#include
using namespace std;
int main()
{
    int numrnd[10], cls1[10]={0}, cls2[10]={0}, ct1=0, ct2=0;
    srand(time(NULL));
    cout << "Los numeros: ";
    for(int i=0; i<=9; i++)
    {
        numrnd[i] = rand() % 51;
        cout << numrnd[i] << ", ";
        if(numrnd[i]  10 && numrnd[i] < 20)
        {
            cls2[ct2] = numrnd[i];
            ct2++;
        }
    }
    cout << endl << "Menores que 10: ";
    for(int i=0; i<ct1; i++)
        cout << cls1[i] << ", ";
    cout << endl << "Mayores que 10 y menores que 20: ";
    for(int i=0; i<ct2; i++)
        cout << cls2[i] << ", ";
}
  • Para dudas respecto a la generación de números random está este post: Obtener números aleatorios en C++.
  • Para dudas respecto a la declaración y uso de matrices está este otro post: ¡Ah nunca he escrito sobre matrices!, voy a tener que ponerme a ello.
  • Para dudas con respecto a los ciclos for, sí tengo un post: Ciclos for en C++.

Tenemos 3 matrices, en la primera guardamos nuestros 10 números aleatorios, en la segunda los números que queden en la primera clasificación (menores que 10) y en la tercera los que queden en la segunda clasificación. Así que lo que hacemos es ir traspasando los valores de la primera matriz a las otras dos según su valor. Para esto tenemos que llevar en el mismo ciclo 3 cuentas diferentes, una para cada matriz.

Las variable ct1 y ct2 se encargan de ir cambiando los índices de las matrices cls1 y cls2 respectivamente, por lo que sólo deben aumentar cuando en realidad sea necesario.

Después lo único necesario es mostrar nuestras dos matrices. Como cada matriz puede tener un número de elementos diferentes cada vez, tenemos que hacer dos ciclos, uno para cada matriz con ct1 o ct2 como límite.

Como última aclaración sólo digo que, tal como dice el problema, el número 10 nunca va a quedar clasificado en algún rango porque el 10 no es menor que 1o y tampoco es mayor que 10.

Convertir segundos a horas, minutos y segundos

Como les prometí en el post anterior, en este post vamos a hablar sobre un programa que usa los operadores compuestos de manera muy útil: convierte los segundos en horas minutos y segundos.

El programa es este:

#include 
using namespace std;

int main()
{
    int sec, hr, min;
    cout <> sec;
    cout << sec << " segundos son ";
    hr = sec / (60*60);
    sec %= 60*60;
    min = sec / 60;
    sec %= 60;
    cout << hr << " horas " << min << " minutos y " << sec << " segundos" << endl;
}

Primero dividimos los segundos sec entre 60*60 (3600) para obtener los horas y lo guardamos en hr. Noten que la variable sec no cambia.

Luego obtenemos el residuo de dividir sec / 60*60 (es lo que el operador % hace) y lo guardamos en la misma variable. En este paso sí modificamos la variable sec, ahora contiene los segundos iniciales menos las horas que ya obtuvimos en el paso anterior.

Ahora dividimos nuevamente la variable sec / 60 para obtener los minutos y lo guardamos en hr. La variable sec no cambia.

Luego obtenemos el residuo de dividir sec / 60 (es lo que el operador % hace) y lo guardamos en la misma variable. En este paso sí modificamos la variable sec, ahora contiene los segundos iniciales menos las horas menos los minutos.

Ya sólo mostramos las tres variable y listo.

Ahora, si somos de los que nos preocupamos por el lenguaje, veremos que a veces hay errores de ortografía como “1 minutos”. Para solucionar eso sólo necesitamos unos cuantos ifs:

#include 
using namespace std;

int main()
{
    int sec, hr, min;
    cout <> sec;
    cout << sec << " segundos son ";
    hr = sec / (60*60);
    sec %= 60*60;
    min = sec / 60;
    sec %= 60;
    cout << hr << " hora";
    if(hr != 1) cout << "s";
    cout << " " << min << " minuto";
    if(min != 1) cout << "s";
    cout << " y " << sec << " segundo";
    if(sec != 1) cout << "s";
}

Cómo pasar una matriz o arreglo como parámetro a una función

Bueno, casi creo que nunca he hablado de matrices, parámetros o funciones en este blog, pero este post es una petición de Rodrigo que me dijo por email que tenía problemas con su tarea porque no sabe cómo pasar una matriz como parámetro a una función en c++. Es algo sencillo, pero difícil de deducir. Veamos.

Si tu arreglo es de una dimensión…
int matriz[4];
… la forma de declarar la función es la siguiente:
void fx(int m[4]) { ...código... }
Y la forma de llamar la función sería:
fx(matriz);

Si el arreglo es de dos dimensiones…
int matriz[4][3];
… pues es lo mismo:
void fx(int m[4][3]) { ...código... }
Y la forma de llamar la función sería:
fx(matriz);

Si la función retorna una matriz…
int matriz[4];
… se declara normal:
void fx(int m[4]) { return matriz[4]; }
Y la forma de llamar la función sería:
matriz[4] = fx(matriz);

Este programa pide tres números, los almacena en una matriz, le suma 1 a cada elemento y los muestra, usando para cada acción una función. Así que tenemos funciones que reciben matrices y que retornan matrices. Chéquenlo.

#include
using namespace std;

void pedir(int matriz[3], int len)
{
    for(int i=0; i<=len; i++)
    {
        cout << "Numero " << i+1 <> matriz[i];
    }
}

int sumar(int matriz[3], int len)
{
    for(int i=0; i<=len; i++)
        matriz[i]++;
    return matriz[3];
}

void mostrar(int matriz[3], int len)
{
    for(int i=0; i<=len; i++)
        cout << matriz[i] << " ";
}

int main()
{
    int matriz[3]={0}, len = sizeof(matriz)/sizeof(int);
    pedir(matriz, len-1);
    matriz[3] = sumar(matriz, len-1);
    mostrar(matriz, len-1);
    return 0;
}