Pequeño programa de horarios

(actualizacion. ya solucione el problema, simplemente utilice claude en vez de chatgpt)
un poco de contexto. tengo un amigo que estudia animación porque… es masoquista, no puedo describirlo de otra forma, y bueno, para que el hombre tenga por fin un respiro, decidi crear un programa para crear horarios, y asi nunca mas pueda poner excusas del tipo, se me olvido, o esto ahora no me encaja, o cosas asi, asi que dije, le voy a crear un programa para hacer horarios, y asi no me pondra mas excusas. bueno, digamos que mis conocimientos en programación son un poco escasos y bien, decidi hacer esto con chatgpt. tengo una minima nocion de como hacer esto, pero tampoco mucha y personalmente creo que el resultado de momento no es del todo malo. digamos que estoy en una etapa de prealfa o alfa (honestamente no se como funciona esto de las versiones) y bueno, queria ver si alguien podria darme una pequeña ayuda o alguna idea de que estoy haciendo mal

la sintaxis es un poco rara ya que en un momento con 100% se sobriedad y 100% de racismo hacia grigos decidi hacer la sintaxis del programa completamente en español pero con una libreria que tradujera todo a algo que entendiera la maquina, asi que entiendo confunsiones y los palos en los comentarios (por cierto el archivo de sintaxis ahorita esta incompleto, ya que ahorita queria ver si funcionaba y luego le pondria una sintaxis propias)

otras 3 aclaraciones antes de empezar. primero tengo algunos archivos definiendo metas de lo que quiero conseguir para que mi organizacion no se nefasta, y si quieren los puedo compartir para que se hagan una idea de mis objetivos, ahorita no los he incluido porque me parecia demaciado largo el texto, asi que por acortar lo omiti

segundo, creo que por el lugar que estamos, se entenderia un poco el hecho que esto lo quiero hacer de codigo abierto, o al menos si tengo un programa minimamente decente, no me molestaria simplemente regalar el codigo para quien lo quisiera, poniendo en algun tipo de licencia de codigo abierto o software libre, yo solo quiero que se pueda ejecutar donde sea y ya, pero bueno, digamos que el sobre el tema de licencias no tengo ni la mas minima idea

y por ultimo, el error que tengo creo que esta relacionado con el archivo de rutina, no se si el .cpp o .h, lo que pasa es que no puedo guardar los archivos con las rutinas, siempre me exporta un archivo en blanco, y cuando intento cargar un archivo echo aparte siguiendo la logica que quise seguir pues… tampoco funciona

y ya esto lo ultimo y los dejo con el codigo, si quieren puedo darles el codigo puro en c++ para que tengan una mejor idea de que intente hacer, la traduccion de la sintaxis la hice manualmente asi que todavia tengo los archivos con la sintaxis que cualquier otro ser humano utilizaria:

// main.cpp
#include <map>

#include "sintaxis_es.h"
#include "horario.h"
#include "evento.h"
#include "rutina.h"

// Muestra el menú de opciones al usuario
nulo MostrarMenu() {
    imp "=== Gestión de Horarios ===\n"
    << "1. Agregar evento\n"
    << "2. Eliminar evento\n"
    << "3. Mostrar eventos de un día\n"
    << "4. Guardar rutina\n"
    << "5. Cargar rutina\n"
    << "6. Cambiar formato de hora (12/24 horas)\n"
    << "7. Salir\n"
    << "Seleccione una opción: ";
}

// Función auxiliar para elegir un día de la semana
txt seleccionarDia() {
    std::map<num, txt> dias = {
        {1, "Lunes"},
        {2, "Martes"},
        {3, "Miércoles"},
        {4, "Jueves"},
        {5, "Viernes"},
        {6, "Sábado"},
        {7, "Domingo"} //Dia del señor XD
    };

    num opcion;
    imp "Seleccione el día:\n";
    cada (const fn& [indice, dia] : dias) {
        imp indice << ". " << dia << '\n';
    }
    imp "Ingrese el número del día: ";
    leer >> opcion;

    si (dias.encontrar(opcion) !=dias.end()) {
        dev dias[opcion];
    } sino {
        imp "Opción no válida. Seleccionando Lunes por defecto.\n";
        dev "Lunes"; //Valor predeterminado
    }
}

nucleo() {
    Horario horario;  // Instancia de Horario para gestionar los eventos
    Rutina rutina;
    bol formato24Horas = cierto; // Inicialmente en formato de 24 horas
    num opcion;       // Variable para almacenar la opción seleccionada por el usuario

    hacer {
        MostrarMenu();
        leer >> opcion;
        leer.ignore(); // Limpiar el buffer de entrada

        si (opcion == 1) {  // Agregar un evento
        txt nombre, dia;
        num horaInicio, minutoInicio, horaFin, minutoFin;
        dia = seleccionarDia();

        imp "Ingrese el nombre del evento: ";
        leer.ignore();  // Limpiar el buffer antes de getline
        std::getline(leer, nombre);

        imp "Ingrese la hora de inicio (0-23): ";
        leer >> horaInicio;

        imp "Ingrese el minuto de inicio (0-59): ";
        leer >> minutoInicio;

        imp "Ingrese la hora de finalización (0-23): ";
        leer >> horaFin;

        imp "Ingrese el minuto de finalización (0-59): ";
        leer >> minutoFin;

        // Crea el evento usando todos los parámetros requeridos
        Evento evento(nombre, horaInicio, minutoInicio, horaFin, minutoFin);

        // Llama a agregarEvento con el día especificado
        si (horario.agregarEvento(evento, dia)) {
            imp "Evento agregado exitosamente.\n";
        } sino {
            imp "No se pudo agregar el evento debido a un conflicto.\n";
        }

    } sino si (opcion == 2) {  // Eliminar un evento
        txt nombre, dia;
        dia = seleccionarDia();

        imp "Ingrese el nombre del evento a eliminar: ";
        leer.ignore();  // Limpiar el buffer antes de getline
        std::getline(leer, nombre);

        // Llama a eliminarEvento con el nombre y día especificados
        si (horario.eliminarEvento(nombre, dia)) {
            imp "Evento eliminado exitosamente.\n";
        } sino {
            imp "No se encontró el evento a eliminar.\n";
        }
        } sino si (opcion == 3) {  // Mostrar eventos
            txt dia = seleccionarDia();

            // Llama a mostrarEventos con el día y formato especificados
            horario.mostrarEventos(dia, formato24Horas);

        } sino si (opcion == 4){
            txt archivo;
            imp "Ingrese el nombre del archivo para guardar la rutina: ";
            std::getline(leer, archivo);
            archivo += ".hrt"; //Extensión personalizada (hora de rutina)

            si (rutina.guardarEnArchivo(archivo)) {
                imp "Rutina guardada en " << archivo << " exitosamente.\n";
            } sino {
                imp "Error al guardar la rutina.\n";
            }
        } sino si (opcion == 5){
            txt archivo;
            imp "Ingrese el nombre del archivo para cargar la rutina: ";
            std::getline(leer, archivo);
            archivo += ".hrt"; // Asegurar la extensión personalizada

            si (rutina.cargarDesdeArchivo(archivo)) {
                imp "Rutina cargada desde " << archivo << " exitosamente.\n";
            } sino {
                imp "Error al cargar la rutina.\n";
            }
        } sino si (opcion == 6) {
            formato24Horas = !formato24Horas; // Alterna el formato de 12 a 24 horas o viceversa
            imp "Formato de hora cambiado a " << (formato24Horas ? "24 horas.\n" : "12 horas.\n");
        } sino si (opcion == 7) {
            imp "Saliendo del programa...\n";
        } sino {
            imp "Opción no válida. Intente de nuevo.\n";
        }
    
    } mientras (opcion != 7); // Termina cuando la opción es 4 (salir)

    dev 0; // Finaliza el programa con éxito
}

// rutina.cpp
#include "rutina.h"
#include "sintaxis_es.h"
#include <fstream>
#include <sstream>
#include <iomanip>
#include <regex>

// Cargar eventos desde un archivo personalizado con extensión .hrt
bol Rutina::cargarDesdeArchivo(const txt& rutinaArchivo) {
    std::ifstream archivo(rutinaArchivo);
    si (!archivo) {
        adv "Error: No se pudo abrir el archivo" << rutinaArchivo << " para lectura.\n";
        dev falso;
    }

    txt linea, diaActual;
    std::regex formatoEvento(R"(Evento:\s*(.+?),\s*Hora inicio:\s*(\d{2}):(\d{2}),\s*Hora fin:\s*(\d{2}):(\d{2}))");

    mientras (getline(archivo, linea)) {
        // Procesa la línea de evento en el contexto del día actual
        std::smatch match;
        si (std::regex_match(linea, match, formatoEvento)) {
            // Extrae los datos del evento si coincide con el formato esperado
            txt nombre = match[1];
            num horaInicio = std::stoi(match[2]);
            num minutoInicio = std::stoi(match[3]);
            num horaFin = std::stoi(match[4]);
            num minutoFin = std::stoi(match[5]);

            Evento evento(nombre, horaInicio, minutoInicio, horaFin, minutoFin);
            eventosDiarios[diaActual].agregar(evento);
        } sino {
            adv "Error: Formato de evento inválido en la línea: " << linea << '\n';
        }
    }
    archivo.close();
    dev cierto;
}

// Guarda los eventos actuales en un archivo personalizado con extensión .hrt
bol Rutina:: guardarEnArchivo(const txt& rutinaArchivo) const {
    std::ofstream archivo(rutinaArchivo);
    si (!archivo) {
        adv "Error: No se pudo abrir el archivo " << rutinaArchivo << " para escritura.\n";
        dev falso;
    }

    // Escribe cada día y sus eventos
    cada (const fn& [dia, eventos] : eventosDiarios) {
        archivo << "[" << dia << "]\n"; //Marca el inicio de un día
        cada (const fn& evento : eventos) {
            archivo << "Evento: " << evento.obtenerNombre()
                    << ", Hora inicio: " << std::setw(2) << std::setfill('0') << evento.obtenerHoraInicio()
                    << ":" << std::setw(2) << std::setfill('0') << evento.obtenerMinutoInicio()
                    << ", Hora fin: " << std::setw(2) << std::setfill('0') << evento.obtenerHoraFin()
                    << ":" << std::setw(2) << std::setfill('0') << evento.obtenerMinutoFin() << '\n';
        }
    }
    archivo.close();
    dev cierto;
}

// Funcion privada para parsear la línea de evento en el archivo de rutina (con regex para validar formato)
bol Rutina::parsearLinea(const txt& linea, const txt& dia) {
    // Esta función no se utiliza directamente, ya que el proceso de carga maneja el parseo con regex.
    dev falso;
}

// evento.cpp
#include "evento.h"
#include "sintaxis_es.h"
#include <iomanip>
#include <sstream>

// Constructor de la clase Evento: inicializa el evento con su nombre, hora y minuto de inicio y fin
Evento::Evento(const txt& nombre, num horaInicio, num minutoInicio, num horaFin, num minutoFin)
    : nombre(nombre), horaInicio(horaInicio), minutoInicio(minutoInicio), horaFin(horaFin), minutoFin(minutoFin) {}

// Métodos para obtener los atributos individuales del evento
txt Evento::obtenerNombre() const { dev nombre; }
num Evento::obtenerHoraInicio() const { dev horaInicio; }
num Evento::obtenerMinutoInicio() const { dev minutoInicio; }
num Evento::obtenerHoraFin() const { dev horaFin; }
num Evento::obtenerMinutoFin() const { dev minutoFin; }

// Método para obtener la hora de inicio en formato de 12 o 24 horas
txt Evento::obtenerHoraInicioFormato(bol formato24Horas) const {
    dev formatoHora(horaInicio, minutoInicio, formato24Horas);
}

// Método para obtener la hora de fin en formato de 12 o 24 horas
txt Evento::obtenerHoraFinFormato(bol formato24Horas) const {
    dev formatoHora(horaFin, minutoFin, formato24Horas);
}

// Método privado para formatear la hora y minutos en formato de 12 o 24 horas
txt Evento::formatoHora(num hora, num minuto, bol formato24Horas) const {
    std::ostringstream oss;
    si (formato24Horas) {
        oss << std::setw(2) << std::setfill('0') << hora << ":"
            << std::setw(2) << std::setfill('0') << minuto;
    } sino {
        num horas12 = hora % 12 == 0 ? 12 : hora % 12;
        txt periodo = hora < 12 ? "AM" : "PM";
        oss << std::setw(2) << std::setfill('0') << horas12 << ":"
            << std::setw(2) << std::setfill('0') << minuto << " " << periodo;
    }
    dev oss.str();
}

// horario.cpp
#include "sintaxis_es.h"
#include "horario.h"
#include <fstream>

// Agrega un evento al horario en el día especificado, si no hay conflicto de horarios
bol Horario::agregarEvento(const Evento& evento, const txt& dia) {
    si (!hayConflicto(evento, dia)) {
        eventosPorDia[dia].agregar(evento);  // Usa la macro "agregar" para añadir el evento
        dev cierto;  // Indica que el evento fue agregado exitosamente
    } 
    imp "Conflicto de horario detectado. Evento no agregado.\n";
    dev falso;  // Indica que no se pudo agregar el evento debido a un conflicto
}

// Elimina un evento del horario dado su nombre y día especificado
bol Horario::eliminarEvento(const txt& nombreEvento, const txt& dia) {
    fn& eventos = eventosPorDia[dia];
    cada (fn esto = eventos.begin(); esto != eventos.end(); ++esto) {
        si (esto->obtenerNombre() == nombreEvento) {
            eventos.eliminar(esto);  // Usa la macro "eliminar" para borrar el evento
            dev cierto;  // Indica que el evento fue eliminado
        }
    }
    imp "Evento no encontrado.\n";
    dev falso;  // Indica que el evento no se encontró en el día especificado
}

// Muestra todos los eventos de un día en formato 12 o 24 horas
nulo Horario::mostrarEventos(const txt& dia, bol formato24Horas) const {
    si (eventosPorDia.encontrar(dia) != eventosPorDia.end()) {
        cada (const fn& evento : eventosPorDia.at(dia)) {
            imp "Evento: " << evento.obtenerNombre()
                << ", Hora de inicio: " << evento.obtenerHoraInicioFormato(formato24Horas)
                << ", Hora de fin: " << evento.obtenerHoraFinFormato(formato24Horas) << '\n';
        }
    } sino {
        imp "No hay eventos para el día " << dia << ".\n";
    }
}

// Verifica si un nuevo evento tiene un conflicto de horario en el día especificado
bol Horario::hayConflicto(const Evento& nuevoEvento, const txt& dia) const {
    si (eventosPorDia.encontrar(dia) != eventosPorDia.end()) {
        cada (const fn& evento : eventosPorDia.at(dia)) {
            // Convierte las horas y minutos de inicio y fin a minutos para facilitar la comparación
            num inicio1 = evento.obtenerHoraInicio() * 60 + evento.obtenerMinutoInicio();
            num fin1 = evento.obtenerHoraFin() * 60 + evento.obtenerMinutoFin();
            num inicio2 = nuevoEvento.obtenerHoraInicio() * 60 + nuevoEvento.obtenerMinutoInicio();
            num fin2 = nuevoEvento.obtenerHoraFin() * 60 + nuevoEvento.obtenerMinutoFin();

            // Comprueba si los horarios de los eventos se superponen
            si ((inicio1 < fin2) && (inicio2 < fin1)) {
                dev cierto;  // Conflicto detectado
            }
        }
    }
    dev falso;  // No hay conflicto de horario
}

// rutina.h
#ifndef RUTINA_H
#define RUTINA_H

#include <map>
#include "evento.h"
#include "sintaxis_es.h"

class Rutina {
public:
    bol cargarDesdeArchivo(const txt& rutaArchivo);
    bol guardarEnArchivo(const txt& rutaArchivo) const;
    lista<Evento> obtenerEventos(const txt& dia) const;

private:
    std::map<txt, lista<Evento>> eventosDiarios;
    bol parsearLinea(const txt& linea, const txt& dia);
};

#endif

// horario.h
#ifndef HORARIO_H
#define HORARIO_H

#include <map>
#include "evento.h"
#include "sintaxis_es.h"

// Clase que representa un horario de eventos organizados por día
class Horario {
public:
    // Agrega un evento al horario en un día específico
    bol agregarEvento(const Evento& evento, const txt& dia);

    // Elimina un evento del horario por su nombre y día específico
    bol eliminarEvento(const txt& nombreEvento, const txt& dia);

    // Muestra todos los eventos de un día en formato 12 o 24 horas
    nulo mostrarEventos(const txt& dia, bol formato24Horas) const;

    // Guarda el horario completo en un archivo
    bol guardarHorario(const txt& archivo) const;

    // Carga el horario completo desde un archivo
    bol cargarHorario(const txt& archivo);

private:
    std::map<txt, lista<Evento>> eventosPorDia; // Mapa de listas de eventos organizados por día

    // Verifica si el nuevo evento tiene un conflicto en un día específico
    bol hayConflicto(const Evento& nuevoEvento, const txt& dia) const;
};

#endif // HORARIO_H

// evento.h
#ifndef EVENTO_H
#define EVENTO_H

#include "sintaxis_es.h"

// Clase que representa un evento con nombre, hora de inicio y fin
class Evento {
public:
    // Constructor que inicializa un evento con su nombre, hora y minuto de inicio y fin
    Evento(const txt& nombre, num horaInicio, num minutoInicio, num horaFin, num minutoFin);

    // Métodos para obtener los atributos básicos del evento
    txt obtenerNombre() const;          // Retorna el nombre del evento
    num obtenerHoraInicio() const;      // Retorna la hora de inicio del evento (horas)
    num obtenerMinutoInicio() const;    // Retorna el minuto de inicio del evento
    num obtenerHoraFin() const;         // Retorna la hora de finalización del evento (horas)
    num obtenerMinutoFin() const;       // Retorna el minuto de finalización del evento

    // Formateo de horas en 12 y 24 horas
    txt obtenerHoraInicioFormato(bol formato24Horas) const; // Retorna la hora de inicio en formato 12 o 24 horas
    txt obtenerHoraFinFormato(bol formato24Horas) const;    // Retorna la hora de fin en formato 12 o 24 horas

private:
    txt nombre;            // Nombre del evento
    num horaInicio;        // Hora de inicio del evento (horas)
    num minutoInicio;      // Minuto de inicio del evento
    num horaFin;           // Hora de fin del evento (horas)
    num minutoFin;         // Minuto de fin del evento

    // Método privado para formatear la hora y minuto en 12 o 24 horas
    txt formatoHora(num hora, num minuto, bol formato24Horas) const;
};

#endif

// sintaxis_es.h
#ifndef SINTAXIS_ES_H
#define SINTAXIS_ES_H

#include <iostream>
#include <vector>
#include <string>
#include <stdexcept>
#include <algorithm>  // Para uso de algoritmos estándar

// --- Tipos de Datos ---
typedef int num;                  // Para enteros
typedef bool bol;                 // Para booleanos
typedef std::string txt;          // Para cadenas de texto

// Plantilla de lista para soportar vectores de cualquier tipo de dato
template<typename T>
using lista = std::vector<T>;     // Definición de lista genérica

// --- Constantes ---
#define cierto true               // Equivalente a 'true'
#define falso false               // Equivalente a 'false'

// --- Métodos de Contenedores (Equivalencias en Español) ---
#define agregar push_back         // Añadir elemento a un contenedor
#define eliminar erase            // Eliminar elemento de un contenedor
#define encontrar find            // Encontrar un elemento en un contenedor
#define tamano size               // Obtener el tamaño de un contenedor
#define vacio empty               // Verificar si el contenedor está vacío

// --- Entrada y Salida ---
#define imp std::cout <<          // Imprimir en consola
#define adv std::cerr <<          // Mensajes de error o advertencia en consola
inline std::istream& leer = std::cin;  // Leer entrada de datos desde el usuario, usando alias en lugar de macro

// --- Control de Flujo ---
#define si if                     // Condicional 'if'
#define sino else                 // Alternativa 'else'
#define mientras while            // Bucle mientras
#define cada for                  // Bucle para iteraciones
#define hacer do                  // Bucle hacer-mientras
#define romper break              // Para romper un bucle
#define continuar continue        // Para continuar en el siguiente ciclo
#define nulo void                 // Representa el tipo 'void'

// --- Control de Flujo (Switch/Case) ---
#define segun switch              // Estructura de selección múltiple
#define caso case                 // Cada caso dentro de 'switch'
#define defecto default           // Caso por defecto en 'switch'

// --- Manejo de Funciones ---
#define fn auto                   // Declaración de función con tipo automático
#define dev return                // Devolver valor en función

// --- Manejo de Excepciones ---
#define cap try                   // Bloque 'try' para manejo de excepciones
#define excep catch               // Bloque 'catch' para capturar excepciones

// --- Punto de Entrada del Programa ---
#define nucleo int main           // Punto de entrada principal del programa

#endif // SINTAXIS_ES_H
3 Me gusta

aqui les dejo una actualización, por si les intereza (os podria dar el makefile, pero tendrian que poner los archivos de la misma forma que lo hice yo) (diria que ya estoy en una alfa solida, creo, que de versiones no se):

//main.cpp

#include <map>
#include <cstdlib>  // Para las funciones de limpieza de pantalla
#include <limits>   // Para std::numeric_limits

#include "sintaxis_es.h"
#include "horario.h"
#include "evento.h"
#include "rutina.h"

// Función para limpiar la pantalla de forma multiplataforma
nulo LimpiarPantalla() {
    #ifdef _WIN32
        system("cls");
    #else
        system("clear");
    #endif
}

// Función para limpiar el buffer de entrada
nulo LimpiarBuffer() {
    leer.clear();
    leer.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

// Función para pausar la ejecución y esperar input del usuario
nulo PausarPantalla() {
    imp "\nPresione Enter para continuar...";
    leer.get();
}

// Muestra el menú de opciones al usuario
nulo MostrarMenu() {
    LimpiarPantalla();
    imp "=== Gestión de Horarios ===\n"
        << "1. Agregar evento\n"
        << "2. Eliminar evento\n"
        << "3. Mostrar eventos de un día\n"
        << "4. Guardar rutina\n"
        << "5. Cargar rutina\n"
        << "6. Cambiar formato de hora (12/24 horas)\n"
        << "7. Salir\n"
        << "Seleccione una opción: ";
}

// Función auxiliar para elegir un día de la semana
txt seleccionarDia() {
    LimpiarPantalla();
    mapa<num, txt> dias = {
        {1, "Lunes"},
        {2, "Martes"},
        {3, "Miércoles"},
        {4, "Jueves"},
        {5, "Viernes"},
        {6, "Sábado"},
        {7, "Domingo"}
    };

    num opcion;
    imp "Seleccione el día:\n";
    cada (const fn& [indice, dia] : dias) {
        imp indice << ". " << dia << '\n';
    }
    imp "Ingrese el número del día: ";
    leer >> opcion;
    LimpiarBuffer();

    si (dias.encontrar(opcion) != dias.end()) {
        dev dias[opcion];
    } sino {
        imp "Opción no válida. Seleccionando Lunes por defecto.\n";
        PausarPantalla();
        dev "Lunes";
    }
}

nucleo() {
    Horario horario;
    Rutina rutina;
    bol formato24Horas = cierto;
    num opcion;

    hacer {
        MostrarMenu();
        leer >> opcion;
        LimpiarBuffer();

        segun(opcion) {
            caso 1: {  // Agregar un evento
                txt nombre, dia;
                num horaInicio, minutoInicio, horaFin, minutoFin;
                dia = seleccionarDia();

                LimpiarPantalla();
                imp "=== Agregar Nuevo Evento ===\n\n";
                imp "Ingrese el nombre del evento: ";
                obt_linea(leer, nombre);

                imp "Ingrese la hora de inicio (0-23): ";
                leer >> horaInicio;
                LimpiarBuffer();

                imp "Ingrese el minuto de inicio (0-59): ";
                leer >> minutoInicio;
                LimpiarBuffer();

                imp "Ingrese la hora de finalización (0-23): ";
                leer >> horaFin;
                LimpiarBuffer();

                imp "Ingrese el minuto de finalización (0-59): ";
                leer >> minutoFin;
                LimpiarBuffer();

                Evento evento(nombre, horaInicio, minutoInicio, horaFin, minutoFin);

                si (horario.agregarEvento(evento, dia)) {
                    imp "\n✓ Evento agregado exitosamente.\n";
                } sino {
                    imp "\n✗ No se pudo agregar el evento debido a un conflicto.\n";
                }
                PausarPantalla();
                romper;
            }

            caso 2: {  // Eliminar un evento
                txt nombre, dia;
                dia = seleccionarDia();

                LimpiarPantalla();
                imp "=== Eliminar Evento ===\n\n";
                imp "Ingrese el nombre del evento a eliminar: ";
                obt_linea(leer, nombre);

                si (horario.eliminarEvento(nombre, dia)) {
                    imp "\n✓ Evento eliminado exitosamente.\n";
                } sino {
                    imp "\n✗ No se encontró el evento a eliminar.\n";
                }
                PausarPantalla();
                romper;
            }

            caso 3: {  // Mostrar eventos
                txt dia = seleccionarDia();
                LimpiarPantalla();
                imp "=== Eventos del " << dia << " ===\n\n";
                horario.mostrarEventos(dia, formato24Horas);
                PausarPantalla();
                romper;
            }

            caso 4: {  // Guardar rutina
                LimpiarPantalla();
                imp "=== Guardar Rutina ===\n\n";
                txt archivo;
                imp "Ingrese el nombre del archivo para guardar la rutina: ";
                obt_linea(leer, archivo);
                archivo += ".hrt";

                rutina.establecerEventos(horario.obtenerTodosEventos());

                si (rutina.guardarEnArchivo(archivo)) {
                    imp "\n✓ Rutina guardada en " << archivo << " exitosamente.\n";
                } sino {
                    imp "\n✗ Error al guardar la rutina.\n";
                }
                PausarPantalla();
                romper;
            }

            caso 5: {  // Cargar rutina
                LimpiarPantalla();
                imp "=== Cargar Rutina ===\n\n";
                txt archivo;
                imp "Ingrese el nombre del archivo para cargar la rutina: ";
                obt_linea(leer, archivo);
                archivo += ".hrt";

                si (rutina.cargarDesdeArchivo(archivo)) {
                    horario.establecerEventos(rutina.obtenerTodosEventos());
                    imp "\n✓ Rutina cargada desde " << archivo << " exitosamente.\n";
                } sino {
                    imp "\n✗ Error al cargar la rutina.\n";
                }
                PausarPantalla();
                romper;
            }

            caso 6: {  // Cambiar formato de hora
                formato24Horas = !formato24Horas;
                LimpiarPantalla();
                imp "=== Cambio de Formato de Hora ===\n\n";
                imp "✓ Formato de hora cambiado a " << (formato24Horas ? "24 horas" : "12 horas") << ".\n";
                PausarPantalla();
                romper;
            }

            caso 7: {  // Salir
                LimpiarPantalla();
                imp "¡Gracias por usar el Gestor de Horarios!\n";
                romper;
            }

            defecto: {
                LimpiarPantalla();
                imp "✗ Opción no válida. Intente de nuevo.\n";
                PausarPantalla();
                romper;
            }
        }
    } mientras (opcion != 7);

    dev 0;
}
//evento.cpp

#include "evento.h"
#include "sintaxis_es.h"

// Constructor de la clase Evento: inicializa el evento con su nombre, hora y minuto de inicio y fin
Evento::Evento(const txt& nombre, num horaInicio, num minutoInicio, num horaFin, num minutoFin)
    : nombre(nombre), horaInicio(horaInicio), minutoInicio(minutoInicio), horaFin(horaFin), minutoFin(minutoFin) {}

// Métodos para obtener los atributos individuales del evento
txt Evento::obtenerNombre() const { dev nombre; }
num Evento::obtenerHoraInicio() const { dev horaInicio; }
num Evento::obtenerMinutoInicio() const { dev minutoInicio; }
num Evento::obtenerHoraFin() const { dev horaFin; }
num Evento::obtenerMinutoFin() const { dev minutoFin; }

// Método para obtener la hora de inicio en formato de 12 o 24 horas
txt Evento::obtenerHoraInicioFormato(bol formato24Horas) const {
    dev formatoHora(horaInicio, minutoInicio, formato24Horas);
}

// Método para obtener la hora de fin en formato de 12 o 24 horas
txt Evento::obtenerHoraFinFormato(bol formato24Horas) const {
    dev formatoHora(horaFin, minutoFin, formato24Horas);
}

// Método privado para formatear la hora y minutos en formato de 12 o 24 horas
txt Evento::formatoHora(num hora, num minuto, bol formato24Horas) const {
    FlujoSalida oss;
    si (formato24Horas) {
        oss << ancho(2) << relleno('0') << hora << ":"
            << ancho(2) << relleno('0') << minuto;
    } sino {
        num horas12 = hora % 12 == 0 ? 12 : hora % 12;
        txt periodo = hora < 12 ? "AM" : "PM";
        oss << ancho(2) << relleno('0') << horas12 << ":"
            << ancho(2) << relleno('0') << minuto << " " << periodo;
    }
    dev oss.fat();
}
// rutina.cpp
#include "rutina.h"
#include "sintaxis_es.h"
#include <fstream>
#include <sstream>
#include <iomanip>
#include <regex>

bol Rutina::cargarDesdeArchivo(const txt& rutinaArchivo) {
    ArchivoEntrada archivo(rutinaArchivo);
    si (!archivo) {
        adv "Error: No se pudo abrir el archivo " << rutinaArchivo << " para lectura.\n";
        dev falso;
    }

    txt linea;
    txt diaActual;
    eventosDiarios.limpiar(); // Limpia los eventos existentes

    expr_reg diaReg(R"(\[(.*?)\])");
    expr_reg formatoEvento(R"(Evento:\s*(.+?),\s*Hora inicio:\s*(\d{2}):(\d{2}),\s*Hora fin:\s*(\d{2}):(\d{2}))");
    
    mientras (obt_linea(archivo, linea)) {
        busq_expr coinc;
        
        // Verifica si es una línea de día
        si (coinc_expr(linea, coinc, diaReg)) {
            diaActual = coinc[1];
            continuar;
        }
        
        // Procesa la línea de evento
        si (coinc_expr(linea, coinc, formatoEvento)) {
            txt nombre = coinc[1];
            num horaInicio = a_entero(coinc[2]);
            num minutoInicio = a_entero(coinc[3]);
            num horaFin = a_entero(coinc[4]);
            num minutoFin = a_entero(coinc[5]);
            
            Evento evento(nombre, horaInicio, minutoInicio, horaFin, minutoFin);
            eventosDiarios[diaActual].agregar(evento);
        }
    }
    
    archivo.cerrar();
    dev cierto;
}

bol Rutina::guardarEnArchivo(const txt& rutinaArchivo) const {
    ArchivoSalida archivo(rutinaArchivo);
    si (!archivo) {
        adv "Error: No se pudo abrir el archivo " << rutinaArchivo << " para escritura.\n";
        dev falso;
    }

    // Escribe cada día y sus eventos
    cada (const auto& [dia, eventos] : eventosDiarios) {
        archivo << "[" << dia << "]\n";
        cada (const auto& evento : eventos) {
            archivo << "Evento: " << evento.obtenerNombre()
                   << ", Hora inicio: " << ancho(2) << relleno('0') 
                   << evento.obtenerHoraInicio()
                   << ":" << ancho(2) << relleno('0') 
                   << evento.obtenerMinutoInicio()
                   << ", Hora fin: " << ancho(2) << relleno('0') 
                   << evento.obtenerHoraFin()
                   << ":" << ancho(2) << relleno('0') 
                   << evento.obtenerMinutoFin() << '\n';
        }
    }

    archivo.cerrar();
    dev cierto;
}
//horario.cpp

#include "sintaxis_es.h"
#include "horario.h"
#include <fstream>

// Agrega un evento al horario en el día especificado, si no hay conflicto de horarios
bol Horario::agregarEvento(const Evento& evento, const txt& dia) {
    si (!hayConflicto(evento, dia)) {
        eventosPorDia[dia].agregar(evento);  // Usa la macro "agregar" para añadir el evento
        dev cierto;  // Indica que el evento fue agregado exitosamente
    } 
    imp "Conflicto de horario detectado. Evento no agregado.\n";
    dev falso;  // Indica que no se pudo agregar el evento debido a un conflicto
}

// Elimina un evento del horario dado su nombre y día especificado
bol Horario::eliminarEvento(const txt& nombreEvento, const txt& dia) {
    fn& eventos = eventosPorDia[dia];
    cada (fn esto = eventos.begin(); esto != eventos.end(); ++esto) {
        si (esto->obtenerNombre() == nombreEvento) {
            eventos.eliminar(esto);  // Usa la macro "eliminar" para borrar el evento
            dev cierto;  // Indica que el evento fue eliminado
        }
    }
    imp "Evento no encontrado.\n";
    dev falso;  // Indica que el evento no se encontró en el día especificado
}

// Muestra todos los eventos de un día en formato 12 o 24 horas
nulo Horario::mostrarEventos(const txt& dia, bol formato24Horas) const {
    si (eventosPorDia.encontrar(dia) != eventosPorDia.end()) {
        cada (const fn& evento : eventosPorDia.at(dia)) {
            imp "Evento: " << evento.obtenerNombre()
                << ", Hora de inicio: " << evento.obtenerHoraInicioFormato(formato24Horas)
                << ", Hora de fin: " << evento.obtenerHoraFinFormato(formato24Horas) << '\n';
        }
    } sino {
        imp "No hay eventos para el día " << dia << ".\n";
    }
}

// Verifica si un nuevo evento tiene un conflicto de horario en el día especificado
bol Horario::hayConflicto(const Evento& nuevoEvento, const txt& dia) const {
    si (eventosPorDia.encontrar(dia) != eventosPorDia.end()) {
        cada (const fn& evento : eventosPorDia.at(dia)) {
            // Convierte las horas y minutos de inicio y fin a minutos para facilitar la comparación
            num inicio1 = evento.obtenerHoraInicio() * 60 + evento.obtenerMinutoInicio();
            num fin1 = evento.obtenerHoraFin() * 60 + evento.obtenerMinutoFin();
            num inicio2 = nuevoEvento.obtenerHoraInicio() * 60 + nuevoEvento.obtenerMinutoInicio();
            num fin2 = nuevoEvento.obtenerHoraFin() * 60 + nuevoEvento.obtenerMinutoFin();

            // Comprueba si los horarios de los eventos se superponen
            si ((inicio1 < fin2) && (inicio2 < fin1)) {
                dev cierto;  // Conflicto detectado
            }
        }
    }
    dev falso;  // No hay conflicto de horario
}
//evento.h

#ifndef EVENTO_H
#define EVENTO_H

#include "sintaxis_es.h"

// Clase que representa un evento con nombre, hora de inicio y fin
clase Evento {
publico:
    // Constructor que inicializa un evento con su nombre, hora y minuto de inicio y fin
    Evento(const txt& nombre, num horaInicio, num minutoInicio, num horaFin, num minutoFin);

    // Métodos para obtener los atributos básicos del evento
    txt obtenerNombre() const;          // Retorna el nombre del evento
    num obtenerHoraInicio() const;      // Retorna la hora de inicio del evento (horas)
    num obtenerMinutoInicio() const;    // Retorna el minuto de inicio del evento
    num obtenerHoraFin() const;         // Retorna la hora de finalización del evento (horas)
    num obtenerMinutoFin() const;       // Retorna el minuto de finalización del evento

    // Formateo de horas en 12 y 24 horas
    txt obtenerHoraInicioFormato(bol formato24Horas) const; // Retorna la hora de inicio en formato 12 o 24 horas
    txt obtenerHoraFinFormato(bol formato24Horas) const;    // Retorna la hora de fin en formato 12 o 24 horas

privado:
    txt nombre;            // Nombre del evento
    num horaInicio;        // Hora de inicio del evento (horas)
    num minutoInicio;      // Minuto de inicio del evento
    num horaFin;           // Hora de fin del evento (horas)
    num minutoFin;         // Minuto de fin del evento

    // Método privado para formatear la hora y minuto en 12 o 24 horas
    txt formatoHora(num hora, num minuto, bol formato24Horas) const;
};

#endif
//horario.h

#ifndef HORARIO_H
#define HORARIO_H
#include <map>
#include "evento.h"
#include "sintaxis_es.h"

// Clase que representa un horario de eventos organizados por día
clase Horario {
publico:
    // Agrega un evento al horario en un día específico
    bol agregarEvento(const Evento& evento, const txt& dia);
    
    // Elimina un evento del horario por su nombre y día específico
    bol eliminarEvento(const txt& nombreEvento, const txt& dia);
    
    // Muestra todos los eventos de un día en formato 12 o 24 horas
    nulo mostrarEventos(const txt& dia, bol formato24Horas) const;
    
    // Métodos para sincronización con Rutina
    const mapa<txt, lista<Evento>>& obtenerTodosEventos() const {
        dev eventosPorDia;
    }
    
    nulo establecerEventos(const mapa<txt, lista<Evento>>& nuevosEventos) {
        eventosPorDia = nuevosEventos;
    }

privado:
    mapa<txt, lista<Evento>> eventosPorDia; // Mapa de listas de eventos organizados por día
    
    // Verifica si el nuevo evento tiene un conflicto en un día específico
    bol hayConflicto(const Evento& nuevoEvento, const txt& dia) const;
};

#endif // HORARIO_H
// rutina.h
#ifndef RUTINA_H
#define RUTINA_H
#include <map>
#include "evento.h"
#include "sintaxis_es.h"

clase Rutina {
publico:
    bol cargarDesdeArchivo(const txt& rutaArchivo);
    bol guardarEnArchivo(const txt& rutaArchivo) const;
    lista<Evento> obtenerEventos(const txt& dia) const;
    
    // Nuevo método para establecer los eventos
    nulo establecerEventos(const mapa<txt, lista<Evento>>& eventos) {
        eventosDiarios = eventos;
    }
    
    // Nuevo método para obtener todos los eventos
    const mapa<txt, lista<Evento>>& obtenerTodosEventos() const {
        dev eventosDiarios;
    }

privado:
    mapa<txt, lista<Evento>> eventosDiarios;
    bol parsearLinea(const txt& linea, const txt& dia);
};
#endif
//sintaxis_es.h

#ifndef SINTAXIS_ES_H
#define SINTAXIS_ES_H

#include <iostream>
#include <vector>
#include <string>
#include <stdexcept>
#include <algorithm>
#include <map>
#include <fstream>      // Para manejo de archivos
#include <sstream>      // Para stringstream
#include <iomanip>      // Para setw y setfill
#include <regex>        // Para expresiones regulares

// --- Tipos de Datos ---
typedef int num;                  // Para representar enteros
typedef bool bol;                 // Para representar booleanos
typedef std::string txt;          // Para representar cadenas de texto

// --- Manejo de Streams ---
typedef std::ostringstream FlujoSalida;    // Para string stream de salida
typedef std::ifstream ArchivoEntrada;      // Para lectura de archivos
typedef std::ofstream ArchivoSalida;       // Para escritura de archivos
#define obt_linea std::getline             // Para leer líneas de texto
#define fat str                            // Para convertir flujo a texto

// Plantilla de lista para soportar vectores de cualquier tipo de dato
template<typename T>
using lista = std::vector<T>;     // Definición de lista genérica

// Plantilla de mapa para usar mapas con tipos personalizados
template<typename K, typename V>
using mapa = std::map<K, V>;      // Definición de mapa genérico

// --- Constantes Booleanas ---
#define cierto true               // Equivalente a 'true'
#define falso false              // Equivalente a 'false'

// --- Métodos de Contenedores ---
#define agregar push_back        // Agregar elemento
#define eliminar erase          // Eliminar elemento
#define encontrar find          // Buscar elemento
#define tamano size            // Obtener tamaño
#define vacio empty           // Verificar si está vacío
#define limpiar clear        // Limpiar contenedor

// --- Entrada y Salida ---
#define imp std::cout <<         // Imprimir en consola
#define adv std::cerr <<         // Imprimir error
#define leer std::cin           // Leer entrada

// --- Formateo de Salida ---
#define ancho std::setw         // Establecer ancho de campo
#define relleno std::setfill    // Establecer carácter de relleno

// --- Expresiones Regulares ---
#define expr_reg std::regex           // Definir expresión regular
#define coinc_expr std::regex_match   // Verificar coincidencia
#define busq_expr std::smatch         // Almacenar coincidencias

// --- Control de Flujo ---
#define si if                    // Estructura condicional if
#define sino else               // Alternativa else
#define mientras while          // Bucle while
#define cada for               // Bucle for
#define hacer do              // Bucle do-while
#define romper break         // Romper bucle
#define continuar continue   // Continuar bucle
#define segun switch        // Switch
#define caso case          // Case
#define defecto default   // Default

// --- Control de Funciones ---
#define fn auto                  // Función automática
#define dev return              // Retornar valor
#define nulo void              // Sin tipo de retorno

// --- Clases y Acceso ---
#define clase class             // Definir clase
#define privado private        // Acceso privado
#define publico public        // Acceso público
#define protegido protected   // Acceso protegido

// --- Manejo de Excepciones ---
#define cap try                 // Bloque try
#define excep catch            // Bloque catch

// --- Punto de Entrada ---
#define nucleo int main        // Función principal

// --- Conversión de Tipos ---
#define a_entero std::stoi     // Convertir a entero
#define a_texto std::to_string // Convertir a texto

// --- Manejo de Archivos ---
#define cerrar close  // Cierra un archivo o flujo

#endif // SINTAXIS_ES_H
1 me gusta

actualización:

// Principal.cpp

#include "sintaxis_es.h"
#include "horario.h"
#include "rutina.h"
#include "interfaz_cli.h"

nucleo() {
    iniciarInterfazCLI();  // Llama a la función que inicia la interfaz de usuario
    dev 0;
}
// interfaz_cli.cpp

#include "sintaxis_es.h"
#include "interfaz_cli.h"
#include "utilidades.h"
#include "horario.h"
#include "rutina.h"
#include "evento.h"
#include "exportador.h"

nulo MostrarMenu() {
    LimpiarPantalla();
    imp "=== Gestión de Horarios ===\n"
        << "1. Agregar evento\n"
        << "2. Eliminar evento\n"
        << "3. Mostrar eventos de un día\n"
        << "4. Guardar rutina\n"
        << "5. Cargar rutina\n"
        << "6. Cambiar formato de hora (12/24 horas)\n"
        << "7. Exportar horario a CSV\n"
        << "8. Exportar horario a PDF\n"
        << "9. Salir\n"
        << "Seleccione una opción: ";
}

txt seleccionarDia() {
    LimpiarPantalla();
    mapa<num, txt> dias = {
        {1, "Lunes"}, {2, "Martes"}, {3, "Miércoles"},
        {4, "Jueves"}, {5, "Viernes"}, {6, "Sábado"}, {7, "Domingo"}
    };

    num opcion;
    imp "Seleccione el día:\n";
    cada (const fn& [indice, dia] : dias) {
        imp indice << ". " << dia << '\n';
    }
    imp "Ingrese el número del día: ";
    leer >> opcion;
    LimpiarBuffer();

    si (dias.encontrar(opcion) != dias.end()) {
        dev dias[opcion];
    } sino {
        imp "Opción no válida. Seleccionando Lunes por defecto.\n";
        PausarPantalla();
        dev "Lunes";
    }
}

nulo iniciarInterfazCLI() {
    Horario horario;
    Rutina rutina;
    bol formato24Horas = cierto;
    num opcion;

    hacer {
        MostrarMenu();
        leer >> opcion;
        LimpiarBuffer();

        segun(opcion) {
            caso 1: {  
                txt nombre, dia;
                num horaInicio, minutoInicio, horaFin, minutoFin;
                dia = seleccionarDia();

                LimpiarPantalla();
                imp "=== Agregar Nuevo Evento ===\n\n";
                imp "Ingrese el nombre del evento: ";
                obt_linea(leer, nombre);

                imp "Ingrese la hora de inicio (0-23): ";
                leer >> horaInicio;
                LimpiarBuffer();

                imp "Ingrese el minuto de inicio (0-59): ";
                leer >> minutoInicio;
                LimpiarBuffer();

                imp "Ingrese la hora de finalización (0-23): ";
                leer >> horaFin;
                LimpiarBuffer();

                imp "Ingrese el minuto de finalización (0-59): ";
                leer >> minutoFin;
                LimpiarBuffer();

                Evento evento(nombre, horaInicio, minutoInicio, horaFin, minutoFin);

                si (horario.agregarEvento(evento, dia)) {
                    imp "\n✓ Evento agregado exitosamente.\n";
                } sino {
                    imp "\n✗ No se pudo agregar el evento debido a un conflicto.\n";
                }
                PausarPantalla();
                romper;
            }
            caso 2: {  
                txt nombre, dia;
                dia = seleccionarDia();

                LimpiarPantalla();
                imp "=== Eliminar Evento ===\n\n";
                imp "Ingrese el nombre del evento a eliminar: ";
                obt_linea(leer, nombre);

                si (horario.eliminarEvento(nombre, dia)) {
                    imp "\n✓ Evento eliminado exitosamente.\n";
                } sino {
                    imp "\n✗ No se encontró el evento a eliminar.\n";
                }
                PausarPantalla();
                romper;
            }
            caso 3: {  
                txt dia = seleccionarDia();
                LimpiarPantalla();
                imp "=== Eventos del " << dia << " ===\n\n";
                horario.mostrarEventos(dia, formato24Horas);
                PausarPantalla();
                romper;
            }
            caso 4: {  
                LimpiarPantalla();
                imp "=== Guardar Rutina ===\n\n";
                txt archivo;
                imp "Ingrese el nombre del archivo para guardar la rutina: ";
                obt_linea(leer, archivo);
                archivo += ".hrt";

                rutina.establecerEventos(horario.obtenerTodosEventos());

                si (rutina.guardarEnArchivo(archivo)) {
                    imp "\n✓ Rutina guardada en " << archivo << " exitosamente.\n";
                } sino {
                    imp "\n✗ Error al guardar la rutina.\n";
                }
                PausarPantalla();
                romper;
            }
            caso 5: {  
                LimpiarPantalla();
                imp "=== Cargar Rutina ===\n\n";
                txt archivo;
                imp "Ingrese el nombre del archivo para cargar la rutina: ";
                obt_linea(leer, archivo);
                archivo += ".hrt";

                si (rutina.cargarDesdeArchivo(archivo)) {
                    horario.establecerEventos(rutina.obtenerTodosEventos());
                    imp "\n✓ Rutina cargada desde " << archivo << " exitosamente.\n";
                } sino {
                    imp "\n✗ Error al cargar la rutina.\n";
                }
                PausarPantalla();
                romper;
            }
            caso 6: {  
                formato24Horas = !formato24Horas;
                LimpiarPantalla();
                imp "=== Cambio de Formato de Hora ===\n\n";
                imp "✓ Formato de hora cambiado a " << (formato24Horas ? "24 horas" : "12 horas") << ".\n";
                PausarPantalla();
                romper;
            }
            caso 7: {  // Exportar a CSV
                LimpiarPantalla();
                imp "=== Exportar Horario a CSV ===\n\n";
                txt nombreArchivo;
                imp "Ingrese el nombre del archivo (sin extensión): ";
                obt_linea(leer, nombreArchivo);
                nombreArchivo += ".csv";

                Exportador exportador(horario);
                si (exportador.exportarCSV(nombreArchivo)) {
                    imp "\n✓ Horario exportado a " << nombreArchivo << " exitosamente.\n";
                } sino {
                    imp "\n✗ Error al exportar el horario a CSV.\n";
                }
                PausarPantalla();
                romper;
            }

            caso 8: {  // Exportar a PDF
                LimpiarPantalla();
                imp "=== Exportar Horario a PDF ===\n\n";
                txt nombreArchivo;
                imp "Ingrese el nombre del archivo (sin extensión): ";
                obt_linea(leer, nombreArchivo);
                nombreArchivo += ".pdf";

                Exportador exportador(horario);
                si (exportador.exportarPDF(nombreArchivo)) {
                    imp "\n✓ Horario exportado a " << nombreArchivo << " exitosamente.\n";
                } sino {
                    imp "\n✗ Error al exportar el horario a PDF.\n"
                        << "Asegúrese de tener instalado wkhtmltopdf en su sistema.\n";
                }
                PausarPantalla();
                romper;
            }

            caso 9: {  // Salir (anteriormente caso 7)
                LimpiarPantalla();
                imp "¡Gracias por usar el Gestor de Horarios!\n";
                romper;
            }

            defecto: {
                LimpiarPantalla();
                imp "✗ Opción no válida. Intente de nuevo.\n";
                PausarPantalla();
                romper;
            }
        }
    } mientras (opcion != 9);  // Modificar condición de salida
}
// interfaz_cli.h

#ifndef INTERFAZ_CLI_H
#define INTERFAZ_CLI_H

nulo iniciarInterfazCLI();

#endif // INTERFAZ_CLI_H
// utilidades.cpp

#include "sintaxis_es.h"
#include "utilidades.h"

nulo LimpiarPantalla() {
    #ifdef _WIN32
        sistema(LPW);
    #else
        sistema(LPU);
    #endif
}

nulo LimpiarBuffer() {
    leer.limpiar();
    leer.ignorar(limite_maximo<tam_flujo>::max(), '\n');  // Usar `limite_maximo` en lugar de `std::numeric_limits`
}

nulo PausarPantalla() {
    imp "\nPresione Enter para continuar...";
    leer.obt();
}
// utilidades.h

#ifndef UTILIDADES_H
#define UTILIDADES_H

nulo LimpiarPantalla();
nulo LimpiarBuffer();
nulo PausarPantalla();

#endif // UTILIDADES_H
//evento.cpp

#include "evento.h"
#include "sintaxis_es.h"

// Constructor de la clase Evento: inicializa el evento con su nombre, hora y minuto de inicio y fin
Evento::Evento(const txt& nombre, num horaInicio, num minutoInicio, num horaFin, num minutoFin)
    : nombre(nombre), horaInicio(horaInicio), minutoInicio(minutoInicio), horaFin(horaFin), minutoFin(minutoFin) {}

// Métodos para obtener los atributos individuales del evento
txt Evento::obtenerNombre() const { dev nombre; }
num Evento::obtenerHoraInicio() const { dev horaInicio; }
num Evento::obtenerMinutoInicio() const { dev minutoInicio; }
num Evento::obtenerHoraFin() const { dev horaFin; }
num Evento::obtenerMinutoFin() const { dev minutoFin; }

// Método para obtener la hora de inicio en formato de 12 o 24 horas
txt Evento::obtenerHoraInicioFormato(bol formato24Horas) const {
    dev formatoHora(horaInicio, minutoInicio, formato24Horas);
}

// Método para obtener la hora de fin en formato de 12 o 24 horas
txt Evento::obtenerHoraFinFormato(bol formato24Horas) const {
    dev formatoHora(horaFin, minutoFin, formato24Horas);
}

// Método privado para formatear la hora y minutos en formato de 12 o 24 horas
txt Evento::formatoHora(num hora, num minuto, bol formato24Horas) const {
    FlujoSalida oss;
    si (formato24Horas) {
        oss << ancho(2) << relleno('0') << hora << ":"
            << ancho(2) << relleno('0') << minuto;
    } sino {
        num horas12 = hora % 12 == 0 ? 12 : hora % 12;
        txt periodo = hora < 12 ? "AM" : "PM";
        oss << ancho(2) << relleno('0') << horas12 << ":"
            << ancho(2) << relleno('0') << minuto << " " << periodo;
    }
    dev oss.fat();
}
//evento.h

#ifndef EVENTO_H
#define EVENTO_H

#include "sintaxis_es.h"

// Clase que representa un evento con nombre, hora de inicio y fin
clase Evento {
publico:
    // Constructor que inicializa un evento con su nombre, hora y minuto de inicio y fin
    Evento(const txt& nombre, num horaInicio, num minutoInicio, num horaFin, num minutoFin);

    // Métodos para obtener los atributos básicos del evento
    txt obtenerNombre() const;          // Retorna el nombre del evento
    num obtenerHoraInicio() const;      // Retorna la hora de inicio del evento (horas)
    num obtenerMinutoInicio() const;    // Retorna el minuto de inicio del evento
    num obtenerHoraFin() const;         // Retorna la hora de finalización del evento (horas)
    num obtenerMinutoFin() const;       // Retorna el minuto de finalización del evento

    // Formateo de horas en 12 y 24 horas
    txt obtenerHoraInicioFormato(bol formato24Horas) const; // Retorna la hora de inicio en formato 12 o 24 horas
    txt obtenerHoraFinFormato(bol formato24Horas) const;    // Retorna la hora de fin en formato 12 o 24 horas

privado:
    txt nombre;            // Nombre del evento
    num horaInicio;        // Hora de inicio del evento (horas)
    num minutoInicio;      // Minuto de inicio del evento
    num horaFin;           // Hora de fin del evento (horas)
    num minutoFin;         // Minuto de fin del evento

    // Método privado para formatear la hora y minuto en 12 o 24 horas
    txt formatoHora(num hora, num minuto, bol formato24Horas) const;
};

#endif
// rutina.cpp
#include "rutina.h"
#include "sintaxis_es.h"
#include <fstream>
#include <sstream>
#include <iomanip>
#include <regex>

bol Rutina::cargarDesdeArchivo(const txt& rutinaArchivo) {
    ArchivoEntrada archivo(rutinaArchivo);
    si (!archivo) {
        adv "Error: No se pudo abrir el archivo " << rutinaArchivo << " para lectura.\n";
        dev falso;
    }

    txt linea;
    txt diaActual;
    eventosDiarios.limpiar(); // Limpia los eventos existentes

    expr_reg diaReg(R"(\[(.*?)\])");
    expr_reg formatoEvento(R"(Evento:\s*(.+?),\s*Hora inicio:\s*(\d{2}):(\d{2}),\s*Hora fin:\s*(\d{2}):(\d{2}))");
    
    mientras (obt_linea(archivo, linea)) {
        busq_expr coinc;
        
        // Verifica si es una línea de día
        si (coinc_expr(linea, coinc, diaReg)) {
            diaActual = coinc[1];
            continuar;
        }
        
        // Procesa la línea de evento
        si (coinc_expr(linea, coinc, formatoEvento)) {
            txt nombre = coinc[1];
            num horaInicio = a_entero(coinc[2]);
            num minutoInicio = a_entero(coinc[3]);
            num horaFin = a_entero(coinc[4]);
            num minutoFin = a_entero(coinc[5]);
            
            Evento evento(nombre, horaInicio, minutoInicio, horaFin, minutoFin);
            eventosDiarios[diaActual].agregar(evento);
        }
    }
    
    archivo.cerrar();
    dev cierto;
}

bol Rutina::guardarEnArchivo(const txt& rutinaArchivo) const {
    ArchivoSalida archivo(rutinaArchivo);
    si (!archivo) {
        adv "Error: No se pudo abrir el archivo " << rutinaArchivo << " para escritura.\n";
        dev falso;
    }

    // Escribe cada día y sus eventos
    cada (const auto& [dia, eventos] : eventosDiarios) {
        archivo << "[" << dia << "]\n";
        cada (const auto& evento : eventos) {
            archivo << "Evento: " << evento.obtenerNombre()
                   << ", Hora inicio: " << ancho(2) << relleno('0') 
                   << evento.obtenerHoraInicio()
                   << ":" << ancho(2) << relleno('0') 
                   << evento.obtenerMinutoInicio()
                   << ", Hora fin: " << ancho(2) << relleno('0') 
                   << evento.obtenerHoraFin()
                   << ":" << ancho(2) << relleno('0') 
                   << evento.obtenerMinutoFin() << '\n';
        }
    }

    archivo.cerrar();
    dev cierto;
}
// rutina.h
#ifndef RUTINA_H
#define RUTINA_H
#include <map>
#include "evento.h"
#include "sintaxis_es.h"

clase Rutina {
publico:
    bol cargarDesdeArchivo(const txt& rutaArchivo);
    bol guardarEnArchivo(const txt& rutaArchivo) const;
    lista<Evento> obtenerEventos(const txt& dia) const;
    
    // Nuevo método para establecer los eventos
    nulo establecerEventos(const mapa<txt, lista<Evento>>& eventos) {
        eventosDiarios = eventos;
    }
    
    // Nuevo método para obtener todos los eventos
    const mapa<txt, lista<Evento>>& obtenerTodosEventos() const {
        dev eventosDiarios;
    }

privado:
    mapa<txt, lista<Evento>> eventosDiarios;
    bol parsearLinea(const txt& linea, const txt& dia);
};
#endif
//horario.cpp

#include "sintaxis_es.h"
#include "horario.h"
#include <fstream>

// Agrega un evento al horario en el día especificado, si no hay conflicto de horarios
bol Horario::agregarEvento(const Evento& evento, const txt& dia) {
    si (!hayConflicto(evento, dia)) {
        eventosPorDia[dia].agregar(evento);  // Usa la macro "agregar" para añadir el evento
        dev cierto;  // Indica que el evento fue agregado exitosamente
    } 
    imp "Conflicto de horario detectado. Evento no agregado.\n";
    dev falso;  // Indica que no se pudo agregar el evento debido a un conflicto
}

// Elimina un evento del horario dado su nombre y día especificado
bol Horario::eliminarEvento(const txt& nombreEvento, const txt& dia) {
    fn& eventos = eventosPorDia[dia];
    cada (fn esto = eventos.begin(); esto != eventos.end(); ++esto) {
        si (esto->obtenerNombre() == nombreEvento) {
            eventos.eliminar(esto);  // Usa la macro "eliminar" para borrar el evento
            dev cierto;  // Indica que el evento fue eliminado
        }
    }
    imp "Evento no encontrado.\n";
    dev falso;  // Indica que el evento no se encontró en el día especificado
}

// Muestra todos los eventos de un día en formato 12 o 24 horas
nulo Horario::mostrarEventos(const txt& dia, bol formato24Horas) const {
    si (eventosPorDia.encontrar(dia) != eventosPorDia.end()) {
        cada (const fn& evento : eventosPorDia.at(dia)) {
            imp "Evento: " << evento.obtenerNombre()
                << ", Hora de inicio: " << evento.obtenerHoraInicioFormato(formato24Horas)
                << ", Hora de fin: " << evento.obtenerHoraFinFormato(formato24Horas) << '\n';
        }
    } sino {
        imp "No hay eventos para el día " << dia << ".\n";
    }
}

// Verifica si un nuevo evento tiene un conflicto de horario en el día especificado
bol Horario::hayConflicto(const Evento& nuevoEvento, const txt& dia) const {
    si (eventosPorDia.encontrar(dia) != eventosPorDia.end()) {
        cada (const fn& evento : eventosPorDia.at(dia)) {
            // Convierte las horas y minutos de inicio y fin a minutos para facilitar la comparación
            num inicio1 = evento.obtenerHoraInicio() * 60 + evento.obtenerMinutoInicio();
            num fin1 = evento.obtenerHoraFin() * 60 + evento.obtenerMinutoFin();
            num inicio2 = nuevoEvento.obtenerHoraInicio() * 60 + nuevoEvento.obtenerMinutoInicio();
            num fin2 = nuevoEvento.obtenerHoraFin() * 60 + nuevoEvento.obtenerMinutoFin();

            // Comprueba si los horarios de los eventos se superponen
            si ((inicio1 < fin2) && (inicio2 < fin1)) {
                dev cierto;  // Conflicto detectado
            }
        }
    }
    dev falso;  // No hay conflicto de horario
}
//horario.h

#ifndef HORARIO_H
#define HORARIO_H
#include <map>
#include "evento.h"
#include "sintaxis_es.h"

// Clase que representa un horario de eventos organizados por día
clase Horario {
publico:
    // Agrega un evento al horario en un día específico
    bol agregarEvento(const Evento& evento, const txt& dia);
    
    // Elimina un evento del horario por su nombre y día específico
    bol eliminarEvento(const txt& nombreEvento, const txt& dia);
    
    // Muestra todos los eventos de un día en formato 12 o 24 horas
    nulo mostrarEventos(const txt& dia, bol formato24Horas) const;
    
    // Métodos para sincronización con Rutina
    const mapa<txt, lista<Evento>>& obtenerTodosEventos() const {
        dev eventosPorDia;
    }
    
    nulo establecerEventos(const mapa<txt, lista<Evento>>& nuevosEventos) {
        eventosPorDia = nuevosEventos;
    }

privado:
    mapa<txt, lista<Evento>> eventosPorDia; // Mapa de listas de eventos organizados por día
    
    // Verifica si el nuevo evento tiene un conflicto en un día específico
    bol hayConflicto(const Evento& nuevoEvento, const txt& dia) const;
};

#endif // HORARIO_H
#include "exportador.h"
#include <cstdlib>
#include <map>
#include <set>
Exportador::Exportador(const Horario& horario) : horario(horario) {}

// Función auxiliar para obtener todos los intervalos de tiempo únicos
lista<IntervaloTiempo> Exportador::obtenerIntervalosUnicos() const {
    std::set<IntervaloTiempo> intervalos;
    const auto& todosEventos = horario.obtenerTodosEventos();
    
    cada (const auto& parDiaEventos : todosEventos) {
        cada (const Evento& evento : parDiaEventos.second) {
            intervalos.insert({evento.obtenerHoraInicio(), evento.obtenerMinutoInicio()});
            intervalos.insert({evento.obtenerHoraFin(), evento.obtenerMinutoFin()});
        }
    }
    
    dev lista<IntervaloTiempo>(intervalos.begin(), intervalos.end());
}

txt Exportador::formatearIntervalo(const IntervaloTiempo& intervalo, bol formato24Horas) const {
    FlujoSalida ss;
    si (formato24Horas) {
        ss << ancho(2) << relleno('0') << intervalo.hora << ":"
           << ancho(2) << relleno('0') << intervalo.minuto;
    } sino {
        num hora12 = intervalo.hora % 12;
        si (hora12 == 0) hora12 = 12;
        ss << ancho(2) << relleno('0') << hora12 << ":"
           << ancho(2) << relleno('0') << intervalo.minuto
           << (intervalo.hora < 12 ? " AM" : " PM");
    }
    dev ss.fat();
}

bol Exportador::exportarCSV(const txt& nombreArchivo) const {
    cap {
        ArchivoSalida archivo(nombreArchivo);
        si (!archivo) {
            adv "Error al abrir el archivo para escritura\n";
            dev falso;
        }

        lista<txt> diasSemana = {"Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado", "Domingo"};
        
        // Escribir encabezado
        archivo << "Hora,";
        cada (const auto& dia : diasSemana) {
            archivo << dia;
            si (dia != diasSemana.back()) archivo << ",";
        }
        archivo << "\n";

        // Obtener todos los intervalos de tiempo
        auto intervalos = obtenerIntervalosUnicos();
        std::sort(intervalos.begin(), intervalos.end());

        // Escribir cada fila
        cada (const auto& intervalo : intervalos) {
            archivo << formatearIntervalo(intervalo, cierto) << ",";
            
            cada (const auto& dia : diasSemana) {
                bol eventoEncontrado = falso;
                const auto& eventos = horario.obtenerTodosEventos();
                
                si (eventos.encontrar(dia) != eventos.end()) {
                    cada (const auto& evento : eventos.at(dia)) {
                        num inicioEvento = evento.obtenerHoraInicio() * 60 + evento.obtenerMinutoInicio();
                        num finEvento = evento.obtenerHoraFin() * 60 + evento.obtenerMinutoFin();
                        num tiempoActual = intervalo.hora * 60 + intervalo.minuto;
                        
                        si (tiempoActual >= inicioEvento && tiempoActual < finEvento) {
                            archivo << evento.obtenerNombre();
                            eventoEncontrado = cierto;
                            romper;
                        }
                    }
                }
                
                si (!eventoEncontrado) archivo << "";
                si (dia != diasSemana.back()) archivo << ",";
            }
            archivo << "\n";
        }

        archivo.cerrar();
        dev cierto;
    } excep (const std::exception& e) {
        adv "Error al exportar a CSV: " << e.what() << '\n';
        dev falso;
    }
}

bol Exportador::exportarPDF(const txt& nombreArchivo) const {
    cap {
        txt nombreHTML = nombreArchivo + ".html";
        ArchivoSalida archivo(nombreHTML);
        
        si (!archivo) {
            adv "Error al crear archivo HTML temporal\n";
            dev falso;
        }

        archivo << generarHTML();
        archivo.cerrar();

        txt comando = "wkhtmltopdf " + nombreHTML + " " + nombreArchivo;
        num resultado = sistema(comando.c_str());
        sistema(("rm " + nombreHTML).c_str());

        dev resultado == 0;
    } excep (const std::exception& e) {
        adv "Error al exportar a PDF: " << e.what() << '\n';
        dev falso;
    }
}

txt Exportador::obtenerEstilosCSS() const {
    dev R"(
        table { 
            border-collapse: collapse; 
            width: 100%; 
            margin-bottom: 20px; 
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        th, td { 
            border: 1px solid #ddd;
            padding: 12px 8px;
            text-align: center;
            font-size: 14px;
            vertical-align: top;
        }
        th { 
            background-color: #2c3e50;
            color: white;
            font-weight: bold;
            padding: 15px;
        }
        td.hora { 
            background-color: #f8f9fa;
            width: 120px;
            position: relative;
            padding: 0;
        }
        .intervalo-tiempo {
            display: flex;
            flex-direction: column;
            height: 100%;
            padding: 8px;
        }
        .tiempo-inicio {
            color: #2c3e50;
            font-weight: bold;
            font-size: 15px;
            border-bottom: 2px solid #e9ecef;
            padding-bottom: 4px;
            margin-bottom: 4px;
        }
        .tiempo-fin {
            color: #6c757d;
            font-size: 13px;
        }
        .duracion {
            font-size: 11px;
            color: #95a5a6;
            margin-top: 4px;
            font-style: italic;
        }
        td.evento { 
            background-color: #e6f3ff;
            transition: background-color 0.2s;
        }
        td.evento:hover {
            background-color: #d1e7ff;
        }
        .tiempo-evento {
            font-size: 12px;
            color: #666;
            display: block;
            margin-bottom: 4px;
            background: rgba(255,255,255,0.5);
            padding: 2px 4px;
            border-radius: 3px;
        }
        .nombre-evento {
            font-weight: bold;
            color: #2c3e50;
        }
        h1 { 
            text-align: center; 
            color: #2c3e50;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            margin-bottom: 30px;
        }
        .horario-container { 
            padding: 20px;
            max-width: 1200px;
            margin: 0 auto;
        }
    )";
}

txt Exportador::formatearColumnaTiempo(const IntervaloTiempo& actual, const IntervaloTiempo& siguiente) const {
    FlujoSalida ss;
    
    // Calcular la duración del intervalo en minutos
    num duracionMinutos = 0;
    si (siguiente.hora * 60 + siguiente.minuto > actual.hora * 60 + actual.minuto) {
        duracionMinutos = (siguiente.hora * 60 + siguiente.minuto) - (actual.hora * 60 + actual.minuto);
    }
    
    ss << "<div class=\"intervalo-tiempo\">"
       << "<div class=\"tiempo-inicio\">" 
       << formatearIntervalo(actual, cierto)
       << "</div>"
       << "<div class=\"tiempo-fin\">"
       << "hasta " << formatearIntervalo(siguiente, cierto)
       << "</div>";
    
    // Añadir la duración si es relevante
    si (duracionMinutos > 0) {
        ss << "<div class=\"duracion\">";
        si (duracionMinutos >= 60) {
            num horas = duracionMinutos / 60;
            num mins = duracionMinutos % 60;
            si (horas > 0) {
                ss << horas << "h";
                si (mins > 0) ss << " " << mins << "min";
            }
        } sino {
            ss << duracionMinutos << " min";
        }
        ss << "</div>";
    }
    
    ss << "</div>";
    dev ss.fat();
}

txt Exportador::generarHTML() const {
    FlujoSalida html;
    html << "<!DOCTYPE html>\n<html><head>\n"
         << "<style>\n" << obtenerEstilosCSS() << "</style>\n"
         << "<meta charset=\"UTF-8\">\n"
         << "</head><body>\n"
         << "<div class=\"horario-container\">\n"
         << "<h1>Horario de Actividades</h1>\n"
         << "<table>\n";

    lista<txt> diasSemana = {"Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado", "Domingo"};
    
    // Encabezado con días
    html << "<tr><th>Hora</th>";
    cada (const auto& dia : diasSemana) {
        html << "<th>" << dia << "</th>";
    }
    html << "</tr>\n";

    // Obtener intervalos de tiempo
    auto intervalos = obtenerIntervalosUnicos();
    std::sort(intervalos.begin(), intervalos.end());

    // Generar filas
    cada (std::vector<IntervaloTiempo>::size_type i = 0; i < intervalos.tamano(); i++) {
        html << "<tr><td class=\"hora\">";
        
        // Si no es el último intervalo, mostrar el intervalo actual y el siguiente
        si (i < intervalos.tamano() - 1) {
            html << formatearColumnaTiempo(intervalos[i], intervalos[i + 1]);
        } sino {
            // Para el último intervalo, mostrar solo la hora final
            html << "<div class=\"intervalo-tiempo\">"
                 << "<div class=\"tiempo-inicio\">" 
                 << formatearIntervalo(intervalos[i], cierto)
                 << "</div></div>";
        }
        html << "</td>";
        
        cada (const auto& dia : diasSemana) {
            bol eventoEncontrado = falso;
            const auto& eventos = horario.obtenerTodosEventos();
            
            si (eventos.encontrar(dia) != eventos.end()) {
                cada (const auto& evento : eventos.at(dia)) {
                    num inicioEvento = evento.obtenerHoraInicio() * 60 + evento.obtenerMinutoInicio();
                    num finEvento = evento.obtenerHoraFin() * 60 + evento.obtenerMinutoFin();
                    num tiempoActual = intervalos[i].hora * 60 + intervalos[i].minuto;
                    
                    si (tiempoActual >= inicioEvento && tiempoActual < finEvento) {
                        html << "<td class=\"evento\">"
                             << "<span class=\"tiempo-evento\">"
                             << formatearIntervalo({evento.obtenerHoraInicio(), evento.obtenerMinutoInicio()}, cierto)
                             << " - "
                             << formatearIntervalo({evento.obtenerHoraFin(), evento.obtenerMinutoFin()}, cierto)
                             << "</span>"
                             << "<span class=\"nombre-evento\">"
                             << evento.obtenerNombre()
                             << "</span>"
                             << "</td>";
                        eventoEncontrado = cierto;
                        romper;
                    }
                }
            }
            
            si (!eventoEncontrado) html << "<td></td>";
        }
        html << "</tr>\n";
    }

    html << "</table>\n</div></body></html>";
    dev html.fat();
}
// exportador.h
#ifndef EXPORTADOR_H
#define EXPORTADOR_H

#include "sintaxis_es.h"
#include "horario.h"

struct IntervaloTiempo {
    num hora;
    num minuto;
    
    bol operator<(const IntervaloTiempo& otro) const {
        dev (hora * 60 + minuto) < (otro.hora * 60 + otro.minuto);
    }
    
    num aMinutos() const {
        dev hora * 60 + minuto;
    }
};

struct EventoCelda {
    txt nombre;
    IntervaloTiempo inicio;
    IntervaloTiempo fin;
    num rowspan;
    bol yaImpreso;
    
    EventoCelda(const txt& n, const IntervaloTiempo& i, const IntervaloTiempo& f) 
        : nombre(n), inicio(i), fin(f), rowspan(1), yaImpreso(falso) {}
};

clase Exportador {
publico:
    Exportador(const Horario& horario);
    bol exportarCSV(const txt& nombreArchivo) const;
    bol exportarPDF(const txt& nombreArchivo) const;
    
privado:
    const Horario& horario;
    
    lista<IntervaloTiempo> obtenerIntervalosUnicos() const;
    txt formatearIntervalo(const IntervaloTiempo& intervalo, bol formato24Horas) const;
    txt formatearColumnaTiempo(const IntervaloTiempo& actual, const IntervaloTiempo& siguiente) const;
    txt generarHTML() const;
    txt obtenerEstilosCSS() const;
    mapa<txt, lista<EventoCelda>> prepararEventosPorDia() const;
    num calcularRowspan(const EventoCelda& evento, const lista<IntervaloTiempo>& intervalos) const;
    bol eventoIntersecta(const EventoCelda& evento, const IntervaloTiempo& intervalo) const;
};

#endif // EXPORTADOR_H
1 me gusta

Interesante ejercicio. Yo hice mi propia versión usando C. Como data structure usé una linked list, ya que veía que la inserción y eliminación de elementos (en este caso, los elementos son las tareas) en la lista era muy eficiente.

Todas las funciones están en un mismo archivo, por simplicidad.

El manejo de memoria dinámica es un poco caótico, espero no estar causando ningún maldito memory leak.

demo1

/* Powered by Vim & GCC */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define M_RUN 0b1    // mask
#define M_SHUTD 0b0  // mask
#define CLEAN_SCREEN "\033c"
#define NUM_OPTION   6

typedef struct{
		char* task;
		struct Node* next;
} Node;

Node* insert_node(const char* task){
	Node* new_node = (Node*) malloc(sizeof(Node)); // asignar un bloque de memoria al nuevo nodo
	
	if (new_node == NULL){ // seguridad, detectar error en crear nodo
		perror("Error al asignar memoria");
		exit(EXIT_FAILURE);
	}

	new_node->task = (char*) malloc(strlen(task) + 1); // asignar memoria a un string dinamico
					 								   // +1 para cracter nulo, \0
	if (new_node->task == NULL){ // seguridad, detectar error al crear string dinamico
		perror("Error al asignar memoria para char*");
		free(new_node);
		exit(EXIT_FAILURE);
	}

	strcpy(new_node->task, task); // copiar cadena dada por argumento y que el nuevo nodo la copie

	new_node->next = NULL;

	return new_node;
}

Node* delete_node(Node* head, int sel){
	if (head == NULL){ // controlar con un macro
		printf("Lista vacía");
		return head;
	}

	Node* temp = head;
	Node* prev = NULL;
	
	// si es el head a eliminar
	if (sel == 0){
		head = temp->next;
		free(temp->task);
		free(temp);
		return head;
	}
	
	// si es otro elemento
	for(int i = 0; i != sel; ++i){
		prev = temp;
		temp = temp->next;
	}

	prev->next = temp->next;

	free(temp->task);
	free(temp);

	return head;
}

void print_node(Node* head){
	Node* temp = head;

	for(int i = 0; temp != NULL; ++i){
		printf("%d. %s\n", i+1, temp->task);
		temp = temp->next;
	}
}
void free_node(Node* head){
	Node* temp;

	while(head != NULL){
		temp = head->next;
		free(head->task);
		free(head);
		head = temp;
	}
}

void save_schedule(Node* head){
	FILE* file = fopen("schedule.bin", "wb");

	if (file == NULL){
		perror("Error al crear o guardar archivo");
		return;
	}

	Node* temp = head;

	while(temp != NULL){
		fprintf(file, "%s\n", temp->task);
		temp = temp->next;
	}

	fclose(file);

	printf("Horario guardado correctamente\n");
}

Node* load_schedule(int* task_num){
	FILE* file = fopen("schedule.bin", "rb");

	if (file == NULL){
		perror("Error al cargar horario");
		return NULL;
	}

	Node* head = NULL;
	Node* temp = NULL;
	char buffer[256];

	while(fgets(buffer, sizeof(buffer), file) != NULL){
		buffer[strcspn(buffer, "\n")] = '\0';
		Node* new_node = insert_node(buffer);

		if (head == NULL){
			head = new_node;
		}else{
			temp->next = new_node;
		}
		temp = new_node;
		(*task_num)++;
	}

	fclose(file);

	printf("Horario cargado correctamente\n");

	return head;
}

int show_options(){
	printf("\n--- OPCIONES ---\n");
	printf("1. Agregar tarea\n");
	printf("2. Eliminar tarea\n");
	printf("3. Guardar horario\n");
	printf("4. Cargar horario\n");
	printf("5. Salir (guardar)\n");
	printf("6. Salir (sin guardar)\n");
}

int main(int argc, char* argv[]){ // int argc, char**, for load tasks
	Node* head = NULL; // lista, inicializada como vacia
	Node* temp = NULL; // variable auxiliar
	char mode = M_RUN; // si mode = 0b1, true | si mode = 0b0, false
	char* task = NULL;
	int task_num = 0;
	size_t task_init_size = 0;
	int option;
	
	// executar argumento
	if (argc > 1 && strcmp(argv[1], "load") == 0){
		head = load_schedule(&task_num);
	}

	// escribir interfaz
	while(mode & M_RUN){
		// limpiar pantalla
		printf(CLEAN_SCREEN);

		// imprimir tasks
		print_node(head);

		// imprimir opciones disponibles
		show_options();

		// input del usuario
		do{
			printf("> ");

			scanf("%d", &option);

			while(getchar() != '\n'); // limpiar buffer

		}while(option <= 0 || option > NUM_OPTION);

		// ejecutar opcion eligida
		switch(option){
			case 1: // agregar tarea
				printf("Tarea a agregar: ");
				ssize_t task_len = getline(&task, &task_init_size, stdin); // leer entrada del usuario con getline()

				if (task_len == -1){ // en caso de que haya ocurrido un error
					perror("Error al leer entrada");
					free(task);
					return EXIT_FAILURE;
				}

				if (task[task_len-1] == '\n'){
					task[task_len-1] = '\0';
				}

				temp = insert_node(task);
				temp->next = head;
				head = temp;
				task_num++;
			break;

			case 2: // eliminar tarea
				printf("Tarea a eliminar: ");
				scanf("%d", &option);
				if (option != 0 && (option) <= task_num){
					head = delete_node(head, option-1);
				}
			break;

			case 3: // guardar horario
				save_schedule(head);
			break;

			case 4: // cargar horario
				if (head == NULL){
					head = load_schedule(&task_num);
				}
			break;

			case 5: // salir y guardar
				save_schedule(head);
				mode &= M_SHUTD;
			break;

			case 6: // salir sin guardar
				mode &= M_SHUTD;
			break;
		}
	}
	
	// liberar memoria
	free(task);
	free_node(head);

	return 0;
}

¿este lo hiciste por tu cuenta o teniendo en base al mio?
por cierto ¿podria utilizar parte de tu codigo para implementarlo de cirta forma a mi proyecto?

por cierto, con este proyecto me di cuenta que C es mucho mas legible que C++

¿este lo hiciste por tu cuenta o teniendo en base al mio?

No usé tu código de referencia, solo la idea de crear un programa de horarios y desde
ahí empecé.

¿podria utilizar parte de tu codigo para implementarlo de cirta forma a mi proyecto?

Claro, haz lo que quieras con él.

He hecho proyectos en C y en C++ (usar C y C++ en un mismo proyecto), y la verdad es que C++ tiene una sintaxis bastante fea, además de que es un lenguaje orientado a objetos, del cual tampoco es de mi simpatía.

Cuando tengo este hibrido en un proyecto, uso más un “estilo C” que un estilo correspondiente a C++. Por ejemplo, para funciones de guardar y cargar archivos uso solo elementos de C; recuerdo la vez que investigué en cómo hacer lo mismo en C++, lo encontré un tanto rebuscado.

Pero C++ es un poderoso lenguaje, eso nadie lo niega. Quizá lo use algún día para crear programas complejos, como simulaciones.

Enhorabuena!
Estaría bueno si lo subes a un repo, así se puede ver la estructura del proyecto:D

gracias, cuando pueda analizo tu proyecto y veo que utilizo

la proxima vez que haga un proyecto, lo hare en c, quiero enterarme mejor lo que hace mi codigo

estos dias, he tenido una semana algo pesada, por algunos examenes y tareas, y que ademas que me doy cuenta que se acerca diciembre y ahi tengo otras tareas, y examenes. pero bueno, en un ratito que pueda me hago un repocitorio y ahi actualizo el proyecto. ya tengo una pequeña actualizacion en el proyecto, pero es solo una estructuracion nueva que le he dado para organizarlo mejor, realmente no he añadido algo nuevo. algo que medio me preocupa es que, por pruebas que me ha echo mi padre (pues yo no tengo windows) aparentemente este programa no se compila bien en windows, por algun motivo que no me explico. esto me puede ser un problema a futuro

1 me gusta