Sesión 4
Decisiones “serias”: prioridad, cobertura y trazabilidad
Si/Si-no anidado bien diseñado
AND/OR con paréntesis (sin ambigüedad)
Tabla de decisión → código
Pruebas: ramas + bordes
Navegación: ← → · Pantalla completa: F
Objetivos medibles
- Convertir un conjunto de reglas en una tabla de decisión completa (sin huecos, sin solapes).
- Traducir tabla de decisión a if/else o switch con prioridad explícita.
- Diseñar un set mínimo de pruebas con cobertura de ramas y casos borde.
- Implementar el ejercicio en C# respetando tipos (decimal para dinero) y validando rangos.
Meta universitaria: que puedas defender tu solución (reglas, pruebas y código coherente).
Problema típico: reglas que “se pisan”
Lo que pasa en la vida real
- Hay múltiples descuentos, recargos, excepciones y topes.
- Dos reglas pueden aplicar al mismo tiempo.
- Si no defines prioridad, el resultado depende del orden del programador.
La solución técnica
- Escribes reglas como condiciones + acciones.
- Defines prioridad (qué gana cuando hay conflicto).
- Usas tabla de decisión + pruebas por ramas.
Hoy entrenamos un método repetible: reglas → tabla → código → pruebas.
Ejercicio guía (enunciado)
Sistema de cobro de parqueadero (por día)
- Entrada: tipoVehiculo (1=Moto, 2=Carro), horas (0..24), esFestivo (S/N).
- Tarifa base por hora: Moto 2000; Carro 3500.
- Regla A: si horas ≥ 8, se cobra “tope diario”: Moto 12000; Carro 20000.
- Regla B: si esFestivo = S, recargo del 10% sobre lo cobrado (incluye tope).
- Salida: total a pagar.
Este ejercicio fuerza: rangos, prioridad (tope vs por hora) y condición compuesta.
Modelo mental (diagrama en español)
Diagrama de flujo conceptual: separa decisiones y evita mezclar reglas en una sola condición gigante.
Tabla de decisión (mínima y completa)
Condiciones:
- C1: horas ≥ 8
- C2: festivo = S
Caso | C1 (tope) | C2 (festivo) | Acción base | Acción final
-----|-----------|--------------|--------------------------------|------------------------------
1 | F | F | total = horas * tarifa | total = total
2 | F | V | total = horas * tarifa | total = total * 1.10
3 | V | F | total = tope(tipoVehiculo) | total = total
4 | V | V | total = tope(tipoVehiculo) | total = total * 1.10
Esta tabla obliga a cubrir 4 escenarios; si te falta uno, tu código queda incompleto.
Pseudocódigo (fiel a la tabla)
Leer tipoVehiculo
Leer horas
Leer esFestivo
Si horas >= 8 Entonces
base = topeSegunTipo(tipoVehiculo)
Si no
base = horas * tarifaSegunTipo(tipoVehiculo)
FinSi
Si esFestivo == "S" Entonces
total = base * 1.10
Si no
total = base
FinSi
Escribir total
Nota: “tarifaSegunTipo” y “topeSegunTipo” pueden ser un switch en C#.
C# (estructura + tipos correctos)
Por qué decimal
- El problema es dinero (tarifas, tope, recargo).
- decimal reduce errores de aproximación en cálculos financieros.
- Usa sufijo m en literales: 3500m, 1.10m.
Precondiciones (rango)
- horas debe estar entre 0 y 24.
- tipoVehiculo debe ser 1 o 2.
- festivo debe ser S o N.
Universitario: o validas o declaras la precondición (y la cumples en pruebas).
Implementación C# (paso 1: entrada robusta)
using System;
class Program
{
static void Main(string[] args)
{
Console.Write("Tipo (1=Moto, 2=Carro): ");
string sTipo = Console.ReadLine() ?? "";
if (!int.TryParse(sTipo, out int tipo) || (tipo != 1 && tipo != 2))
{
Console.WriteLine("Tipo inválido.");
return;
}
Console.Write("Horas (0..24): ");
string sHoras = Console.ReadLine() ?? "";
if (!int.TryParse(sHoras, out int horas) || horas < 0 || horas > 24)
{
Console.WriteLine("Horas inválidas.");
return;
}
Console.Write("¿Es festivo? (S/N): ");
string festivo = (Console.ReadLine() ?? "").Trim().ToUpperInvariant();
if (festivo != "S" && festivo != "N")
{
Console.WriteLine("Valor de festivo inválido.");
return;
}
// Paso 2: calcular...
}
}
Esto evita que el programa “explote” por un dato mal digitado.
Implementación C# (paso 2: tarifas con switch)
decimal tarifaHora = tipo switch
{
1 => 2000m, // Moto
2 => 3500m, // Carro
_ => 0m
};
decimal topeDiario = tipo switch
{
1 => 12000m,
2 => 20000m,
_ => 0m
};
switch expresa “selección por categoría” de forma clara y auditable.
Implementación C# (paso 3: decisiones según tabla)
decimal baseCobro;
if (horas >= 8)
{
baseCobro = topeDiario;
}
else
{
baseCobro = horas * tarifaHora;
}
decimal total = baseCobro;
if (festivo == "S")
{
total = total * 1.10m;
}
Console.WriteLine($"Total a pagar: {total}");
La estructura coincide con la tabla de decisión: primero base (tope o por hora), luego recargo.
Pruebas (cobertura de ramas + bordes)
Casos mínimos recomendados
- Caso normal sin tope, no festivo: tipo=1, horas=2, N.
- Caso normal sin tope, festivo: tipo=2, horas=3, S.
- Borde del tope: horas=8 (debe activar tope).
- Borde inferior: horas=0 (total debe ser 0 o recargo sobre 0).
Caso | tipo | horas | festivo | Esperado (explicación)
-----|------|-------|---------|------------------------
A | 1 | 2 | N | 2*2000 = 4000
B | 2 | 3 | S | (3*3500)=10500 → *1.10 = 11550
C | 2 | 8 | N | tope carro = 20000
D | 1 | 0 | S | 0 → *1.10 = 0
Cada caso justifica una rama (y C y D son bordes).
Error frecuente 1: condiciones mezcladas
Mal enfoque
if ((horas >= 8 && festivo=="S") || ...)
{
// muchas cosas aquí
}
Difícil de leer, difícil de probar, fácil de dañar con cambios.
Buen enfoque
baseCobro = (horas >= 8) ? tope : horas * tarifa;
if (festivo == "S") total = baseCobro * 1.10m;
Decisiones separadas = pruebas más simples.
Error frecuente 2: “huecos” en rangos
Si tu regla es “0–2”, “3–5”, “6+”, debes escribirla sin dejar números sin dueño.
Ejemplo correcto:
if (h <= 2) ...
else if (h <= 5) ...
else ...
Esto aplica a tus proyectos: la ambigüedad se vuelve bug.
Actividad (obligatoria, 30–35 min)
En parejas (o individual si es virtual):
- Escribe la tabla de decisión del parqueadero.
- Implementa en C# con TryParse + switch + if/else.
- Documenta 4 casos de prueba (incluye horas=8 y horas=0).
Entrega: archivo .cs + captura/tabla de pruebas (con explicación breve por caso).
Aplicación al proyecto (10–15 min)
- Identifica 2 reglas de tu proyecto que puedan “pisarse”.
- Define prioridad (quién gana) y escríbela en texto.
- Construye una mini tabla de decisión (2 condiciones → 4 casos).
Si tu proyecto está bien modelado hoy, mañana programar es “mecánico”.
Reto (opcional, sin nota)
Auditoría de validación: agrega mensajes de error específicos.
- Si horas está fuera de 0..24, explica el rango permitido.
- Si tipo no es 1 o 2, muestra opciones válidas.
- Si festivo no es S/N, normaliza y vuelve a pedir (solo si te alcanza el tiempo).
Esto sube calidad, pero no cambia la nota (reto opcional).
Ticket de salida (5 min)
- Escribe 1 caso borde y explica qué rama valida.
- ¿Qué parte resolviste con switch y por qué?
- ¿Qué prioridad de reglas existe en el ejercicio?
Próxima sesión: condicionales más complejos + más énfasis en pruebas (sin perder C#).