4. Curso C++: Operadores en C++ - Una Guía Completa

4. Curso C++: Operadores en C++ - Una Guía Completa

Los operadores son elementos que disparan ciertos cálculos cuando se aplican a variables u otros objetos en una expresión. En esta guía, aprenderemos sobre los diferentes tipos de operadores en C++, cómo se utilizan y sus particularidades.

1. Definiciones Básicas 📚

  • Variable: Entidad que almacena un valor que puede cambiar durante la ejecución del programa.

  • Operando: Constante, variable o expresión que interviene en una operación.

  • Operador: Símbolo que indica las operaciones a realizar sobre los operandos.

  • Expresión: Conjunto de operadores y operandos que da como resultado un valor.

Por ejemplo, en la expresión a + b, a y b son operandos, + es el operador, y todo junto forma una expresión que devuelve un valor.

2. Tipos de Operadores

Los operadores se pueden clasificar según el número de operandos que afectan:

  • Unitarios: Afectan a un solo operando.

  • Binarios: Afectan a dos operandos.

  • Ternarios: Afectan a tres operandos.

Veamos cada tipo en detalle.

3. Operadores Aritméticos

Los operadores aritméticos se usan para crear expresiones matemáticas. Hay dos operadores aritméticos unitarios:

  • + <expresión> y - <expresión>: Asignan valores positivos o negativos a la expresión.

Ejemplo:

int x = -5; // Aplicación de operador unitario

Existen también varios operadores binarios: +, -, *, /, que admiten tanto expresiones enteras como en coma flotante.

Ejemplo:

int a = 10;
int b = 3;
int suma = a + b;    // Resultado: 13
int resta = a - b;   // Resultado: 7
int producto = a * b; // Resultado: 30
float division = a / (float)b; // Resultado: 3.3333
  • Operador Módulo %: Devuelve el resto de la división entera entre dos operandos. Solo funciona con operandos enteros.

Ejemplo:

int resto = 17 % 7; // Resultado: 3

Resumen Rápido de los Operadores Aritméticos

OperadorDescripciónEjemplo
+Sumaa + b
-Restaa - b
*Multiplicacióna * b
/Divisióna / b
%Módulo (resto división)a % b

4. Operadores de Asignación 🖊️

El operador más común es el =, que asigna un valor a una variable. Además, existen operadores compuestos que combinan una operación con una asignación:

  • +=, -=, *=, /=, %=

Ejemplo:

int a = 10;
a += 5; // Es equivalente a: a = a + 5; Resultado: 15

Estos operadores permiten escribir el código de forma más concisa y clara.

Tabla de Operadores de Asignación

OperadorDescripciónEjemplo
=Asignación simplea = b
+=Suma y asignacióna += b
-=Resta y asignacióna -= b
*=Multiplicación y asignacióna *= b
/=División y asignacióna /= b

5. Operadores de Incremento y Decremento 🔄

  • ++ y --: Incrementan o decrementan una variable en una unidad. Pueden usarse en modo prefijo o sufijo.

Ejemplos:

int b = 10;
int c = ++b; // Pre-incremento: b vale 11, c también vale 11
int d = b--; // Post-decremento: d vale 11, luego b vale 10

En su forma de prefijo (++b), el operador incrementa el valor antes de evaluarlo en el resto de la expresión. En la forma sufijo (b++), se evalúa primero la expresión y luego se incrementa.

6. Operadores Lógicos y de Comparación ⚖️

  • Operadores Lógicos: && (AND), || (OR), ! (NOT). Permiten combinar expresiones lógicas.

  • Operadores de Comparación: ==, !=, <, >, <=, >=. Se usan para comparar dos valores y devolver un booleano (true o false).

Ejemplo:

int a = 5;
int b = 10;
bool resultado = (a < b) && (b > 0); // Resultado: true

Tabla de Operadores de Comparación

OperadorDescripciónEjemplo
==Igualdada == b
!=Desigualdada != b
<Menor quea < b
>Mayor quea > b
<=Menor o igual quea <= b
>=Mayor o igual quea >= b

7. Desafío Práctico 🚀

¿Podés adivinar el resultado de este código?

int a = 5;
int b = 3;
int resultado = a++ + ++b;
// ¿Cuál es el valor final de `resultado`?

Pista: Presta atención a cómo se incrementan a y b en cada paso 😏.

3. Curso C++: Funciones I - Declaración y Definición

3. Curso C++: Funciones I - Declaración y Definición

Las funciones en C++ son un conjunto de instrucciones que realizan una tarea específica. En general, toman ciertos valores de entrada, llamados parámetros, y proporcionan un valor de salida o valor de retorno. En C++, tanto los parámetros como el valor de retorno son opcionales, pero comprender el concepto de las funciones es esencial para escribir código modular y reutilizable.

Las funciones son fundamentales en C++, ya que todos los programas contienen al menos una función: la función main(). Comprender cómo funcionan las funciones es crucial para escribir código eficiente. Vamos a explorar cómo se declaran y se definen las funciones en un programa C++.

1. Prototipos de Funciones en C++ 📋

En C++, es obligatorio usar prototipos. Un prototipo es una declaración previa de una función que indica al compilador qué esperar. Básicamente, es la estructura de la función sin el cuerpo y termina con un punto y coma (;). Los prototipos permiten que el compilador valide llamadas a funciones antes de que estas se definan.

Estructura de un Prototipo de Función:

[tipo de almacenamiento] <tipo_valor_retorno> <nombre_función>(<lista_parámetros>);
  • Tipo de almacenamiento: Puede ser extern o static. Si no se especifica, será extern por defecto. Por el momento, solo usaremos funciones extern.

  • Tipo de valor de retorno: Define qué tipo de dato devolverá la función. Si no devuelve nada, usamos void.

  • Nombre de la función: Debe ser descriptivo. Es buena práctica usar nombres claros como BuscaTelefono o calculaPromedio, lo que facilita la lectura del código.

  • Lista de parámetros: Son los valores de entrada. Pueden ser variables de cualquier tipo y se separan con comas. Si no hay parámetros, se usan paréntesis vacíos: func().

Ejemplo de Prototipo de Función:

int Mayor(int a, int b);

Este prototipo indica que la función Mayor aceptará dos enteros como parámetros y devolverá un entero.

Nota: Los nombres de los parámetros son opcionales en el prototipo, pero agregarlos mejora la comprensión del código.

2. Definición de Funciones en C++ ✍️

Después de declarar una función, debemos definirla, es decir, proporcionar el cuerpo de la función con las instrucciones que se ejecutarán cuando la función sea llamada.

Sintaxis de una Definición de Función en C++:

[tipo de almacenamiento] <tipo_valor_retorno> <nombre_función>(<lista_parámetros>) {
  // Cuerpo de la función
  [sentencias]
}
  • Tipo de almacenamiento: Igual que en el prototipo (extern o static).

  • Cuerpo de la función: Las instrucciones que ejecutará la función.

Ejemplo de Definición de Función:

int Mayor(int a, int b) {
  if (a > b) {
    return a;
  } else {
    return b;
  }
}

En este ejemplo, la función Mayor toma dos enteros y devuelve el mayor de ambos.

3. La Función main() en C++ 🏁

La función main() es especial porque es el punto de entrada de cualquier programa en C++. Su definición siempre debe existir para que el programa pueda ejecutarse correctamente.

Ejemplo de Función main() en C++:

int main() {
  // Código principal
  return 0; // Indica que el programa terminó correctamente
}

El valor 0 indica que el programa finalizó sin errores. Otros valores se usan para indicar errores específicos.

4. Prototipos vs. Definiciones en C++ ⚖️

  • Prototipos: Son útiles para indicar al compilador la existencia de una función antes de su uso. Permiten definir el flujo del programa sin importar el orden de las funciones en el código.

  • Definiciones: Son la implementación real de la función. Deben proporcionar el cuerpo con el código que realiza la tarea.

En C++, los prototipos de funciones suelen ubicarse al principio del archivo o en ficheros de cabecera (.h), que luego se incluyen con #include.

5. Ejemplo Completo de un Programa en C++ 🖥️

#include <iostream>

// Prototipo de función
int Mayor(int a, int b);

int main() {
  int x = 5;
  int y = 10;
  int resultado = Mayor(x, y);
  std::cout << "El mayor es: " << resultado << std::endl;
  return 0;
}

// Definición de la función
int Mayor(int a, int b) {
  return (a > b) ? a : b;
}

En este programa, el prototipo de la función Mayor se declara antes de main(), y luego se define al final. Esto asegura que el compilador conozca la función cuando se usa en main().

6. Resumen Rápido sobre Funciones en C++ 📜

  • Prototipo: Declara la función e indica al compilador qué esperar.

  • Definición: Implementa la función y contiene el código ejecutable.

  • main(): Punto de entrada de cualquier programa en C++.

7. Desafío Práctico sobre Funciones en C++ 🚀

Escribe una función llamada Menor que tome dos números enteros y devuelva el menor de los dos. Declara el prototipo al principio del archivo y luego define la función después de main(). ¿Podés hacerlo? 😊

2. Curso C++: Tipos de Variables - Introducción Completa

2. Curso C++: Tipos de Variables - Introducción Completa

Conceptualmente, desde el punto de vista de un programador, una variable es una entidad cuyo valor puede cambiar a lo largo de la ejecución de un programa.

A nivel más bajo, una variable se almacena en la memoria del ordenador. Esa memoria puede estar compuesta de semiconductores, ciertos campos magnéticos en la superficie de un disco, polarizaciones en una memoria de ferrita, o cualquier otra tecnología que esté por venir. Por suerte, no necesitamos preocuparnos por esos detalles tan técnicos. Lo importante es saber que la información se almacena en forma binaria. El tipo de variable es lo que nos permite definir cómo interpretar esa información binaria.

En un nivel más lógico, una variable ocupa un espacio de memoria reservado para contener sus valores durante la ejecución del programa. Cada variable debe tener un tipo, y ese tipo determina tanto el tamaño del espacio de memoria como la manera en que se manipula la información.

En este capítulo, veremos los tipos fundamentales: void, char, int, float, double, y en C++ también el tipo bool. Además, existen modificadores como short, long, signed, y unsigned, que permiten ajustar ciertas propiedades de los tipos. También aprenderemos sobre los tipos enumerados, enum.

1. Sintaxis y Tipos de Variables

A partir de ahora, mostraremos las definiciones de la sintaxis para las diferentes sentencias en C++. Esto nos ayudará a entender las opciones, las partes obligatorias y opcionales, y dónde colocar los identificadores.

Ejemplo de Sintaxis para Declarar una Variable char:

[signed | unsigned] char <identificador>[, <identificador2>, ...];
  • Se puede usar signed o unsigned, o ninguna de las dos (en cuyo caso, se asume signed por defecto).

  • Luego de char debe escribirse un identificador que será el nombre de la variable.

  • Opcionalmente, podemos declarar más variables del mismo tipo separándolas con comas.

  • Finalmente, la declaración termina con un punto y coma (;).

Reglas para Crear Identificadores:

  • Solo se pueden usar letras, números y ciertos caracteres como el guion bajo (_).

  • El primer carácter no puede ser un número.

  • C++ distingue entre mayúsculas y minúsculas, así que numero y Numero son diferentes.

  • Las palabras reservadas de C++ (como char, int, float, etc.) no se pueden usar como identificadores.

Ejemplos de Declaración de Variables Válidas:

signed char cuenta, cuenta2, total;
unsigned char letras;
char caracter, inicial, respuesta;
signed char _letra;

2. Tipos Fundamentales de Variables

Veamos los tipos fundamentales uno por uno y cómo afectan los modificadores.

Tipo char o Carácter

El tipo char almacena un solo carácter, ya sea una letra, un dígito o un signo de puntuación. Ocupa 1 byte en memoria y puede ser signed (valores entre -128 y 127) o unsigned (valores entre 0 y 255).

Este tipo de variable también se puede usar para almacenar números pequeños debido a la correspondencia entre números y caracteres definida por el código ASCII.

Ejemplo de Declaración:

char letra = 'A';
unsigned char numero = 65;

Tipo int o Entero

Las variables int almacenan números enteros. Pueden ser short, long, o incluso long long, dependiendo del tamaño del valor que necesitemos almacenar. Los modificadores signed y unsigned también se aplican aquí.

Ejemplos:

int numero = 100;
unsigned long int cantidad = 1000000;
short int edad = 25;

Estas variables son ideales para almacenar valores enteros que no tienen decimales, como edades o cantidades.

Tipo float o Coma Flotante

Las variables float almacenan números reales con decimales. Utilizan un formato de mantisa y exponente para representar números muy grandes o muy pequeños. Sacrifican precisión para representar un mayor rango de valores.

Ejemplo:

float temperatura = 36.6;

Este tipo de variable es útil para representar valores con decimales, como temperaturas o tasas de cambio.

Tipo double o Coma Flotante de Doble Precisión

Las variables double también almacenan números reales, pero con mayor precisión que float. Utilizan más memoria y se prefieren cuando la precisión es importante.

Ejemplo:

double distancia = 1234567.89;

Tipo bool o Booleano

Las variables bool solo pueden tener dos valores: true o false. Se utilizan para almacenar respuestas lógicas o evaluar condiciones.

Ejemplo:

bool esMayor = true;

Este tipo es muy útil para manejar condiciones y lógica de control.

Tipo void o Sin Tipo

El tipo void indica ausencia de tipo. No se puede usar para declarar variables, pero se usa para funciones que no devuelven un valor.

Tipo enum o Enumerado

El tipo enum permite definir conjuntos de constantes enteras. Las variables de tipo enum solo pueden tomar valores predefinidos dentro de su dominio.

Ejemplo de Declaración:

enum Dia { Lunes, Martes, Miercoles, Jueves, Viernes };
Dia hoy = Miercoles;

3. Desafío Práctico 🚀

Declara una variable de cada tipo que hemos visto en este capítulo e inicialízala con un valor adecuado. ¿Podés hacerlo?

1. Curso C++: Un Pequeño Código para Comenzar

1. Curso C++: Un Pequeño Código para Comenzar

La forma más rápida e interesante de empezar, sin perder potenciales seguidores de este curso, es mediante un ejemplo. Veamos nuestro primer programa en C++ para establecer una base útil que nos ayudará en futuros ejemplos.

int main() {
    int numero;
    numero = 2 + 2;
    return 0;
}

No te preocupes demasiado si no captas todos los detalles de este pequeño programa. Aprovecharemos la ocasión para explicar algunas de las peculiaridades de C++. De hecho, este programa es casi un ejemplo de C puro, y eso es porque C++ incluye a C. En general, un programa escrito en C podrá compilarse utilizando un compilador de C++. Más adelante, veremos las diferencias en detalle.

Iremos repasando el programa, línea a línea:

1. Primera línea: int main()

Se trata de una línea muy especial y la encontrarás en todos los programas en C y C++. Define el comienzo de una función. Todas las funciones en C y C++ toman valores de entrada, llamados parámetros o argumentos, y devuelven un valor de salida o retorno.

  • int nos dice el tipo de valor de retorno de la función. En este caso, es un número entero (integer). La función main siempre devuelve un entero.

  • main es el nombre de la función, y es muy especial, ya que el sistema operativo la llama automáticamente para comenzar la ejecución del programa. Nunca encontraremos en el código una llamada explícita a main().

  • Los paréntesis () indican que main es una función. En este caso, la lista de argumentos está vacía, lo que significa que no tiene parámetros de entrada.

2. Segunda línea: {

Esta llave abre el cuerpo de la función main. Todo lo que está entre { y } forma parte de la definición de la función. Más adelante veremos que las llaves tienen otros usos, pero aquí simplemente indican el inicio del código de la función.

3. Tercera línea: int numero;

Esta es nuestra primera sentencia. Todas las sentencias terminan con un punto y coma (;). Esta en particular es una declaración de variable. Declara una variable llamada numero de tipo int (entero). Al declarar una variable, el compilador reserva un espacio en la memoria para ella, pero no se le asigna ningún valor inicial, lo que significa que puede contener cualquier cosa ("basura") hasta que se le asigne un valor.

4. Quinta línea: numero = 2 + 2;

Esta es una sentencia de asignación. Asigna a la variable numero el valor resultante de la expresión 2 + 2. Después de ejecutar esta línea, numero contendrá el valor 4.

5. Sexta línea: return 0;

return es una palabra reservada que indica que la función debe terminar y devolver un valor. En el caso de main, devolver 0 significa que el programa se ejecutó correctamente. Si el programa retorna un valor distinto de 0, suele indicar que ocurrió un error.

6. Séptima línea: }

Esta es la llave que cierra el cuerpo de la función main. Con esto, terminamos la definición de nuestra función.

Resumen

Aunque este programa suma 2 + 2 correctamente, no muestra ningún resultado ni acepta entradas externas. Es decir, es "inútil" desde una perspectiva práctica, pero es una excelente manera de empezar a familiarizarte con la estructura de un programa en C++.

En los siguientes capítulos, exploraremos conceptos básicos como variables, funciones, y operadores. Con estos conocimientos, podremos crear programas más complejos e interactivos. ¡Paciencia y sigamos aprendiendo! 😊

0. Introducción al Curso C++

0. Introducción al Curso C++

¡Hola lectores! Hoy les traigo un pequeño curso que espero sea de su agrado, especialmente para aquellos que se inician en este maravilloso lenguaje de programación.

He intentado que los ejemplos que ilustran cada capítulo sean compatibles con cualquier versión de compilador. Sin embargo, les cuento que yo he usado el compilador MinGW (Minimalist GNU for Windows), que es una versión para Windows del compilador GCC para Unix y Linux. Este compilador está adaptado para crear programas en Windows, pero cualquier programa que siga el estándar de C++ debería funcionar con este compilador en Windows y Linux.

Para hacer más cómodo el desarrollo de nuestros programas, recomiendo usar un IDE (Entorno de Desarrollo Integrado), como Dev-C++ de Bloodshed o Code::Blocks, ambos perfectos para crear programas en modo consola.

Vale aclarar que los programas de Windows tienen dos modos para interactuar con el usuario:

  • Modo consola: Simula el funcionamiento de una ventana MS-DOS y trabaja en modo de texto. En este modo, la ventana funciona como una especie de tabla donde cada casilla puede contener un solo carácter. No permite usar gráficos de alta resolución, pero esto no representa una gran pérdida para nosotros, ya que C y C++ no incluyen por defecto herramientas para trabajar con gráficos. Esto se logra mediante bibliotecas externas.

  • Modo GUI (Interfaz Gráfica de Usuario): Este es el modo tradicional de los programas de Windows, con ventanas, menús, íconos, etc. La creación de este tipo de programas se explica en otro curso, y requiere conocimientos sobre la biblioteca de funciones WinAPI32.

Para quienes trabajan en otros entornos, como Linux, Unix o Mac, el entorno Dev-C++ no será compatible, ya que está diseñado para Windows. Sin embargo, todos los sistemas operativos cuentan con compiladores de C++ que soportan la norma ANSI, que es el estándar que buscaremos seguir para garantizar la compatibilidad de nuestros programas en cualquier sistema operativo.

Compiladores y la Norma ANSI

El ANSI define un conjunto de reglas que cualquier compilador de C o C++ debe cumplir para ser considerado como tal. Estas reglas determinan cómo deben comportarse las palabras reservadas, los elementos del lenguaje y las funciones externas incluidas. Si un programa está escrito siguiendo el estándar ANSI, debería poder compilarse en cualquier compilador que cumpla con esta norma.

Aunque todos los compiladores suelen incluir características adicionales no estándar (como bibliotecas gráficas), mientras no usemos esas funcionalidades, nuestros programas serán portables, es decir, funcionarán en cualquier ordenador y sistema operativo.

Proceso de Obtención de un Programa Ejecutable

Probablemente sea un buen momento para explicar cómo se obtiene un fichero ejecutable a partir de un programa C++.

Código Fuente y Fichero Fuente

Los programas en C y C++ se escriben con la ayuda de un editor de textos, como si fuera un documento cualquiera. Estos ficheros que contienen el código del programa se conocen como ficheros fuente, y el texto en su interior es el código fuente. Nosotros siempre escribiremos programas fuente y los guardaremos en ficheros fuente.

Compiladores vs. Intérpretes

C y C++ son lenguajes compilados, no interpretados. La diferencia entre ambos enfoques es importante:

  • En un lenguaje interpretado, como BASIC o Java, el programa fuente es procesado por un intérprete que traduce y ejecuta el programa en tiempo real, línea a línea.

  • En los lenguajes compilados, el código fuente se traduce una sola vez, generando un fichero ejecutable que puede correr de forma autónoma sin necesidad del compilador.

Los lenguajes compilados tienden a ser más rápidos y requieren menos recursos que los lenguajes interpretados, ya que el proceso de traducción ocurre sólo una vez.

Ficheros Objeto y Bibliotecas

Cuando compilamos un programa, el compilador genera un fichero objeto, que es una traducción del código fuente en un formato comprensible para el ordenador. Para que el programa sea ejecutable, este fichero objeto debe ser combinado con otras bibliotecas (que contienen código reutilizable, como funciones para leer el teclado o escribir en pantalla) mediante un proceso conocido como enlazado.

El enlazador es el programa encargado de unir todos los ficheros objeto y las bibliotecas necesarias para crear un fichero ejecutable.

Errores Comunes en Programación C++

Durante el proceso de creación de programas, es normal cometer errores. Estos errores se dividen en varias categorías:

  • Errores de sintaxis: Ocurren cuando escribimos mal alguna parte del código fuente. Estos errores se detectan durante la fase de compilación.

  • Avisos (warnings): Son errores menores que no impiden la generación del código objeto, pero deben ser corregidos para evitar comportamientos inesperados.

  • Errores de enlazado: Suceden cuando faltan definiciones de funciones o variables que deberían estar en los ficheros objeto o bibliotecas.

  • Errores de ejecución: Se producen cuando el programa se ejecuta, a veces provocando que termine bruscamente. Estos errores son más difíciles de detectar y corregir.

  • Errores de diseño: Los más difíciles de evitar, ya que ocurren debido a fallos en el enfoque o la lógica del programa.

Curso C++: Eliminar Carpetas y Archivos

Curso C++: Eliminar Carpetas y Archivos

Eliminar directorios completos en C++ puede ser un reto, especialmente cuando se busca hacerlo de manera segura y eficiente. En este capítulo, les mostraré un código que permite eliminar archivos o directorios, incluyendo subcarpetas y archivos contenidos. Veremos cómo funciona y algunas consideraciones importantes.

Ejemplo de Código para Eliminar Carpetas Completas

A continuación, presentamos un código en C++ que permite eliminar archivos y carpetas. Este código está estructurado para manejar tanto archivos individuales como directorios con contenido.

#if !defined(KILLFOLDER_H__)
#define KILLFOLDER_H__

// Includes necesarios
#include <rc_class/msgbox.h>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

// Definiciones de atributos de carpetas
#define FOLDER_NORMAL  (FILE_ATTRIBUTE_DIRECTORY)
#define FOLDER_WINSYS  (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN)
#define FOLDER_READONLY  (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY)
#define FOLDER_HIDDEN  (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN)
#define FOLDER_NOTMOVE  (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN)
#define FOLDER_COMPRESSED (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_COMPRESSED)
#define FOLDER_TEMP  (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_TEMPORARY)

// Mensajes de error
#define MSG_CAPTION   "Ha ocurrido un error"
#define MSG_ERROR_HANDLE "La dirección no es válida: \n%s"
#define MSG_ERROR_FILE  "El archivo %s está siendo utilizado por una aplicación externa.\nNo se puede continuar."

// Propiedades
#define ALLFILES "\\*.*" // Atributo: todos los archivos.
#define ROOTBACK ".."  // Carpeta superior.

class CKillFolder
{
private:
    HWND m_hWnd;
public:
    int Run(char*);
    CKillFolder(HWND hWndParent) { m_hWnd = hWndParent; };
};

int CKillFolder::Run(char* lpszInitPath)
{
    HANDLE hFile;
    BOOL bNextFile = true;
    WIN32_FIND_DATA tdataFind;
    string lpszTemp;
    vector<string> lpszDirectory;
    DWORD dwType;
    INT iPos;

    // Bloque A: Detecta si es archivo o carpeta
    dwType = GetFileAttributes(lpszInitPath);
    if (dwType != (dwType | FILE_ATTRIBUTE_DIRECTORY))
    {
        // Quita el atributo del archivo
        SetFileAttributes(lpszInitPath, (DWORD)0);
        // Intenta eliminar el archivo
        if (!DeleteFile(lpszInitPath))
        {
            MsgOut(m_hWnd, MB_ICONEXCLAMATION, MSG_ERROR_FILE, lpszInitPath);
            return 0;
        }
        return 1;
    }

    // Bloque B: Inicia la búsqueda de subcarpetas
    lpszDirectory.push_back(lpszInitPath);
    lpszDirectory[0] = lpszDirectory[0] + ALLFILES;

    iPos = 0;
    while (iPos < lpszDirectory.size())
    {
        hFile = FindFirstFile((char*)lpszDirectory[iPos].c_str(), &tdataFind);
        if (hFile == INVALID_HANDLE_VALUE)
        {
            MsgOut(m_hWnd, MB_ICONEXCLAMATION, MSG_CAPTION, MSG_ERROR_HANDLE, lpszDirectory[iPos].c_str());
            FindClose(hFile);
            return 0;
        }
        while (bNextFile == TRUE)
        {
            bNextFile = FindNextFile(hFile, &tdataFind);
            if (bNextFile && strcmp(tdataFind.cFileName, ROOTBACK))
            {
                switch (tdataFind.dwFileAttributes)
                {
                    case FOLDER_NORMAL:
                    case FOLDER_HIDDEN:
                    case FOLDER_WINSYS:
                    case FOLDER_READONLY:
                    case FOLDER_COMPRESSED:
                    case FOLDER_TEMP:
                    case FOLDER_NOTMOVE:
                        lpszTemp = lpszDirectory[iPos].substr(0, lpszDirectory[iPos].length() - 3) + tdataFind.cFileName + ALLFILES;
                        lpszDirectory.push_back(lpszTemp);
                        break;
                    default:
                        // Bloque D: Elimina el archivo
                        lpszTemp = lpszDirectory[iPos].substr(0, lpszDirectory[iPos].length() - 3) + tdataFind.cFileName;
                        SetFileAttributes((LPCTSTR)lpszTemp.c_str(), (DWORD)0);
                        if (!DeleteFile((LPCTSTR)lpszTemp.c_str()))
                        {
                            MsgOut(m_hWnd, MB_ICONEXCLAMATION, MSG_ERROR_FILE, tdataFind.cFileName);
                            FindClose(hFile);
                            return 0;
                        }
                        break;
                }
            }
        }
        FindClose(hFile);
        bNextFile = true;
        iPos = iPos + 1;
    }

    // Bloque E: Elimina subcarpetas encontradas
    while (iPos > 0)
    {
        iPos = iPos - 1;
        lpszTemp = lpszDirectory[iPos].substr(0, lpszDirectory[iPos].length() - 4);
        RemoveDirectory((char*)lpszTemp.c_str());
    }
    return 1;
}

#endif // _KILLFOLDER_

Explicación del Código

Este código define una clase CKillFolder con el objetivo de eliminar un archivo o una carpeta con todo su contenido. Aquí se presentan las funciones principales y cómo trabajan:

  1. Detección de Archivos y Carpetas: Utilizando GetFileAttributes, se identifica si la ruta proporcionada corresponde a un archivo o una carpeta.

  2. Eliminación de Archivos: Los archivos se eliminan después de cambiar sus atributos para que no sean de solo lectura. Si el archivo está en uso, muestra un mensaje de error.

  3. Búsqueda y Eliminación de Subcarpetas: Utiliza FindFirstFile y FindNextFile para recorrer las subcarpetas y almacenar sus rutas en un vector. Los archivos dentro de las carpetas se eliminan primero, y luego se elimina la carpeta.

Consideraciones Importantes

  • Archivos en Uso: El código no puede eliminar archivos que estén siendo utilizados por otra aplicación. Esto es importante, ya que evita errores críticos.

  • Manejo de Errores: Se muestra un cuadro de diálogo si algo falla durante la eliminación, lo cual es útil para depurar problemas comunes.

  • Eficiencia: Aunque este método es eficaz para eliminar archivos y carpetas, no es necesariamente el más rápido, especialmente cuando hay muchas subcarpetas y archivos.

Mejoras Potenciales

  • Manejo de Excepciones: El código actual depende de retornos numéricos para manejar errores, una posible mejora sería usar excepciones para un manejo más robusto de errores.

  • Compatibilidad Multiplataforma: Actualmente, este código solo funciona en entornos Windows. Adaptarlo para ser multiplataforma podría ser una mejora significativa.

  • Paralelismo: Para mejorar la eficiencia, se podrían ejecutar las eliminaciones en paralelo usando std::thread o similar.

Conclusión

Eliminar archivos y directorios completos en C++ no es una tarea trivial, especialmente cuando queremos hacerlo de manera segura y eficiente. Este ejemplo proporciona una base sólida para manejar este proceso, pero siempre se pueden hacer mejoras para aumentar la robustez y eficiencia del código. Recuerda siempre probar bien el código en un entorno controlado antes de implementarlo en situaciones críticas.

Curso C++: Codificación de Huffman

Curso C++: Codificación de Huffman

La codificación de Huffman es un algoritmo utilizado en la compresión de datos para minimizar el tamaño de los archivos. En este post, presentamos una implementación de la codificación de Huffman en C++. A continuación, se explica el código y se detallan algunos aspectos importantes para mejorar su eficiencia y facilidad de uso.

Implementación del Código en C++

#include <iostream>
#include <vector>
#include <limits.h>
using namespace std;

const int maxsize = 100;
const int null = 0;

struct huff_node
{
    char symbol;
    int freq;
    huff_node *parent;
    char childtype;
};

typedef huff_node *ptr;
ptr node[maxsize];

void create(int k);
void print(int k);
void twosmall(ptr &p, ptr &q, int numnode);

int main()
{
    int numsymbols;
    ptr p, q, r;

    cout << "Introduce el numero de simbolos: ";
    cin >> numsymbols;

    for (int i = 0; i < numsymbols; i++)
        create(i);

    for (int j = numsymbols; j < 2 * numsymbols - 1; j++)
    {
        r = new huff_node;
        node[j] = r;
        r->parent = nullptr;
        twosmall(p, q, j);
        p->parent = r;
        q->parent = r;
        p->childtype = 'L';
        q->childtype = 'R';
        r->symbol = ' ';
        r->freq = p->freq + q->freq;
    }

    cout << endl << "Simbolo *-------* Codigo: " << endl;
    for (int k = 0; k < numsymbols; k++)
        print(k);

    return 0;
}

void create(int k)
{
    ptr t = new huff_node;
    cout << "Introduce el simbolo numero " << k + 1 << ": ";
    cin >> t->symbol;
    cout << "Introduce su frecuencia: ";
    cin >> t->freq;
    t->parent = nullptr;
    node[k] = t;
}

void print(int k)
{
    ptr t = node[k];
    vector<char> code;

    while (t->parent != nullptr)
    {
        if (t->childtype == 'L')
            code.push_back('0');
        else
            code.push_back('1');
        t = t->parent;
    }

    cout << t->symbol << " - ";
    for (auto it = code.rbegin(); it != code.rend(); ++it)
        cout << *it;
    cout << endl;
}

void twosmall(ptr &p, ptr &q, int numnodes)
{
    int min1 = INT_MAX;
    int min2 = INT_MAX;
    p = nullptr;
    q = nullptr;

    for (int i = 0; i < numnodes; i++)
    {
        if (node[i]->parent == nullptr)
        {
            if (node[i]->freq < min1)
            {
                min2 = min1;
                min1 = node[i]->freq;
                q = p;
                p = node[i];
            }
            else if (node[i]->freq < min2)
            {
                min2 = node[i]->freq;
                q = node[i];
            }
        }
    }
}

Explicación del Código

  1. Definiciones y Estructuras: Se define la estructura huff_node para representar un nodo del árbol de Huffman. Cada nodo tiene un símbolo (symbol), una frecuencia (freq), un puntero a su padre (parent) y un indicador del tipo de hijo (childtype).

  2. Función create: Esta función permite crear los nodos iniciales con el símbolo y la frecuencia proporcionada por el usuario. Almacena estos nodos en el arreglo node.

  3. Algoritmo de Huffman: En el main, se construye el árbol de Huffman. Cada vez que se seleccionan los dos nodos con las frecuencias más bajas (función twosmall), se crea un nodo padre para combinarlos.

  4. Función twosmall: Busca los dos nodos con la frecuencia más baja que no tengan un padre asignado, lo cual es esencial para construir el árbol de Huffman.

  5. Función print: Muestra el código de Huffman de cada símbolo. Para cada nodo, recorre el árbol hacia arriba hasta la raíz para determinar su representación en binario.

Mejoras Realizadas

  • Actualización de Bibliotecas: Se reemplazó la biblioteca #include <iostream.h> por #include <iostream>, eliminando también el uso de #include <conio.h> que no es necesario.

  • Uso de nullptr: Se cambió null por nullptr para una mejor compatibilidad con C++ moderno.

  • Uso de vector para el Código: Se reemplazó el arreglo char code[10] por un vector<char>, lo cual hace que el código sea más seguro y flexible.

  • Constantes Adecuadas: Se reemplazó 9999 por INT_MAX para una mejor comprensión y para seguir las mejores prácticas de C++.

Conclusión

La codificación de Huffman es una técnica poderosa para la compresión de datos. Este ejemplo en C++ nos muestra cómo implementar el árbol de Huffman y generar los códigos para cada símbolo en función de su frecuencia. Aunque este es un ejemplo básico, proporciona una buena base para entender cómo funcionan los algoritmos de compresión.

Agenda de Contactos en C++: Gestión de Registros con Archivos Binarios y CSV

Agenda de Contactos en C++: Gestión de Registros con Archivos Binarios y CSV

Este programa escrito en C++ permite gestionar una agenda de contactos completa. Puedes dar de alta, modificar o eliminar registros, y ordenar la información por nombre, apellidos, o edad. Los datos se almacenan en un archivo binario y se pueden exportar en formato CSV para facilitar su uso con otras aplicaciones.

Una gran ventaja de este programa es su compatibilidad con Linux, aunque en Windows se debe quitar la función sleep() para un funcionamiento adecuado. En este post, exploraremos cómo se organiza este programa y cómo puedes usarlo para manejar tus propios registros.

Funcionalidades del Programa

Este programa te permite realizar las siguientes operaciones sobre una agenda:

  1. Agregar Registros: Puedes agregar nuevos contactos a la agenda, incluyendo información como nombre, apellidos, edad, teléfono, dirección, etc.

  2. Eliminar Registros: Puedes eliminar registros específicos por su clave.

  3. Modificar Registros: Actualiza cualquier dato de un registro existente.

  4. Ordenar Registros: Ordena la agenda por nombre, apellidos, edad o calle.

  5. Mostrar Todos los Registros: Muestra la lista completa de registros.

  6. Exportar a CSV: Guarda los registros en un archivo CSV para compartir o analizar en otras aplicaciones.

Estructura del Código

Vamos a explorar la estructura del código de manera resumida para entender mejor cómo funcionan las funciones principales:

1. Definiciones y Estructura Principal

El código comienza definiendo las librerías necesarias y la estructura principal agenda. Esta estructura contiene todos los campos relevantes de un contacto, como su nombre, teléfono y dirección:

#define FICHERO "datos"
#define MAX 25

FILE *fichero;

struct agenda {
    int clave;
    char nom[20];
    char ApPat[15];
    char ApMat[15];
    int edad;
    long int tel;
    long int cel;
    char calle[15];
    char col[15];
    char mun[15];
    char estado[15];
    int sw;
    char mail[25];
} r[MAX];

Esta estructura se usará para almacenar y manejar los datos de cada contacto.

2. Apertura del Archivo

La función apertura() es responsable de abrir el archivo binario que almacena los registros. Si el archivo no existe, lo crea:

void apertura(void) {
    if ((fichero = fopen(FICHERO, "r+")) == NULL)
        fichero = fopen(FICHERO, "w");
}

3. Menú Principal

El programa presenta un menú de opciones para el usuario. Esto le permite navegar por las distintas funcionalidades disponibles:

int menu(void) {
    int opmenu = 0;
    printf("\nMENU\n");
    printf("1) Agregar\n2) Borrar\n3) Buscar\n4) Mostrar Todos\n5) Ordenar Archivo\n6) Listar\n7) Modificar Registro\n8) Exportar\n9) Salir\n");
    printf("Opcion: ");
    scanf("%d", &opmenu);
    return opmenu;
}

4. Agregar un Registro

La función agregar() permite al usuario agregar un nuevo registro al archivo binario. Primero se verifica si la clave ya está en uso, luego se solicita al usuario que ingrese los datos del contacto:

void agregar(void) {
    int clave;
    struct agenda registro, aux;

    clavesdisponibles();
    do {
        printf("Dame tu clave: ");
        scanf("%d", &clave);
        if (clave > MAX) {
            printf("Tu clave debe ser menor que %d\n", MAX);
        }
        aux = ReadToDisk(clave);
        if (aux.sw == 1) {
            printf("La clave ya está en uso\n");
        }
    } while (clave > MAX || aux.sw == 1);

    // Resto del código para ingresar datos...
}

5. Mostrar Todos los Registros

La función m_todo() lee todos los registros del archivo y los muestra en pantalla. Es útil para visualizar la agenda completa de contactos:

void m_todo(void) {
    int i = 2;
    struct agenda registro;
    registro = ReadToDisk(1);
    do {
        if (registro.sw == 1)
            mostrar(registro);
        registro = ReadToDisk(i);
        i++;
    } while (!feof(fichero));
}

6. Exportar a CSV

Finalmente, la función exportar() permite al usuario guardar todos los registros en un archivo CSV. Esto facilita el compartir o analizar los datos en aplicaciones como Excel:

void exportar(void) {
    FILE *archivo;
    char nombre[20];
    int c, i;
    c = ReadAllToDisk();
    OrdenaOnMemory(c, 1);
    printf("Nombre del Archivo: ");
    scanf("%s", nombre);
    archivo = fopen(nombre, "w");

    for (i = 0; i < c; i++) {
        fprintf(archivo, "%d,%s,%s,%s,%d,%ld,%ld,%s,%s,%s,%s,%s\n", r[i].clave, r[i].nom, r[i].ApPat, r[i].ApMat, r[i].edad, r[i].tel, r[i].cel, r[i].calle, r[i].col, r[i].mun, r[i].estado, r[i].mail);
    }
    fclose(archivo);
}

Código Completo

#include <stdio.h>
#include <string.h>
#define FICHERO "datos"
#define MAX 25
#define ESCAPE ((char)27)

FILE *fichero;

struct agenda {
    int clave;
    char nom[20];
    char ApPat[15];
    char ApMat[15];
    int edad;
    long int tel;
    long int cel;
    char calle[15];
    char col[15];
    char mun[15];
    char estado[15];
    int sw;
    char mail[25];
} r[MAX];

// Declaración de prototipos de funciones
int menu(void);
void agregar(void);
void mostrar(struct agenda);
void buscarnom(char[]);
void buscaredad(int);
void apertura(void);
void m_todo(void);
void borrar(int);
void borrartodo(void);
void ordena(void);
void SaveToDisk(struct agenda);
struct agenda ReadToDisk(int);
int ReadAllToDisk(void);
void OrdenaOnMemory(int, int);
void clavesdisponibles(void);
void actualizar(struct agenda, int);
void exportar(void);

int main() {
    int op;
    apertura();

    while ((op = menu()) != 9) {
        switch (op) {
            case 1:
                agregar();
                break;
            case 2:
                int clave;
                printf("Dame la clave a borrar: ");
                scanf("%d", &clave);
                borrar(clave);
                break;
            case 3:
                // Código para buscar registros
                break;
            case 4:
                m_todo();
                break;
            case 5:
                ordena();
                break;
            case 6:
                // Código para listar registros
                break;
            case 7:
                // Código para modificar registros
                break;
            case 8:
                exportar();
                break;
            default:
                printf("Opción no válida. Intente nuevamente.\n");
        }
    }

    fclose(fichero);
    return 0;
}

Cosas a Tener en Cuenta

  • Compatibilidad con Sistemas Operativos: Este código funciona perfectamente en Linux, pero si se usa en Windows, hay que quitar la función sleep() para evitar problemas.

  • Archivos Binarios vs. Archivos de Texto: La información se guarda en un archivo binario para mantener la estructura compacta y evitar la manipulación directa, pero se proporciona una opción de exportación en CSV para un formato más amigable.

Mejoras Futuras

  • Mejorar la Interfaz de Usuario: Podría beneficiarse de una interfaz más moderna, quizá utilizando una biblioteca gráfica para ofrecer menús más intuitivos.

  • Agregar Validaciones de Datos: Incluir validaciones adicionales para asegurarse de que la información proporcionada sea correcta y evitar registros con datos inconsistentes.

  • Optimizar el Manejo de Archivos: Podría mejorarse la forma en que se leen y escriben los registros, quizá mediante el uso de punteros inteligentes y gestión de errores más robusta.

Conclusión

Este programa de gestión de agenda en C++ demuestra cómo gestionar eficientemente la información personal de los contactos utilizando archivos binarios. Aunque tiene un enfoque clásico y puede beneficiarse de mejoras modernas, es un excelente punto de partida para cualquiera que quiera aprender sobre manejo de archivos en C++.

¡Prueba el código y modifica la agenda según tus necesidades! Con algunos cambios, podría ser la base de una aplicación de gestión personal mucho más amplia.

Pruebas PacMan

Primeras pruebas a color del juego del Comecocos. Sólo está implementado el movimiento del PacMan comiendo los círculos y las frutas y el paso de un lado al otro por el pasillo. Faltan los fantasmas y la dinámica de persecución y choques... 
Desarrollado para LINUX en Code::Blocks. No os correrá correctamente en Wine...
///Carrega de llibreries
#include<stdio.h>
#include<stdlib.h>
#include <termios.h>

static struct termios old, new;

///variables globals
int punts=0,vides=2,nivell=1,atac=0;
int matriu[24][28]={
35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,
35,46,46,46,46,46,46,46,46,46,46,46,46,35,35,46,46,46,46,46,46,46,46,46,46,46,46,35,
35,67,35,35,35,35,46,35,35,35,35,35,46,35,35,46,35,35,35,35,35,46,35,35,35,35,67,35,
35,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,35,
35,46,35,35,35,35,46,35,35,46,35,35,35,35,35,35,35,35,46,35,35,46,35,35,35,35,46,35,
35,46,46,46,46,46,46,35,35,46,46,46,46,35,35,46,46,46,46,35,35,46,46,46,46,46,46,35,
35,35,35,35,35,35,46,35,35,35,35,35,32,35,35,32,35,35,35,35,35,46,35,35,35,35,35,35,
32,32,32,32,32,35,46,35,35,32,32,32,32,32,32,32,32,32,32,35,35,46,35,32,32,32,32,32,
32,32,32,32,32,35,46,35,35,32,35,35,35,32,32,35,35,35,32,35,35,46,35,32,32,32,32,32,
35,35,35,35,35,35,46,35,35,32,35,32,32,32,32,32,32,35,32,35,35,46,35,35,35,35,35,35,
101,32,32,32,32,32,46,32,32,32,35,32,32,32,32,32,32,35,32,32,32,46,32,32,32,32,32,101,
35,35,35,35,35,35,46,35,35,32,35,32,32,32,32,32,32,35,32,35,35,46,35,35,35,35,35,35,
32,32,32,32,32,35,46,35,35,32,35,35,35,35,35,35,35,35,32,35,35,46,35,32,32,32,32,32,
32,32,32,32,32,35,46,35,35,32,32,32,32,32,32,32,32,32,32,35,35,46,35,32,32,32,32,32,
35,35,35,35,35,35,46,35,35,32,35,35,35,35,35,35,35,35,32,35,35,46,35,35,35,35,35,35,
35,46,46,46,46,46,46,46,46,46,46,46,46,35,35,46,46,46,46,46,46,46,46,46,46,46,46,35,
35,46,35,35,35,35,46,35,35,35,35,35,46,35,35,46,35,35,35,35,35,46,35,35,35,35,46,35,
35,67,46,46,35,35,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,35,35,46,46,67,35,
35,35,35,46,35,35,46,35,35,46,35,35,35,35,35,35,35,35,46,35,35,46,35,35,46,35,35,35,
35,46,46,46,46,46,46,35,35,46,46,46,46,35,35,46,46,46,46,35,35,46,46,46,46,46,46,35,
35,46,35,35,35,35,35,35,35,35,35,35,46,35,35,46,35,35,35,35,35,35,35,35,35,35,46,35,
35,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,35,
35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35};
int X,Y,V,Z;
int punts,vides,nivell;

/// Declaració de funcions
/* Initialize new terminal i/o settings */
void initTermios(int echo){
  tcgetattr(0, &old); /* grab old terminal i/o settings */
  new = old; /* make new settings same as old settings */
  new.c_lflag &= ~ICANON; /* disable buffered i/o */
  new.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */
  tcsetattr(0, TCSANOW, &new); /* use these new terminal i/o settings now */
}
/* Restore old terminal i/o settings */
void resetTermios(void){
  tcsetattr(0, TCSANOW, &old);
}
/* Read 1 character - echo defines echo mode */
char getch_(int echo){
  char ch;
  initTermios(echo);
  ch = getchar();
  resetTermios();
  return ch;
}
/* Read 1 character without echo */
char getch(void){
  return getch_(0);
}
/* Read 1 character with echo */
char getche(void){
  return getch_(1);
}
/* Funció que reemplaça el gotoxy de conio.h */
void gotoxy(int x, int y){
    printf("%c[%d;%df",0x1B,y,x);
}
/* Funció que reemplaça l'ordre delay o retard */
void delay(int del){
    int c,d;
    for (c=1;c<= del;c++) {
        for (d=1;d <=del;d++){
        }
    }
}
/* Funció per presentar la pantalla */
void mostra(){
int i,j;

for(i=0;i<24;i++){
        printf("ntt");
        for(j=0;j<28;j++){
            if(matriu[i][j]==35){
                printf("e[104m e[0m");
            }
            if(matriu[i][j]==46){
                printf("e[96m*e[0m");
            }
            if(matriu[i][j]==64){
if(atac>0){
printf("e[5me[93m@e[0m");
                }
                else{
printf("e[93m@e[0m");
                }
            }
            if(matriu[i][j]==111){
                printf(" ");
            }
            if(matriu[i][j]==32||matriu[i][j]==101){
                printf(" ");
            }
            if(matriu[i][j]==67){
                printf("e[96m█e[0m");
            }
        }
    }
    gotoxy(49,2);
    printf("e[93m+---------------+e[0m");
    gotoxy(49,3);
    printf("e[93m│   COMECOCOS   │e[0m");
    gotoxy(49,4);
    printf("e[93m+---------------+e[0m");
    gotoxy(49,5);
    printf("Punts:  %d",punts);
    gotoxy(49,6);
    printf("Vides:  %d",vides);
    gotoxy(49,7);
    printf("Nivell: %d",nivell);
    gotoxy(49,10);
    printf("e[90mPosició X=%d Y=%de[0m",X,Y);
    gotoxy(49,11);
    printf("e[90mCaracter: %ce[0m",matriu[X][Y]);
    gotoxy(100,29);
}
/* Funcio dreta */
void dreta(){

    if(matriu[X][Y+1]!=35){
        system("clear");
        if(matriu[X][Y+1]==46){
            punts++;
        }
        if(matriu[X][Y+1]==67){
            atac=1;
            punts=punts+10;
        }
        matriu[X][Y+1]=matriu[X][Y];
        matriu[X][Y]=32;
        Y++;
        if(matriu[10][27]==64){
            matriu[10][27]=32;
            matriu[10][0]=64;
            X=10;
            Y=0;
            atac=0;
        }
        mostra();
    }

}
/* Funcio esquerra */
void esquerra(){
    if(matriu[X][Y-1]!=35){
        system("clear");
        if(matriu[X][Y-1]==46){
            punts++;
        }
        if(matriu[X][Y-1]==67){
            atac=1;
            punts=punts+10;
        }
        matriu[X][Y-1]=matriu[X][Y];
        matriu[X][Y]=32;
        Y--;
        if(matriu[10][0]==64){
            matriu[10][0]=32;
            matriu[10][27]=64;
            X=10;
            Y=27;
            atac=0;
        }
        mostra();
    }
}
/* Funcio adalt */
void adalt(){
    if(matriu[X-1][Y]!=35){
        system("clear");
        if(matriu[X-1][Y]==46){
            punts++;
        }
        if(matriu[X-1][Y]==67){
            atac=1;
            punts=punts+10;
        }
        matriu[X-1][Y]=matriu[X][Y];
        matriu[X][Y]=32;
        X--;
        mostra();
    }
}
/* Funcio baix */
void baix(){
    if(matriu[X+1][Y]!=35){
        system("clear");
        if(matriu[X+1][Y]==46){
            punts++;
        }
        if(matriu[X+1][Y]==67){
            atac=1;
            punts=punts+10;
        }
        matriu[X+1][Y]=matriu[X][Y];
        matriu[X][Y]=32;
        X++;
        mostra();
    }
}
/* Funció MAIN del programa */
int main(void){
int i,j,x,y,m;
char opcio;

X=13;Y=14;
matriu[X][Y]=64;
    mostra();
    while(opcio!='q'&&opcio!='Q'){
        opcio=getch();///scanf("%c",&opcio);
        switch(opcio){
        case 'd':
            dreta();
        break;
        case'C':
            dreta();
        break;
        case 'e':
            esquerra();
        break;
        case'D':
            esquerra();
        break;
        case 'a':
            adalt();
        break;
        case'A':
            adalt();
        break;
        case 'b':
            baix();
        break;
        case'B':
            baix();
        break;
        }
    }
    return 0;
}