Lección 22: Segunda aplicación de conocimientos.
Encuesta
- Votantes
- 3
Resultados de la encuesta
¿Te ha parecido adecuada la propuesta?
-
NO: No logro entender qué es lo que se pide.
0 Votos -
NO: Creo que excede el nivel del curso.
0 Votos -
MAS O MENOS: Es un poco excesiva pero aplica lo que corresponde.
0 Votos -
SI: Es difícil pero aplica todos los temas y eso ayuda a arraigarlos.
1 Votos -
SI: Me parece una propuesta excelente.
2 Votos
Debes estar registrado para poder votar
Puedes seleccionar más de una opción-
Les traigo un nuevo reto como extensión al anterior para reafirmar lo dado en la última lección más lo dado en todas las anteriores. Aprovecho con esto a comentarles que no está habiendo la participación esperada. Eso es natural ya que rara vez alguien asume responsabilidades como esta, es decir, es raro que alguien se ponga a hacer proyectos y ejercicios que insumen tiempo y energía si estos no son obligatorios. Sin embargo queridos lectores es la única manera de que realmente aprendan con esto y sirva para algo, sino no será más que una mera lectura que queda como un leve registro en la memoria dejando una pequeña intuición de lo que es programar. Quiero destacar que sí han habido quienes han hecho ejercicios y quienes han consultado y preguntado; a tod@s ell@s GRACIAS.
Vallamos entonces, a lo que nos compete ahora.
BASE PRODUCTOS Parte 2
Añadiremos dos funcionalidades más a nuestro programa: Captura de Errores y una Lista Variable de Elementos a almacenar. Para esto tendrán que modificar bastante su código, lo cual puede ser bastante complicado y les mostrará la realidad de trabajar con un código ya hecho. Si no utilizaron buenos comentarios estarán en problemas ya que tendrán que rememorar lo que hace su programa e incluso con ellos tendrán que acomodar su cabeza nuevamente a una lógica puntual. Cada programa es un mundo, tiene sus problemas y complicaciones, su estructura; y para cada uno deben adecuar su mente. Imaginen lo que es trabajar con el código de otra persona cuya cabeza funciona de una forma totalmente diferente a la nuestra, cuya lógica nos hace rompernos la cabeza en el intento por comprendela. Pues ese es el mundo de la programación, de la creación de software, y créanme, lo que yo les he mostrado en este curso no es absolutamente nada. En próximas entregas iremos sumergiéndonos más en un mundo donde la magia es posible, donde la imaginación es prácticamente el único límite, donde el ingenio es la mejor herramienta, donde la paciencia es la mejor virtud. Sin embargo nada será sencillo, necesitarán sentarse a pensar horas cómo lograr tal o cual cosa, analizar una y otra vez dónde cornos está el error que hace a nuestro programa tirarnos cualquier cosa en un caso concreto ¡¡¡¡PERO SI EN TODOS LOS DEMÁS CASOS FUNCIONA!!!
Muchas veces pensarán que no hay solución, que necesitan alguna otra herramienta, sin embargo este manual ha apuntado a que ustedes puedan lograr grandes soluciones con herramientas básicas planteandoles problemas que a priori parecen imposibles de realizar. PASCAL tiene muchas cosas más que nosotros ni hemos nombrado y que en ciertos aspectos solucionarían muchos problemas de forma casi automática. Lenguajes superiores lograrán con dos palabras resolver lo que a ustedes les ha llevado diez o más líneas de código y horas de rompedero de cabeza, pero así se aprende y así, con esos lenguajes superiores, lograrán resolver cosas que tal vez otras personas no podrían. Bien, vayamos a nuestra taréa.
Nuestro programa deberá tiranos el mensaje ERROR: Dato inesperado, ingrese un dato válido para cualquier caso en el que ingresemos algo inadecuado en cualquier entrada. Siempre que se muestre el mensaje de error el programa deberá quedar a la espera de un nuevo ingreso para el mismo dato. Detallaré aquí los posibles errores en las entradas y daré ejemplos de ejecuciones:
Nombre: El nombre de un producto debe estar formado únicamente por números y/o letras mayúsculas y/o minúsculas. Cualquier otro carácter se tomará como inválido.
ID: El ID debe ser un número entero positivo, o sea, un natural. Si el dato ingresado no se corresponde con un número entero positivo o directamente no es un número lo consideraremos como error. Para el ID también deberemos corroborar que no se repita en todos los ingresos anteriores, ya que eso también sería un error.
Stock: Debe ser un número entero positivo. Tiene las mismas restricciones que el ID con la excepción de que Stock sí puede repetirse.
Precio: Este dato debe ser un número real positivo, en caso de ser negativo o no ser un número lo consideraremos como error. Este dato les traerá problemas de captura ya que leer la entrada como carácter y luego pasarla a real no es tan sencillo como pasarla a entero.
Categoría: Para este dato solo debemos corroborar que lo ingresado se corresponda con una de las opciones mostradas en pantalla, de lo contrario será un error. Esto se aplicará a todas las pantallas de nuestro programa en las que el usuario deba elegir una de varias opciones.
Para controlar el nombre ingresado deben implementar una función como la siguiente:donde CadenaChar será un tipo global declarado de la siguiente manera:Código:FUNCTION NombreCorrecto(nombre: CadenaChar): Boolean;
La función NombreCorrecto devolverá TRUE si la cadena ingresada cumple las condiciones de más arriba, FALSE en caso contrario.Código:CONST MaxLargoNombre: 20; TYPE CadenaChar= RECORD nombre: Array[1..MaxLargoNombre] of Char; tope: 0..MaxLargoNombre; END;
Para corroborar que la entrada corresponde a un entero positivo deben utilizar la siguiente función:la cual devolverá TRUE si la entrada es un entero positivo o 0. Esto lo usarán para ID y para Stock, y tal vez para algún otro caso más donde ustedes crean que sea pertinente. No admitimos el signo de + en la entrada.Código:FUNCTION EsEnteroPositivo(numero: CadenaChar): Boolean
Del mismo modo comprobaremos si la entrada se corresponde a un real positivo:la cual obviamente devolverá TRUE si la entrada es un real positivo o FALSE en caso contrario. Recuerden que tomamos como real positivo que contenga números y/o una sola coma. No admitimos el signo de + en la entrada. De este modo, entradas correctas serían las siguientes:Código:FUNCITION EsRealPositivo(numero: CadenaChar): Boolean;
1 Recordar que los números enteros son reales.
10
10,0
,12 equivale a 0,12 por lo cual es correcto.
1325,123
Entradas incorrectas serían:
+1
+1,23
-1,23
-0
+0
12,12,3
,0,1
12,-1
Para obtener el valor entero de una entrada correcta deben implementar la función siguiente:la cual devolverá dicho valor. Esta función recibe una cadena de caracteres correcta, por lo cual la verificación de error debe hacerse antes de su llamada.Código:FUNCTION StringToInt(numero: CadenaChar): Integer;
Del mismo modo implementarán una función para obtener el valor real de una cadena de caracteres correctos:Esta función, como dije antes, les traerá problemas porque no es lo mismo pasar una cadena de caracteres a un valor entero que a un valor real. Les explicaré la lógica que se me ocurrió a mí para su implementación:Código:FUNCTION RealToInt(numero: CadenaChar): Real;
Un número real está constituido de dos partes, la que está antes de la coma y la que está después, o sea, la parte entera y la parte real. Por ejemplo:
1 : Parte entera 1, parte real 0.
1,000: Parte entera 1, parte real 0.
01,0: Parte entera 1, parte real 0.
12,52: Parte entera 12, parte real 52.
El truco está entonces en obtener estas dos partes por separado como números enteros, de este modo si tenemos el 12,52 tendremos por un lado el 12 y por otro lado el 52, ambas partes como enteros, lo cual es fácil llevar a valor integer con la función StringToInt. Una vez tenemos el entero 12 por un lado y el entero 52 por otro debemos establecer el 52 como el real 0,52 y sumárselo al 12 con lo cual obtenemos 12,52.
12 + 0,52= 12,52.
Para obtener el 0,52 a partir de 52 basta con dividirlo entre 100. De este modo, si nuestra parte real tiene un solo dígito debemos dividirla entre 10, si tiene dos dígitos debemos dividirla entre 100, si tiene tres entre 1000 y así sucesivamente. Por ejemplo:
123,146= 123 + 146/1000
1,2365= 1 + 2365/10000
01,0= 1 + 0/10
Espero que con esto puedan implementar correctamente la función RealToInt.
Para comprobar que la opción de la categoría seleccionada es correcta, o para comprobar que la opción de un menú se corresponde con una de las disponibles deben implementar una función como la siguiente:la cual recibirá en sus parámetros el inicio del rango de opciones y el final del mismo, por ejemplo, viendo un menú como los que tiene nuestro programa:Código:FUNCTION OpcionCorrecta(inicioRango, finRango: char): Boolean;
inicioRango sería '1' y finRango sería '9'. Ahora bien, si son obseravdores deberían preguntarse qué pasa si el usuario ingresa el valor '8'. Pues sería una buena pregunta. Para estos casos debemos modificar nuestro menú de modo que todas las opciones sean consecutivas:Código:Modificar Productos: 1) Todos 2) Según ID 3) Según Nombre 4) Comestibles 5) Frutas y verduras 6) Higiene del hogar 7) Higiene personal 9) Volver al Menú Principal Opción >>
Estas modificaciones deberán hacerlas con todos los menús que haga falta. Asumiremos siempre que inicioRangoCódigo:Modificar Productos: 1) Todos 2) Según ID 3) Según Nombre 4) Comestibles 5) Frutas y verduras 6) Higiene del hogar 7) Higiene personal 8) Volver al Menú Principal Opción >>
.
IMPORTANTE: Para la opción Modificar Productos, en la versión anterior se utilizaban estas funciones:Ahora modificaremos las dos últimas para facilitarles a ustedes el trabajo:Código:FUNCTION BuscarPorID(listaProductos: Productos; ID: integer): integer; FUNCTION BuscarPorNombre(listaProductos: Productos; nombre: string): integer; FUNCTION BuscarPorCategoria(listaProductos: Productos; categoria: categorias): integer;
De este modo, el parámetro indice indicará desde qué posición del arreglo hay que comenzar a buscar. Esto les resuelve un enorme problema ya que aunque lo hayan hecho en la versión anterior, adaptarlo a un arreglo con tope es tan complicado que no vale la pena hacerlo aquí porque el enfoque es otro.Código:FUNCTION BuscarPorNombre(listaProductos: Productos; nombre: string; idice: integer): integer; FUNCTION BuscarPorCategoria(listaProductos: Productos; categoria: categorias; indice: integer): integer;
---------------------------------------------------------------------
Finalmente queda por ver el hecho de que la lista de elementos sea variable. Para esto implementaremos un arreglo con tope de la siguiente manera:Como ven, esta definición no cambia a la anterior en casi nada, simplemente implementa el tipo Productos como un arreglo con tope. De este modo nuestro Menú Principal será así:Código:Const N= 5; Type Categorias= (comestibles, frutas_verduras, higiene_h, higiene_p); TNaturales= 1..MAXINT; Elemento= Record Nombre: String; Stock: TNaturales; Precio: Real; Categoria: Categorias; ID: TNaturales; End; Productos= Record Array[1..N] of Elemento; tope: 0..N; End;donde cambia la primera opción, ya que ahora no ingresaremos un número de productos preestablecido, sino que podemos ingresar uno o más; y añadimos dos opciones nuevas. Veamos entonces la opción 1 de nuestro menú:Código:MENÚ PRINCIPAL: 1) Ingresar nuevo producto. 2) Ver lista de productos. 3) Modificar productos. 4) Vender. 5) Buscar. 6) Cantidad de productos ingresados. 7) Eliminar producto. 8) Salir. Opción:
Con eso volveríamos al Menú Principal. Si el usuario está en el menú principal y selecciona la opción 1, entonces volveremos al ingreso de productos tal como se vio arriba. Imaginen que ya se han ingresado 5 productos, entonces veríamos:Código:|-----------Producto 1-----------| ID >> 1 Nombre >> Azúcar Stock >> 10 Precio >> 50,5 Categorías: (1) Comestibles (2) Frutas y verduras (3) Higiene del hogar (4) Higiene personal Ingrese la opción deseada >> 1 Ingresar otro producto (1= SI/2= NO): j ERROR: Dato inesperado, ingrese un dato válido. Ingresar otro producto (1= SI/2= NO): 1 |-----------Producto 2-----------| ID >> 2 Nombre >> Harina Stock >> 10 Precio >> 42,5 Categorías: (1) Comestibles (2) Frutas y verduras (3) Higiene del hogar (4) Higiene personal Ingrese la opción deseada >> 0 ERROR: Dato inesperado, ingrese un dato válido. Ingrese la opción deseada >> 1 Ingresar otro producto (1= SI/2= NO): 2Siempre debemos saber cuantos productos tenemos en nuestra lista.Código:|-----------Producto 6-----------| ID >> 6 Nombre >> AzúcarImpalpable Stock >> 10 Precio >> 55,5 Categorías: (1) Comestibles (2) Frutas y verduras (3) Higiene del hogar (4) Higiene personal Ingrese la opción deseada >> 1 Ingresar otro producto (1= SI/2= NO): 2
Veamos ahora la opción 6: Cantidad de productos ingresados:
Simplemente se nos mostrará en pantalla la cantidad de productos en nuestra lista. Por ejemplo:Lo último por ver es la opción Eliminar producto: Se nos mostrará el siguiente menú:Código:Total de productos: 6 Presione ENTER para volver al Menú Principal...
Podemos eliminar un elemento determinado dando su ID, o podemos eliminar toda una categoría completa para agilizar las cosas. Veamos dos ejemplos:Código:ELIMINAR PRODUCTO: 1) Eliminar según ID 2) Eliminar Comestibles 3) Eliminar Frutas y Verduras 4) Eliminar Higiene del Hogar 5) Eliminar Higiene Personal 6) Volver al Menú Principal Opción:
Supongamos que seleccionamos la opción 1, luego se nos pedirá el ID. Supondremos que el usuario ingresa un ID que no existe, lo cual es un error, se pedirá de nuevo el dato, tras lo cual el usuario ingresará un ID correcto.
Como podrán ver, para no eliminar nada y volver al menú principal debe ingresarse la letra M, cualquier otra cosa será un error.Veamos ahora un ejemplo en el que se selecciona la categoría comestibles para eliminar los productos:Código:Ingrese el ID del producto a eliminar o M para volver al menú principal: 12 ERROR: Dato inesperado, ingrese un dato válido. Ingrese el ID del producto a eliminar o M para volver al Menú Principal: 1 ID: 1 Nombre: Azúcar Stock: 10 Precio: 50,5 Categoría: Comestibles Seguro que desea eliminar este producto (S/N): S Producto eliminado, presione ENTER para volver al Menú Principal...
Como ven, se mostrará un listado de todos los elementos eliminados. Estarán mostrados en el orden que fueron ingresados. Para cualquiera de estas opciones deberán implementar el siguiente procedimiento:Código:¿Seguro que desea eliminar la categoría comestibles? (S/N): S Eliminados: Azucar ID: 1 Harina ID: 2 Fideos ID: 5 Presione ENTER para volver al Menú Principal...
donde lista será nuestro listado de elementos e indice será el lugar de la lista donde está el elemento a eliminar.Código:PROCEDURE EliminarProducto(VAR Lista: Productos; indice: integer);
Cada vez que se elimina un elemento debemos correr todos los siguientes a ese un lugar a la izquierda y reducir el tope un número. Veamos una ilustración:
Allí vemos una lista de elementos donde el arreglo tiene 7 celdas, 5 de las cuales contienen productos, las otras dos no, por lo tanto nuestro tope es 5. En este ejemplo eliminaremos el producto número 3, con lo cual nuestro arreglo quedaría así.
El producto número 3 fue eliminado con lo cual ahora el producto 4 y 5 se corren un lugar hacia la izquierda y el tope se reduce en 1, o sea, Producto 4 estaba en la celda 4 pero ahora está en la celda 3, Producto 5 estaba en la celda 5 pero ahora está en la 4, y donde estaba Producto 5 no hay nada que nos interese, por lo tanto corremos nuestro tope hacia la última celda que contiene información.
Nuestro procedimiento debe hacer justamente esta tarea cada vez que se elimina un elemento de nuestra lista.
Si por ejemplo se eliminaran todos los Productos menos el Producto 5 entonces quedaría así, donde TOPE= 1:
Si se eliminara todo, nuestro TOPE sería 0 y nuestro arreglo estaría vacío, y lo pongo entre comillas porque en realidad las celdas siguen conteniendo información solo que a nosotros no nos importa en absoluto y la tratamos como nula o vacía, de eso se trata la implementación de Arreglos con Tope.
Si se intenta eliminar productos cuando ya no existe nada para eliminar el programa debe darnos el mensaje La lista de elementos está vacía. Hasta aquí llegamos por ahora con nuestro proyecto. La siguiente parte de este tutorial trata el último tema y, a mi gusto, el más interesante, con lo cual modificaremos por última vez nuestro programa de modo que quede perfecto y utilice solo los recursos que necesita para funcionar, pero ya veremos esto.
Deben intentar realizar todo lo que detallo aquí antes de continuar, no importa cuanto tiempo les lleve, cuantas veces se tranquen, si tienen que escribirme a mí o buscar más info en Internet, deben lograr hacerlo. No hay nada aquí que no puedan hacer con lo que saben hasta ahora, es más, todo está pensado para que lo hagan justamente con estas herramientas. Si han logrado resolver la mayoría de los ejercicios anteriores más este programa, entonces han aprendido lo básico de la programación de forma excelente y podrán resolver cualquier tipo de situación que no requiera estructuras mucho más complejas que estas que hemos visto más las que veremos a continuación. Existe una herramienta de implementación de funciones y procedimientos llamada RECURSIÓN, sin embargo no la veremos hasta llegar a Modula.
NOTA: Existe una pequeña errata que fue descubierta por un lector hace tiempo, a quién le surgió la duda y me preguntó. No he corregido esa errata justamente porque se que llegado el momento algunos podrán resolverla y otros deberán preguntarme. En cualquier caso, aprenderán un pequeño truquito nuevo.
Saludos. -
Estimado Vlady yo no he participado mucho pues no tengo facilidad de acceso a internet, pero cada vez que puedo acceder es obligatorio para mí descubrir las nuevas lecciones. Estoy estudiando Informática a nivel universitario y este curso es un apoyo valioso, muy conciso y bien explicado. FELICITACIONES y SIGAMOS ADELANTE!!!
Saludos desde Caracas, Venezuela.
