Lógica de Programación — Sesión 4
Unidad 1 · Condicionales anidados · Condiciones compuestas · Tablas de decisión · Pruebas por ramas (C#)
1/1

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)

Entradas tipo, horas, festivo Decisión 1: ¿aplica tope diario? horas ≥ 8 → usar tope, si no → horas * tarifa Decisión 2: ¿hay recargo? festivo = S → total = base * 1.10 Salida total a pagar (decimal), con pruebas por casos borde
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#).