Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions 2001_carol_alfonso_v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
class Contact():
def __init__(self, name: str, phone: int, email: str):
self.name = name
self.phone = phone
self.email = email

def __str__(self):
return f"{self.name}, {self.phone}, {self.email}"


class ContactBook():
def __init__(self):
self.contacts = []

def ADD(self, contact):
# No permitir emails duplicados
for c in self.contacts:
if c.email.lower() == contact.email.lower():
return "ERROR:DUP"
self.contacts.append(contact)
return f"Contacto {contact.name} agregado."

def DEL(self, name: str):
for contact in self.contacts:
if contact.name.lower() == name.lower():
self.contacts.remove(contact)
return f"Contacto {name} eliminado."
return "Contact not found"

def FIND(self, text: str):
results = []
for contact in self.contacts:
if text.lower() in contact.name.lower() or text.lower() in contact.email.lower():
results.append(str(contact))
if results:
return "\n".join(results)
return "Contact not found"

def LIST(self):
sorted_contacts = sorted(self.contacts, key=lambda c: c.name)
if not sorted_contacts:
return "No hay contactos."
return "\n".join(map(str, sorted_contacts))


# ---- Casos de prueba ----
Juan = Contact("Juan", 1151232528, "juan@gmail.com")
Ana = Contact("Ana", 1065498378, "ana@gmail.com")
Carlos = Contact("Carlos", 1156781234, "carlos@gmail.com")

book = ContactBook()
print(book.ADD(Juan))
print(book.ADD(Ana))
print(book.ADD(Carlos))
print(book.ADD(Contact("Pedro", 111222333, "juan@gmail.com"))) # Email duplicado

print("\n--- LISTA INICIAL ---")
print(book.LIST())

print("\n--- ELIMINANDO ---")
print(book.DEL("Ana"))
print(book.DEL("Maria"))

print("\n--- LISTA DESPUÉS ---")
print(book.LIST())

print("\n--- BUSQUEDA ---")
print(book.FIND("Carlos"))
print(book.FIND("gmail"))
print(book.FIND("Andrés"))
91 changes: 91 additions & 0 deletions 2002_carol_alfonso_v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from decimal import Decimal, ROUND_HALF_UP

class Course():
def __init__(self, name: str, credits: int, grade: Decimal):
self.name = name
self.credits = int(credits)
self.grade = Decimal(str(grade))

def __str__(self):
return f"{self.name}, {self.credits}, {self.grade:.2f}"


class Semester():
def __init__(self):
self.courses = {} # usamos diccionario para evitar duplicados

def ADD(self, name: str, credits: int, grade: Decimal):
if name in self.courses:
print("ERROR:DUP")
else:
self.courses[name] = Course(name, credits, grade)

def LIST(self):
sorted_courses = sorted(self.courses.values(), key=lambda c: (-c.credits, c.name))
for course in sorted_courses:
print(course)

def AVG(self):
total_credits = sum(c.credits for c in self.courses.values())
if total_credits == 0:
avg = Decimal("0.00")
else:
total = sum(c.credits * c.grade for c in self.courses.values())
avg = (total / total_credits).quantize(Decimal("0.00"), rounding=ROUND_HALF_UP)
print(f"prom={avg}")

def IMPORT(self, lines):
valid, invalid = 0, 0
for line in lines:
parts = line.strip().split(",")
if len(parts) != 3:
invalid += 1
continue
name, credits, grade = parts
try:
credits = int(credits)
grade = Decimal(grade)
except:
invalid += 1
continue
if name in self.courses:
invalid += 1
else:
self.courses[name] = Course(name, credits, grade)
valid += 1
print(f"Import: {valid} valid, {invalid} invalid")


# ---- Casos de prueba sencillos ----
sem = Semester()

# 1. Agregar cursos
sem.ADD("Matematicas", 4, Decimal("4.5"))
sem.ADD("Ingles", 2, Decimal("3.7"))
sem.ADD("Matematicas", 3, Decimal("5.0")) # duplicado → ERROR:DUP

# 2. Listar cursos
print("\nLIST:")
sem.LIST()

# 3. Promedio actual
print("\nAVG:")
sem.AVG()

# 4. Importar desde lista CSV
lines = [
"Fisica,3,5.0",
"Matematicas,2,4.0", # duplicado
"Quimica,4,4.2",
"Errorcito,xx,3.5" # inválido
]
sem.IMPORT(lines)

# 5. Listar después de importar
print("\nLIST después de import:")
sem.LIST()

# 6. Nuevo promedio
print("\nAVG nuevo:")
sem.AVG()

70 changes: 70 additions & 0 deletions 2003_carol_alfonso_v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
class StackEmptyError(Exception):
pass


class MinStack:
"""
Implementación de una pila con:
- push(x): O(1)
- pop(): O(1)
- peek(): O(1)
- size(): O(1)
- min(): O(1) → devuelve el mínimo actual de la pila
"""
def __init__(self):
self.stack = [] # pila normal
self.min_stack = [] # pila auxiliar para mínimos

def push(self, x):
self.stack.append(x)
# Si min_stack está vacío o x es menor/igual al actual mínimo
if not self.min_stack or x <= self.min_stack[-1]:
self.min_stack.append(x)

def pop(self):
if not self.stack:
raise StackEmptyError("ERROR:EMPTY")
val = self.stack.pop()
if val == self.min_stack[-1]:
self.min_stack.pop()
return val

def peek(self):
if not self.stack:
raise StackEmptyError("ERROR:EMPTY")
return self.stack[-1]

def size(self):
return len(self.stack)

def get_min(self):
if not self.min_stack:
raise StackEmptyError("ERROR:EMPTY")
return self.min_stack[-1]


# ---- Casos de prueba ----
s = MinStack()

# PUSH
s.push(5)
s.push(3)
s.push(7)
s.push(2)

print("SIZE:", s.size()) # 4
print("PEEK:", s.peek()) # 2
print("MIN:", s.get_min()) # 2

# POP
print("POP:", s.pop()) # 2
print("MIN después de pop:", s.get_min()) # 3

print("POP:", s.pop()) # 7
print("MIN:", s.get_min()) # 3

print("POP:", s.pop()) # 3
print("MIN:", s.get_min()) # 5

print("POP:", s.pop()) # 5
# Intentar MIN o POP aquí lanzaría ERROR:EMPTY
71 changes: 71 additions & 0 deletions 2004_carol_alfonso_v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from collections import deque

class QueueEmptyError(Exception):
pass


class Queue:
def __init__(self):
self.q = deque() # cola principal
self.total_wait = 0 # suma de tiempos de espera
self.served = 0 # elementos atendidos
self.K = None # límite de operaciones
self.ops = deque() # timestamps de operaciones (para control de rate limit)

def setK(self, k):
self.K = k

def _check_limit(self, timestamp):
if self.K is None:
return
# limpiar timestamps más viejos de 60s
while self.ops and timestamp - self.ops[0] >= 60:
self.ops.popleft()
if len(self.ops) >= self.K:
print("ERROR:RATE_LIMIT")
return False
self.ops.append(timestamp)
return True

def ENQUEUE(self, id, timestamp):
if not self._check_limit(timestamp):
return
self.q.append((id, timestamp))

def DEQUEUE(self, timestamp):
if not self._check_limit(timestamp):
return
if not self.q:
raise QueueEmptyError("ERROR:EMPTY")
id, enq_time = self.q.popleft()
wait = timestamp - enq_time
self.total_wait += wait
self.served += 1
return id

def STATS(self):
L = len(self.q)
avg = (self.total_wait // self.served) if self.served > 0 else 0
print(f"len={L} wait_avg={avg}")


# ---- Casos de prueba ----
q = Queue()

# Encolamos
q.ENQUEUE("A", 0)
q.ENQUEUE("B", 10)
q.ENQUEUE("C", 15)

# Sacamos
print("DEQUEUE:", q.DEQUEUE(20)) # A, esperó 20s
print("DEQUEUE:", q.DEQUEUE(25)) # B, esperó 15s

# Stats
q.STATS() # len=1, wait_avg=(20+15)/2 = 17

# Rate limit
q.setK(2)
q.ENQUEUE("D", 30)
q.ENQUEUE("E", 35)
q.ENQUEUE("F", 40) # debería dar ERROR:RATE_LIMIT
74 changes: 74 additions & 0 deletions 2005_carol_alfonso_v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
class BiDictionary:
def __init__(self):
self.es_to_en = {}
self.en_to_es = {}

def ADD(self, es: str, en: str):
es = es.casefold()
en = en.casefold()
if es in self.es_to_en or en in self.en_to_es:
print("ERROR:DUP")
return
self.es_to_en[es] = en
self.en_to_es[en] = es

def FIND(self, word: str):
word = word.casefold()
if word in self.es_to_en:
print(f"es={word}, en={self.es_to_en[word]}")
elif word in self.en_to_es:
print(f"en={word}, es={self.en_to_es[word]}")
else:
print("NOTFOUND")

def LIST(self):
for es in sorted(self.es_to_en.keys()):
print(f"{es} -> {self.es_to_en[es]}")

def BULKADD(self, pairs):
# Validar primero
for es, en in pairs:
es, en = es.casefold(), en.casefold()
if es in self.es_to_en or en in self.en_to_es:
print("ERROR:BULK")
return
# Si no hubo conflicto, agregar todos
for es, en in pairs:
es, en = es.casefold(), en.casefold()
self.es_to_en[es] = en
self.en_to_es[en] = es

def EXPORT(self, filename="diccionario.txt"):
try:
with open(filename, "w", encoding="utf-8") as f:
for es in sorted(self.es_to_en.keys()):
f.write(f"{es} -> {self.es_to_en[es]}\n")
print(f"Diccionario exportado a {filename}")
except Exception as e:
print("ERROR:EXPORT", e)


# ---- Casos de prueba ----
bd = BiDictionary()

bd.ADD("Casa", "House")
bd.ADD("Perro", "Dog")
bd.ADD("Gato", "Cat")

print("\nLIST:")
bd.LIST()

print("\nFIND:")
bd.FIND("casa")
bd.FIND("house")
bd.FIND("bird")

print("\nBULKADD:")
bd.BULKADD([("Sol", "Sun"), ("Luna", "Moon")])
bd.BULKADD([("Agua", "Water"), ("Perro", "Doggy")]) # ERROR:BULK

print("\nLIST después de BULKADD:")
bd.LIST()

print("\nEXPORT:")
bd.EXPORT("mi_diccionario.txt")
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<h1>CodExpress — Nivel Intermedio (Estructuras + POO)</h1>
<h1>CAROL ALFONSO — Entrega Nivel Intermedio PRO .</h1>
CodExpress — Nivel Intermedio (Estructuras + POO)
<p><strong>Tiempo:</strong> 3 horas · <strong>Meta:</strong> completar <u>7 u 8 mini-retos</u> y, si te alcanza, una <u>app integrada (código 2900)</u> que reutilice tus propias <strong>clases y funciones</strong>. Lenguajes: <strong>Python</strong>, <strong>Java</strong> o <strong>C++</strong> (usando POO).</p>

<h2>Flujo de trabajo (fork &amp; PR)</h2>
Expand Down