Scan to open on your phone
Point a camera at the QR code - it opens this exact paste, no app needed.
https://codepastes.com/zzgt4epegjcfq4b6inscripciones.pyPython
class Nodo:
"""
Representa cada elemento individual (nodo) dentro de las estructuras
de datos enlazadas (ya sea para Colas o Pilas).
"""
def __init__(self, nombre, id_estudiante, prioridad=None, siguiente=None):
self.nombre = nombre # Nombre del estudiante
self.id_estudiante = id_estudiante # Identificador único del estudiante
self.prioridad = prioridad # Nivel de prioridad opcional (1 a 5) usado en ColaPrioridad
self.siguiente = siguiente # Puntero de enlace hacia el siguiente nodo en la memoria
class PilaHistorial:
"""
Estructura de Pila (LIFO - Last In, First Out) heredada del Reto 1.
Permite registrar todas las operaciones clave y ofrece la función 'deshacer'.
"""
def __init__(self):
self.tope = None # Puntero al elemento ubicado en la cima de la pila
self._tamanio = 0 # Contador interno de elementos almacenados
def push(self, accion, descripcion):
"""Inserta una nueva acción registrada en la cima de la pila."""
# Se crea un nodo guardando el tipo de acción y su descripción detallada
nuevo_nodo = Nodo(nombre=accion, id_estudiante=descripcion, siguiente=self.tope)
self.tope = nuevo_nodo
self._tamanio += 1
def pop(self):
"""Remueve y retorna el elemento en la cima (permite deshacer la última acción)."""
if self.is_empty():
return None
nodo_removido = self.tope
self.tope = self.tope.siguiente # El tope pasa a ser el nodo anterior
self._tamanio -= 1
return {"accion": nodo_removido.nombre, "descripcion": nodo_removido.id_estudiante}
def is_empty(self):
"""Verifica si la pila se encuentra vacía."""
return self.tope is None
def size(self):
"""Retorna el número total de acciones registradas."""
return self._tamanio
class ColaSimple:
"""
Estructura de Cola Lineal (FIFO - First In, First Out).
Gestiona la llegada general de turnos de los estudiantes por orden de llegada.
"""
def __init__(self):
self.frente = None # Puntero al primer elemento que va a salir
self.fin = None # Puntero al último elemento que acaba de ingresar
self._tamanio = 0 # Contador de elementos en la cola
def enqueue(self, nombre, id_estudiante):
"""Agrega un nuevo estudiante al final de la cola simple."""
nuevo = Nodo(nombre, id_estudiante)
if self.is_empty():
self.frente = self.fin = nuevo
else:
self.fin.siguiente = nuevo
self.fin = nuevo
self._tamanio += 1
print(f"↳ ENQUEUE [{nombre}, id={id_estudiante}] en ColaSimple")
def dequeue(self):
"""Extrae y retorna el estudiante que está al frente de la cola."""
if self.is_empty():
return None
removido = self.frente
self.frente = self.frente.siguiente
if self.frente is None:
self.fin = None # Si la cola queda vacía, el fin también se limpia
self._tamanio -= 1
return removido
def front(self):
"""Devuelve el elemento del frente sin eliminarlo."""
return self.frente if not self.is_empty() else None
def is_empty(self):
"""Comprueba si la cola simple está vacía."""
return self.frente is None
def size(self):
"""Retorna el tamaño actual de la cola."""
return self._tamanio
def mostrar(self):
"""Imprime por consola todos los elementos actuales de la cola."""
if self.is_empty():
print(" (ColaSimple vacía)")
return
actual = self.frente
while actual:
print(f" -> [{actual.nombre} | ID: {actual.id_estudiante}]")
actual = actual.siguiente
class ColaCircular:
"""
Estructura de Cola Circular.
Utilizada para manejar la lista de espera cuando el curso se satura,
permitiendo rotación cíclica de los estudiantes.
"""
def __init__(self, capacidad_max=100):
self.cabeza = None # Puntero al inicio de la cola circular
self.cola = None # Puntero al final del círculo
self._tamanio = 0
self.capacidad_max = capacidad_max
def enqueue(self, nombre, id_estudiante):
"""Inserta un estudiante cerrando el enlace circular hacia la cabeza."""
nuevo = Nodo(nombre, id_estudiante)
if self.is_empty():
self.cabeza = nuevo
self.cola = nuevo
self.cola.siguiente = self.cabeza # Apunta a sí mismo cerrando el ciclo
else:
self.cola.siguiente = nuevo
self.cola = nuevo
self.cola.siguiente = self.cabeza # Mantiene la circularidad
self._tamanio += 1
print(f"↳ ENQUEUE ESPERA CIRCULAR [{nombre}, id={id_estudiante}]")
def dequeue(self):
"""Extrae al estudiante que se encuentra al frente del ciclo."""
if self.is_empty():
return None
removido = self.cabeza
if self.cabeza == self.cola:
self.cabeza = None
self.cola = None
else:
self.cabeza = self.cabeza.siguiente
self.cola.siguiente = self.cabeza # Actualiza la referencia circular del último
self._tamanio -= 1
return removido
def front(self):
"""Retorna el elemento al frente sin extraerlo."""
return self.cabeza if not self.is_empty() else None
def is_empty(self):
"""Verifica si la cola circular está vacía."""
return self.cabeza is None
def size(self):
"""Retorna el número de elementos en espera circular."""
return self._tamanio
def mostrar(self):
"""Recorre la estructura circular de forma controlada para mostrar los elementos."""
if self.is_empty():
print(" (ColaCircular de espera vacía)")
return
actual = self.cabeza
for _ in range(self._tamanio):
print(f" -> [Espera: {actual.nombre} | ID: {actual.id_estudiante}]")
actual = actual.siguiente
class ColaPrioridad:
"""
Estructura de Cola de Prioridad.
Atiende casos especiales con ponderación (5 = prioridad más alta, 1 = más baja).
"""
def __init__(self):
self.frente = None
self._tamanio = 0
def enqueue(self, nombre, id_estudiante, prioridad):
"""Inserta de manera ordenada según la prioridad numérica (mayor prioridad va primero)."""
nuevo = Nodo(nombre, id_estudiante, prioridad=prioridad)
# Si está vacía o el nuevo elemento tiene mayor prioridad que el frente actual
if self.is_empty() or prioridad > self.frente.prioridad:
nuevo.siguiente = self.frente
self.frente = nuevo
else:
actual = self.frente
# Busca la posición adecuada según el nivel de prioridad
while actual.siguiente and actual.siguiente.prioridad >= prioridad:
actual = actual.siguiente
nuevo.siguiente = actual.siguiente
actual.siguiente = nuevo
self._tamanio += 1
print(f"↳ ENQUEUE PRIORIDAD [{nombre}, id={id_estudiante}, p={prioridad}]")
def dequeue(self):
"""Extrae el elemento con la máxima prioridad (ubicado en el frente)."""
if self.is_empty():
return None
removido = self.frente
self.frente = self.frente.siguiente
self._tamanio -= 1
print(f"↳ DEQUEUE [{removido.nombre}, id={removido.id_estudiante}] desde ColaPrioridad (p={removido.prioridad})")
return removido
def front(self):
return self.frente if not self.is_empty() else None
def is_empty(self):
return self.frente is None
def size(self):
return self._tamanio
def mostrar(self):
"""Muestra los casos especiales ordenados por su nivel de prioridad."""
if self.is_empty():
print(" (ColaPrioridad vacía)")
return
actual = self.frente
while actual:
print(f" -> [Prioridad {actual.prioridad}] {actual.nombre} (ID: {actual.id_estudiante})")
actual = actual.siguiente
class SistemaInscripcionAcademico:
"""
Gestor principal del sistema universitario.
Coordina el curso, las diferentes colas, la lista de inscritos y el historial de acciones.
"""
def __init__(self):
self.nombre_curso = ""
self.cupos_totales = 0
self.inscritos = [] # Arreglo para visualizar los estudiantes matriculados exitosamente
# Instanciación de las estructuras de datos requeridas
self.cola_simple = ColaSimple()
self.cola_circular = ColaCircular()
self.cola_prioridad = ColaPrioridad()
self.historial = PilaHistorial()
def configurar_curso(self):
"""Configura el nombre del curso y la cantidad máxima de cupos disponibles."""
print("\n--- 1. CONFIGURAR CURSO ---")
self.nombre_curso = input("Ingrese el nombre del curso: ")
self.cupos_totales = int(input("Ingrese la cantidad máxima de CUPOS: "))
print(f"✅ Curso '{self.nombre_curso}' configurado con {self.cupos_totales} cupos.")
def llegada_estudiante(self):
"""Registra la llegada de un estudiante y lo deriva a la cola correspondiente."""
print("\n--- 2. LLEGADA DE ESTUDIANTE ---")
id_est = input("Ingrese ID del estudiante: ")
nombre = input("Ingrese Nombre del estudiante: ")
es_especial = input("¿Tiene caso especial de prioridad (1-5)? (Deje en blanco si no): ").strip()
if es_especial:
prioridad = int(es_especial)
self.cola_prioridad.enqueue(nombre, id_est, prioridad)
self.historial.push("LLEGADA_PRIORIDAD", f"Estudiante {nombre} con prioridad {prioridad}")
else:
self.cola_simple.enqueue(nombre, id_est)
self.historial.push("LLEGADA_SIMPLE", f"Estudiante {nombre} en cola general")
def procesar_turnos(self):
"""Procesa N turnos para inscribir estudiantes evaluando cupos y prioridades."""
print(f"\n--- 3. PROCESAR TURNOS (Cupos actuales: {len(self.inscritos)}/{self.cupos_totales}) ---")
n = int(input("¿Cuántos turnos desea procesar?: "))
for _ in range(n):
# Si el curso se llena, los estudiantes de la cola general pasan a espera circular
if len(self.inscritos) >= self.cupos_totales:
print("⚠️ ¡Curso saturado! No hay más cupos directos. Los siguientes van a espera circular.")
if not self.cola_simple.is_empty():
est = self.cola_simple.dequeue()
self.cola_circular.enqueue(est.nombre, est.id_estudiante)
self.historial.push("ESPERA", f"{est.nombre} enviado a cola circular por saturación")
break
# Se atiende primero la cola de prioridad si contiene elementos
if not self.cola_prioridad.is_empty():
est = self.cola_prioridad.dequeue()
self.inscritos.append({"nombre": est.nombre, "id": est.id_estudiante})
print(f"✅ INSCRITO (Especial): {est.nombre} (id={est.id_estudiante})")
self.historial.push("INSCRIBIR_PRIORIDAD", f"Inscrito caso especial {est.nombre}")
elif not self.cola_simple.is_empty():
est = self.cola_simple.dequeue()
self.inscritos.append({"nombre": est.nombre, "id": est.id_estudiante})
print(f"✅ INSCRITO: {est.nombre} (id={est.id_estudiante})")
self.historial.push("INSCRIBIR", f"Inscrito general {est.nombre}")
else:
print("⚠️ No hay más estudiantes en las colas de recepción.")
break
def mostrar_estado(self):
"""Muestra de forma visual el estado del curso, inscritos y todas las colas."""
print(f"\n================ ESTADO DEL CURSO: {self.nombre_curso} ================")
print(f"Cupos Ocupados: {len(self.inscritos)} / {self.cupos_totales}")
print("\n--- LISTA DE INSCRITOS ---")
if not self.inscritos:
print(" (Ningún inscrito aún)")
else:
for idx, ins in enumerate(self.inscritos, 1):
print(f" {idx}. {ins['nombre']} (ID: {ins['id']})")
print("\n--- COLA SIMPLE (General) ---")
self.cola_simple.mostrar()
print("\n--- COLA DE PRIORIDAD (Casos Especiales) ---")
self.cola_prioridad.mostrar()
print("\n--- COLA CIRCULAR (Lista de Espera) ---")
self.cola_circular.mostrar()
print("================================================================")
def registrar_retiro(self):
"""Libera el cupo de un estudiante retirado y reasigna automáticamente el espacio."""
print("\n--- 5. REGISTRAR RETIRO DE UN INSCRITO ---")
if not self.inscritos:
print("❌ No hay estudiantes inscritos para retirar.")
return
print("Inscritos actuales:")
for idx, ins in enumerate(self.inscritos, 1):
print(f" {idx}. {ins['nombre']} (ID: {ins['id']})")
op = int(input("Seleccione el número del estudiante que se retira: ")) - 1
if 0 <= op < len(self.inscritos):
retirado = self.inscritos.pop(op)
print(f"⚠️ RETIRADO: {retirado['nombre']} ha liberado un cupo.")
self.historial.push("RETIRAR", f"Retiro de {retirado['nombre']}")
# Reasignación de cupo liberado: prioridad primero, luego circular
if not self.cola_prioridad.is_empty():
nuevo_est = self.cola_prioridad.dequeue()
self.inscritos.append({"nombre": nuevo_est.nombre, "id": nuevo_est.id_estudiante})
print(f"✅ REASIGNADO cupo a {nuevo_est.nombre} desde ColaPrioridad")
self.historial.push("REASIGNAR", f"Cupo reasignado a {nuevo_est.nombre} desde prioridad")
elif not self.cola_circular.is_empty():
nuevo_est = self.cola_circular.dequeue()
self.inscritos.append({"nombre": nuevo_est.nombre, "id": nuevo_est.id_estudiante})
print(f"❓ REASIGNADO cupo a {nuevo_est.nombre} desde ColaCircular")
self.historial.push("REASIGNAR", f"Cupo reasignado a {nuevo_est.nombre} desde circular")
else:
print("ℹ️ No hay estudiantes en espera para reasignar el cupo.")
else:
print("❌ Opción inválida.")
def atender_prioridad(self):
"""Atiende directamente un caso especial desde la cola de prioridad."""
print("\n--- 6. ATENDER CASO ESPECIAL DIRECTO ---")
if self.cola_prioridad.is_empty():
print("ℹ️ No hay casos especiales en la cola de prioridad.")
return
est = self.cola_prioridad.dequeue()
self.inscritos.append({"nombre": est.nombre, "id": est.id_estudiante})
print(f"✅ ATENDIDO Y INSCRITO (Prioridad {est.prioridad}): {est.nombre}")
self.historial.push("ATENDER_PRIORIDAD", f"Atención prioritaria a {est.nombre}")
def deshacer_accion(self):
"""Invoca la función pop de la pila historial para revertir el último cambio."""
print("\n--- 7. DESHACER ÚLTIMA ACCIÓN (Pila Historial) ---")
accion_deshecha = self.historial.pop()
if not accion_deshecha:
print("❌ No hay acciones registradas para deshacer.")
return
print(f"↩️ DESHACER: Se revierte la acción '{accion_deshecha['accion']}' -> {accion_deshecha['descripcion']}")
def main():
"""Función principal que despliega el menú interactivo en consola."""
sistema = SistemaInscripcionAcademico()
while True:
print("\n=== MENÚ SISTEMA DE INSCRIPCIONES PUCE ===")
print("1. Configurar curso (nombre, CUPOS)")
print("2. Llegada estudiante (ID, Nombre, ¿prioridad? 1-5)")
print("3. Procesar siguientes N turnos")
print("4. Mostrar inscritos / mostrar todas las colas")
print("5. Registrar retiro de un inscrito (libera cupo y reasigna)")
print("6. Atender prioridad")
print("7. Deshacer última acción (usando PilaHistorial)")
print("8. Salir")
opcion = input("Seleccione una opción: ").strip()
if opcion == "1":
sistema.configurar_curso()
elif opcion == "2":
sistema.llegada_estudiante()
elif opcion == "3":
sistema.procesar_turnos()
elif opcion == "4":
sistema.mostrar_estado()
elif opcion == "5":
sistema.registrar_retiro()
elif opcion == "6":
sistema.atender_prioridad()
elif opcion == "7":
sistema.deshacer_accion()
elif opcion == "8":
print("Saliendo del sistema de inscripciones. ¡Hasta luego!")
break
else:
print("❌ Opción no válida. Intente de nuevo.")
if __name__ == "__main__":
main()
17,173 chars · codepastes.com